【问题标题】:PL/SQL XML parsing into relational tablesPL/SQL XML 解析成关系表
【发布时间】:2013-09-13 16:37:46
【问题描述】:

我正在使用 PL/SQL 过程将值从 XML 插入到关系表中。 XML 文件位于 XMLTYPE 列中。
包含 XML 的表 (OFFLINE_XML) 的列是

ID, XML_FILE, STATUS

我想在两个表中插入值,即 DEPARTMENT 和 SECTIONS 部门结构如下:-

ID, NAME

SECTIONS 表的结构是:-

ID, NAME, DEPARTMENT_ID

现在有第三个表 (LIST_1),我想在其中插入上述两个表中已经存在的值。
LIST_1 的结构是:-

ID, DEPARTMENT_ID,DEPARTMENT_NAME,SECTIONS_ID, SECTIONS_NAME

XML格式如下:-

<ROWSET> 
 <DEPARTMENT>
  <DEPARTMENT_ID>DEP22681352268280797</DEPARTMENT_ID>
  <DEPARTMENT_NAME>myDEPARTMENT</DEPARTMENT_NAME>
  <SECTIONS_ID>6390135666643567</SECTIONS_ID>
  <SECTIONS_NAME>mySection</SECTIONS_NAME>
 </DEPARTMENT>
 <DEPARTMENT>
  <DEPARTMENT_ID>DEP255555555550797</DEPARTMENT_ID>
  <DEPARTMENT_NAME>myDEPARTMENT2</DEPARTMENT_NAME>
  <SECTIONS_ID>63901667779243567</SECTIONS_ID>
  <SECTIONS_NAME>mySection2</SECTIONS_NAME>
 </DEPARTMENT>
</ROWSET>


DECLARE
  BEGIN
    insert all
        into department (id, name)
           values (unit_id, unit_name)
        into sections (id, name, department _id)
          values ( sect_id, sect_name, department _id)
    select department .id as department _id
          , department.name as department_name
           , sect.id as sect_id
          , sect.name as sect_name
    from OFFLINE_XML
         , xmltable('/ROWSET/DEPARTMENT'
                   passing OFFLINE_XML.xml_file
                   columns
                      "ID"  varchar2(20) path 'UNIT_ID'
                      , "NAME"  varchar2(20) path 'UNIT_NAME'
                  ) department
          , xmltable('/ROWSET/DEPARTMENT'
               passing OFFLINE_XML.xml_file
               columns
                  "ID"  varchar2(20) path 'SECTIONS_ID'
                  , "NAME"  varchar2(20) path 'SECTIONS_NAME'
              ) sect
               where status = 3;
  EXCEPTION
    WHEN DUP_VAL_ON_INDEX THEN
    dbms_output.put_line('Duplicate='|| department.id );
    --insert into LIST_1 values(ID,DEPARTMENT_ID, SECTIONS_ID, DEPARTMENT_NAME,SECTIONS_NAME);
END;

现在的问题是,如何根据 DEPARTMENT 和 SECTIONS 表中已经存在的主键插入或识别值,然后在 LIST_1 表中插入现有值。 -----更新的努力-------------

我想出了另一个解决方案,但这又给我带来了问题。在下面提到的过程中,光标倾向于为每个 xquery 重复。我不知道我将如何处理这个问题..

DECLARE
    department_id varchar2(20);
    department_name varchar2(20);
    sect_id varchar2(20);
    sect_name varchar2(20);
    sections_unit_id varchar2(20);
    var number;
    CURSOR C1 IS
     select
            sect.id as sect_id
          , sect.name as sect_name
          , sect.unit_id  as sections_unit_id
    from OFFLINE_XML
           , xmltable('/ROWSET/DEPARTMENT'
                   passing OFFLINE_XML.xml_file
                   columns
                      "ID"  varchar2(20) path 'UNIT_ID'
                      , "NAME"  varchar2(20) path 'UNIT_NAME'
                  ) DEPARTMENT
          , xmltable('/ROWSET/DEPARTMENT'
               passing OFFLINE_XML.xml_file
               columns
                  "ID"  varchar2(20) path 'SECTIONS_ID'
                  , "NAME"  varchar2(20) path 'SECTIONS_NAME'
                  , "DEPARTMENT_ID" varchar2(20) path 'DEPARTMENT_ID'
              ) sect
               where status = 3;

BEGIN
      FOR R_C1 IN C1 LOOP
      BEGIN
      var :=1;
         --insert into sections_temp_1 (id, name)values ( R_C1.sect_id, R_C1.sect_name);
         -- commit;
           dbms_output.put_line('Duplicate='||var);
      EXCEPTION
         WHEN DUP_VAL_ON_INDEX THEN
         dbms_output.put_line('Duplicate='||R_C1.sect_id);
      END;
      var:=var+1;
      END LOOP;

