3

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

ID, XML_FILE, STATUS

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

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;
4

2 回答 2

2

似乎首先您需要更复杂的 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 小提琴 - 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 小提琴 - 2

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

于 2013-04-23T17:44:47.097 回答
0

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

将这些表与 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 并在之后对其进行排序。 了解更多


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

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

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

“我需要通知我的用户,在 xml 中发现了这么多重复的条目”

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

于 2013-04-23T12:06:53.640 回答