开发者

PL/SQL: how to loop through sql extract() results

This is an arbitrary example. It is a real problem, but I can't share real code.

I have an xml string that does not have standardized node names. example:

<row>
  <date name="date1" id="101"></date>
  <element1 name="ele1" id="111">
    <stuff></stuff>
    <stuff></stuff>
    <stuff></stuff>
  </element1>
  <element2 name="ele2" id="121">
  </element2>
  ...
  <element15 name="ele15" id="1151></element15>
</row>

some of the element nodes have stuff children, some do not.

This xml is contained within a database table (for argument sake: table1, column1).

I need to loop through this code using pl/sql to get: 1. the name attribute of the date field 2. the id attribute of the date field 3. the name attribute of the first node after the date 4. the id attribute of the first node after the date 5. the name attribute of the second node after the date 6. the id attribute of the second node after the date

I need to do this for the first 4 (arbitrary) rows (sql queries have rownum < 5)

So far I've been trying to get data with

set serveroutput on format word_wrapped;
DECLARE

    x_att_name varchar2(4000);
    x_id varchar2(4000);
    x_oth_name varchar2(4000);
    x_oth_id varchar2(4000);
    aCount number := 1;
    xpath1 varchar2(4000);
    xpath2 varchar2(4000);

BEGIN

    FOR i IN  (
                  SELECT 

                  EXTRACT(column1, '/row/date/@name') as att_name,
                  EXTRACT(column1, '/row/date/@id') as id,
                  EXTRACT(column1, '/row/date/following::*/@name') as other_name,
                  EXTRACT(column1, '/row/date/following::*/@id') as other_id

                  FROM table1
                  WHERE column1is not null and rownum < 5
              )
    LOOP

            x_att_name := i.att_name.getStringVal();
            x_id := i.id.getStringVal();
            x_oth_name := i.other_name.getStringVal();
            x_oth_id := i.other_id.getStringVal();开发者_运维技巧

            dbms_output.put_line('LOOPS: ' || aCount);
            dbms_output.put_line(' DATE: ' || x_att_name);
            dbms_output.put_line(' PKDATE: ' || x_id);
            dbms_output.put_line(' FLDNAME: ' || x_oth_name);
            dbms_output.put_line(' PKFLD: ' || x_oth_id);

            aCount := aCount+1;

    END LOOP;

END;

When I run this, I get:

anonymous block completed
LOOPS: 1
 DATE: date1
 PKDATE: 101
 FLDNAME: ele1ele2ele3ele4...ele15
 PKFLD: 111121131141...1151
....

So it essentially spits back all the name attributes from the rest of the nodes in that database record mashed together (rather than in a list as I'd hoped).

It does the same for the id's.

Things to note: - all of the element nodes have widely varying name attributes. They are not simply a list of three character strings with numbers added to the ends (ele1); - all of the id attributes for every node are vastly different. They are a jumbled string of numbers (10212 for example), the do not go in asc/dsc order, are not consecutive, and are not related by any pattern.

Obviously I can't just loop through all of the element nodes as they're all unique. I can't figure out how to write an xpath to get "all the nodes after this one".

I'm brand new to pl/sql and have learned everything you see here in just a matter of days, so obviously the more complex / subtle points of the language still elude me.

Any help you can offer would be greatly appreciated. If I've made any typos or have been unclear in any way, please let me know so I can clarify.

Thanks Q


You're looking for XMLTABLE.

create table so10t(
  id number,
  data xmltype
);

insert into so10t values (1, xmltype(
'<row>
  <date name="date1" id="101"></date>
  <element1 name="ele1" id="111">
    <stuff></stuff>
    <stuff></stuff>
    <stuff></stuff>
  </element1>
  <element2 name="ele2" id="121">
  </element2>
  <element15 name="ele15" id="1151"></element15>
</row>'));
insert into so10t values (2, xmltype(
'<row>
  <date name="date2" id ="102"/>
  <elem23 name="ele23" id="201">
    <whatever/>
  </elem23>
  <elem56 name="ele56" id="402"/>
  <elem112 name="ele112" id="804"/>
</row>'));

declare
  type rec_t is record(
    date_name varchar2(10),
    date_id number,
    first_elem_name varchar2(10),
    first_elem_id number,
    second_elem_name varchar2(10),
    second_elem_id number
  );
  rec rec_t;
  cur sys_refcursor;
begin
  open cur for
    select x.*
      from so10t,
      xmltable('row' passing so10t.data
               columns
               /* 1. the name attribute of the date field */
               date_name varchar2(10) path 'date/@name',
               /* 2. the id attribute of the date field */
               date_id number path 'date/@id',
               /* 3. the name attribute of the first node after the date */
               first_elem_name varchar2(10) path 'date/(following::*)[1]/@name',
               /* 4. the id attribute of the first node after the date */
               first_elem_id number path 'date/(following::*)[1]/@id',
               /* 5. the name attribute of the second node after the date */
               second_elem_name varchar2(10) path 'date/(following::*)[1]/(following::*)[1]/@name',
               /* 6. the id attribute of the second node after the date */
               second_elem_id number path 'date/(following::*)[1]/(following::*)[1]/@id'
               ) x 
      where rownum < 5 ;

  fetch cur into rec;
  while cur%found loop
    dbms_output.put_line(rec.date_name || ';' || rec.date_id || ';' ||
                         rec.first_elem_name || ';' || rec.first_elem_id || ';' ||
                         rec.second_elem_name || ';' || rec.second_elem_id);
    fetch cur into rec;
  end loop;

  close cur;
end;
/
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