END;

【问题讨论】:

    标签: oracle error-handling plsql xml-parsing oracle11g


    【解决方案1】:

    似乎首先您需要更复杂一点的 XQuery 来从 XMLType 字段中提取行。

    无需单独提取部门和部门,然后尝试将其匹配回来。

    试试这个变种:

    select 
      department_id,
      department_name,
      sections_id,
      sections_name
    from 
      OFFLINE_XML xml_list,
      xmltable(
        '
          for $dept in $param/ROWSET/DEPARTMENT
            return $dept
        '
        passing xml_list.xml_file as "param"
        columns
          "DEPARTMENT_ID"   varchar2(100) path '//DEPARTMENT/DEPARTMENT_ID',
          "DEPARTMENT_NAME" varchar2(4000) path '//DEPARTMENT/DEPARTMENT_NAME',
          "SECTIONS_ID"     varchar2(100) path '//DEPARTMENT/SECTIONS_ID',
          "SECTIONS_NAME"   varchar2(4000) path '//DEPARTMENT/SECTIONS_NAME'
      ) section_list
    where 
      xml_list.Status = 3
    

    SQL fiddle - 1

    之后,如果您想查找是否已经存在任何值,您将获得一个数据集,该数据集可以通过其主键(或其他东西 - 取决于所需的逻辑)外部连接到现有表:

    select 
      offline_set.offline_xml_id,
      offline_set.department_id,
      offline_set.department_name,
      offline_set.sections_id,
      offline_set.sections_name,
      nvl2(dept.id,'Y', 'N') is_dept_exists, 
      nvl2(sect.id,'Y', 'N') is_sect_exists 
    from 
      (  
        [... skipped text of previous query ...]
      ) offline_set,
      department dept,
      sections   sect
    where
      dept.id (+) = offline_set.department_id
      and
      sect.id (+) = offline_set.sections_id
    

    SQL fiddle - 2

    因为我实际上不知道此要求背后的逻辑,所以我无法建议任何未来的处理指令。但您似乎错过了对LIST_1OFFLINE_XML 表的引用,该表需要识别错误/重复的来源。

    【讨论】:

      【解决方案2】:

      最好的方法是使用 Oracle 的内置错误日志记录。使用 DBMS_ERRLOG.CREATE_ERROR_LOG() 为 每个目标表 生成一个日志表(即在您的情况下为 SECTION 和 DEPARTMENT)。 Find out more.

      将这些表与 INSERT ALL 一起使用的语法并不直观,但可以这样做:

      insert all
          into department (id, name)
             values (unit_id, unit_name)
             log errors into err$_department  ('XML Load failure')
          into sections (id, name, department_id)
            values ( sect_id, sect_name, department_id)
             log errors into err$_section  ('XML Load failure') 
      select department.id as department_id
              .... 
      

      您可以将任何(短)字符串放入错误日志标签中,但请确保它有助于您本地化相关记录。您可能希望将 REJECT LIMIT 设置为某个值,具体取决于您是希望在一个(或几个)错误上失败,还是处理整个 XML 并在之后对其进行排序。 Find out more.


      我建议您为每个目标表使用单独的日志而不是一个日志,原因有两个:

      1. 在我的经验中,利用 Oracle 内置恐惧的解决方案往往比手动代码更易于扩展且更健壮。
      2. 它更适合可能发生的事情。您有三种情况可能会导致加载抛出 DUP_VAL_ON_INDEX:
        • 记录有重复的部门 ID
        • 记录具有重复的部分 ID
        • 记录有重复的部门 ID 并且重复的部门 ID

      单独的表格使您更容易理解出了什么问题。这是加载大量数据时的一大福音。

      “我需要通知我的用户有这么多重复的条目是 在 xml 中找到”

      您仍然可以使用两个错误日志来执行此操作。哎呀,您甚至可以将错误日志加入一个名为 LIST_1 的视图中,这对您来说非常重要。

      【讨论】:

      • 我想知道这将如何帮助我将 DEPARTMENT 和 SECTIONS 表中已有的值插入到 LIST_1 表中?
      • 我假设您在这些表上定义了主键:在这种情况下,LOG ERROR INTO 将通过将重复记录写入日志表来处理唯一键违规。
      • 也就是说,为每个目标表使用单独的日志,而不是为两个目标表使用一个表。
      • 实际上我的要求是我需要在一个表中包含所有重复的条目。为了将来参考,我需要通知我的用户在 xml 中找到了这么多重复的条目。
      • 请考虑我的最新努力。这可能有助于您理解我的要求。
      猜你喜欢
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-22
      • 2017-07-27
      • 1970-01-01
      相关资源
      最近更新 更多