0

I'm trying to find members of several groups. The group membership is stored as XML in an ORACLE database. I need a SQL query to split each member into a separate rows.

I've seen a few posts on using xmlsequence without success through lack of understanding.

A sample string is

<D:href xmlns:D='DAV:'>/users/admin@Native Directory</D:href>
<D:href xmlns:D='DAV:'>/users/oracle@Native Directory</D:href>
<D:href xmlns:D='DAV:'>/users/user1@DomainProd</D:href>

My current results are

Group       User
-------------------------------------------------------------------------
group1      <D:href xmlns:D='DAV:'>/users/admin@Native Directory</D:href>
            <D:href xmlns:D='DAV:'>/users/oracle@Native Directory</D:href>
            <D:href xmlns:D='DAV:'>/users/user1@DomainProd</D:href>
group2      <D:href xmlns:D='DAV:'>/users/admin@Native Directory</D:href>
            <D:href xmlns:D='DAV:'>/users/oracle@Native Directory</D:href>
            <D:href xmlns:D='DAV:'>/users/user1@DomainProd</D:href>
group3      <D:href xmlns:D='DAV:'>/users/admin@Native Directory</D:href>
            <D:href xmlns:D='DAV:'>/users/oracle@Native Directory</D:href>
            <D:href xmlns:D='DAV:'>/users/user1@DomainProd</D:href>

I want my results set to be

Group       User
-------------------
group1      admin
group1      oracle
group1      user1
group2      admin
group2      oracle
group2      user1
group3      admin
group3      oracle
group3      user1

Any help would be appreciated...

Thanks

1

2 Answers 2

1

you can use XMLTABLE. as your XML document seems to be a fragment in the row, i've wrapped this in a <root> element.

select grp, substr(name, 
              instr(name, '/', -1) + 1,
              instr(name, '@') - instr(name, '/', -1) - 1
             ) name
  from mytab m, 
       xmltable(xmlnamespaces('DAV:' as "D"), 
                '/root/D:href' passing xmltype('<root>'||usr||'</root>')
                columns
                name varchar2(200) path './text()');

i've assumed a table where your xml column is stored as a clob/varchar2 called (usr) .

example output for group1:

SQL> select grp, substr(name,
  2                instr(name, '/', -1) + 1,
  3                instr(name, '@') - instr(name, '/', -1) - 1
  4               ) name
  5    from mytab m,
  6         xmltable(xmlnamespaces('DAV:' as "D"),
  7                  '/root/D:href' passing xmltype('<root>'||usr||'</root>')
  8                  COLUMNS
  9                  name VARCHAR2(200) path './text()');

GRP    NAME
------ ----------
group1 admin
group1 oracle
group1 user1

http://sqlfiddle.com/#!4/435cd/1

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @DazzaL. It's working on sqlfiddle but not on the server. I'm getting ORA-19102: XQuery string literal expected. The query i'm using it select X.name from PROPERTIES p, xmltable(xmlnamespaces('DAV:' as "D"), '/root/D:href' passing xmltype('<root>'||p.PROPERTY_VALUE||'</root>') COLUMNS name CLOB PATH './text()') X'
@5hak3y this may be because you have CURSOR_SHARING set to FORCE or SIMILAR. can you confirm this? a simple way of seeing is add this hint in select /*+ cursor_sharing_exact */ grp
0

@DazzaL's answer is a good one (and probably faster in most cases),
but you can also do something like this:

with tt as 
(select ggroup, regexp_replace(uuser, '([[:print:]]*)(/users/)([[:alnum:]]*)(@)([[:print:]]*)','\3,') user_csv
from t)
select distinct ggroup, regexp_substr(user_csv,'[^,]+',1,level)
from tt
connect by regexp_substr(user_csv,'[^,]+',1,level) is not null
order by ggroup

t in my query is the table's name

Here is a sqlfiddle demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.