2013-05-04 102 views
1

我創建了一個將xml數據解析爲多個表的過程。我正在捕獲主鍵約束的異常,並且如果在結果中找到重複項,它將被插入名爲DUPLICATE的表中。
現在,當我使用光標它往往比迭代所需要的次數更多,即1
程序光標for循環爲嵌套的XQUERY創建重複條目

DECLARE 
PER_ID varchar2(20); 
    NAME varchar2(20); 
SECTIONS_ID varchar2(20); 
SECTIONS_NAME varchar2(20); 
    var1 number; 
    exception_var number; 
CURSOR C1 IS 
    select d.department_id 
     , d.department_name 
     , s.sections_id 
     , s.sections_name 
    from xml_unit_download t 
    , xmltable(
     '/ROWSET/DATA' 
     passing t.xml_file 
     columns 
      DEPARTMENT_ID varchar2(20) path 'DEPARTMENT/DEPARTMENT_ID' 
     , DEPARTMENT_NAME varchar2(30) path 'DEPARTMENT/DEPARTMENT_NAME' 
     , SECTIONS  xmltype  path 'SECTIONS' 
     ) d 
    , xmltable(
     '/SECTIONS' 
     passing d.sections 
     columns 
      SECTIONS_ID  varchar2(20) path 'SECTIONS_ID' 
     , SECTIONS_NAME varchar2(30) path 'SECTIONS_NAME' 
    ) s 
where 
    t.Status = 4; 
    BEGIN 

    FOR R_C1 IN C1 LOOP 
     BEGIN 
     insert into DEPARTMENT(id, name) values(R_C1.PER_ID, R_C1.name); 
     insert into SECTIONS(id, name) values(R_C1.SECTIONS_ID, R_C1.SECTIONS_NAME); 
     var1:= var1+1; 
     dbms_output.put_line('Insert=' || var1); 
     commit; 
      --dbms_output.put_line('Duplicate='||var); 
     EXCEPTION 
     WHEN DUP_VAL_ON_INDEX THEN 
     dbms_output.put_line('Duplicate='); 
     insert into duplicate(id, name)values(R_C1.id, R_C1_name); 
     END; 
     END LOOP; 
    END; 

我應該如何去處理這種情況?我曾嘗試使用INSERT ALL,但它似乎不起作用。這裏是我的INSERT的嘗試所有程序

DECLARE 
PER_ID varchar2(20); 
    NAME varchar2(200); 
    var1 number; 
    exception_var number; 

    BEGIN 

     insert all 
     into SECTIONS (id) values(department_id) 

     --into sect (id, name) values(s.SECTIONS_ID, s.SECTIONS_NAME) 
    select d.department_id 
     , d.department_name 
     , s.sections_id 
     , s.sections_name 
    from xml_unit_download t 
    , xmltable(
     '/ROWSET/DATA' 
     passing t.xml_file 
     columns 
      "DEPARTMENT_ID" varchar2(20) path 'DEPARTMENT/DEPARTMENT_ID' 
     , "DEPARTMENT_NAME" varchar2(30) path 'DEPARTMENT/DEPARTMENT_NAME' 
     , "SECTIONS"  xmltype  path 'SECTIONS' 
     ) d 
    , xmltable(
     '/SECTIONS' 
     passing d.sections 
     columns 
      "SECTIONS_ID"  varchar2(20) path 'SECTIONS_ID' 
     , "SECTIONS_NAME" varchar2(30) path 'SECTIONS_NAME' 
    ) s 
where 
    t.Status = 4; 
    dbms_output.put_line('Insert=' || var1); 
     var1:= var1+1; 
     dbms_output.put_line('Insert=' || var1); 
     commit; 
      --dbms_output.put_line('Duplicate='||var); 
     EXCEPTION 
     WHEN DUP_VAL_ON_INDEX THEN 
     --insert into 
     dbms_output.put_line('Duplicate='); 
    END; 

正在被查詢包含部門和各部分的數據的XML。 DEPARTMENT與SECTIONS有一對多的關係,即一個DEPARTMENT可以有一個或多個SECTIONS,並且可能有DEPARTMENT沒有任何SECTION的情況。

XML的結構就是標籤標識一個DEPARTMENT和一組相應的SECTION。
XML

<ROWSET> 
<DATA> 
<DEPARTMENT> 
    <DEPARTMENT_ID>DEP1</DEPARTMENT_ID> 
    <DEPARTMENT_NAME>myDEPARTMENT1</DEPARTMENT_NAME> 
</DEPARTMENT> 
<SECTIONS> 
    <SECTIONS_ID>6390135666643567</SECTIONS_ID> 
    <SECTIONS_NAME>mySection1</SECTIONS_NAME> 
    </SECTIONS> 
    <SECTIONS> 
    <SECTIONS_ID>6390135666643567</SECTIONS_ID> 
    <SECTIONS_NAME>mySection2</SECTIONS_NAME> 
    </SECTIONS> 
</DATA> 
<DATA> 
<DEPARTMENT> 
    <DEPARTMENT_ID>DEP2</DEPARTMENT_ID> 
    <DEPARTMENT_NAME>myDEPARTMENT2</DEPARTMENT_NAME> 
</DEPARTMENT> 
<SECTIONS> 
    <SECTIONS_ID>63902</SECTIONS_ID> 
    <SECTIONS_NAME>mySection1</SECTIONS_NAME> 
    </SECTIONS> 
</DATA> 
<DATA> 
<DEPARTMENT> 
    <DEPARTMENT_ID>DEP3</DEPARTMENT_ID> 
    <DEPARTMENT_NAME>myDEPARTMENT3</DEPARTMENT_NAME> 
</DEPARTMENT> 
</DATA> 
</ROWSET> 
+0

如果您在部門中有兩個部分,則您的查詢將返回兩行,具有相同的部門信息和不同的部分信息(您可以看到自己運行查詢)。因此,重複的部門是'有效的',並且不能區分一個部門的兩個部門,以及兩個相同的部門各有一個部門,如果這就是您想要做的。無論哪種方式,因爲您的重複部門得到異常,第二部分永遠不會插入。你可以把異常處理程序放在第一次插入,但這似乎不是最好的方法。 – 2013-05-04 11:00:53

回答

1

既然你可以在每個部門的多個部分,你會希望重複。你也許能夠得到你想要的只是通過移動,你捕獲該異常,所以它仍然會做INSERT INTO sections

FOR R_C1 IN C1 LOOP 
     BEGIN 
     insert into DEPARTMENT(id, name) 
      values(R_C1.department_id, R_C1.department_name); 
     EXCEPTION 
     WHEN DUP_VAL_ON_INDEX THEN 
     dbms_output.put_line('Duplicate='); 
     insert into duplicate(id, name) 
      values(R_C1.department_id, R_C1.department_name); 
     END; 
     insert into SECTIONS(id, name) 
     values(R_C1.SECTIONS_ID, R_C1.SECTIONS_NAME); 
     var1:= var1+1; 
     dbms_output.put_line('Insert=' || var1); 
    END LOOP; 

您也可以使用跟蹤變量(如果你看到一個記錄有相同department_id與前一個你所看到的,不要試圖插入department記錄,只是做了sections插入),或者你可以使用嵌套的循環:

declare 
    cursor dept_cur is 
     select d.department_id 
     , d.department_name 
     , d.sections 
     from xml_unit_download t 
     , xmltable(
      '/ROWSET/DATA' 
      passing t.xml_file 
      columns 
       "DEPARTMENT_ID" varchar2(20) path 'DEPARTMENT/DEPARTMENT_ID' 
      , "DEPARTMENT_NAME" varchar2(30) path 'DEPARTMENT/DEPARTMENT_NAME' 
      , "SECTIONS"  xmltype  path 'SECTIONS' 
     ) d 
     where 
     t.Status = 4; 

    cursor sect_cur(sections xmltype) is 
     select s.sections_id 
     , s.sections_name 
     from xmltable(
      '/SECTIONS' 
      passing sections 
      columns 
       "SECTIONS_ID"  varchar2(20) path 'SECTIONS_ID' 
      , "SECTIONS_NAME" varchar2(30) path 'SECTIONS_NAME' 
     ) s; 
begin 
    for dept in dept_cur loop 
     insert into department(id, name) 
     values (dept.department_id, dept.department_name); 
     for sect in sect_cur(dept.sections) loop 
     insert into sections(id, name, department_id) 
      values (sect.sections_id, sect.sections_name, dept.department_id); 
     end loop; 
    end loop; 
end; 
/

PL/SQL procedure successfully completed. 

它使用一個循環來獲取部門信息(這將不會有重複項)加上XMLTYPE部分,然後將該部分傳遞給第二個光標t o擴大。

select * from department; 

ID        NAME 
------------------------------ ------------------------------ 
DEP1       myDEPARTMENT1 
DEP2       myDEPARTMENT2 
DEP3       myDEPARTMENT3 

select * from sections; 

ID        NAME       DEPARTMENT_ID 
------------------------------ ------------------------------ ------------------------------ 
6390135666643567    mySection1      DEP1 
6390135666643567    mySection2      DEP1 
63902       mySection1      DEP2 

您不必使用PL/SQL,你可以只是做兩個插件:

insert into department(id, name) 
select d.department_id 
    , d.department_name 
from xml_unit_download t 
    , xmltable(
     '/ROWSET/DATA' 
     passing t.xml_file 
     columns 
     "DEPARTMENT_ID" varchar2(20) path 'DEPARTMENT/DEPARTMENT_ID' 
     , "DEPARTMENT_NAME" varchar2(30) path 'DEPARTMENT/DEPARTMENT_NAME' 
    ) d 
where 
    t.Status = 4; 

...和:

insert into sections(id, name, department_id) 
select s.sections_id 
    , s.sections_name 
    , d.department_id 
from xml_unit_download t 
    , xmltable(
     '/ROWSET/DATA' 
     passing t.xml_file 
     columns 
     "DEPARTMENT_ID" varchar2(20) path 'DEPARTMENT/DEPARTMENT_ID' 
     , "DEPARTMENT_NAME" varchar2(30) path 'DEPARTMENT/DEPARTMENT_NAME' 
     , "SECTIONS"  xmltype  path 'SECTIONS' 
    ) d 
    , xmltable(
     '/SECTIONS' 
     passing d.sections 
     columns 
     "SECTIONS_ID"  varchar2(20) path 'SECTIONS_ID' 
    , "SECTIONS_NAME" varchar2(30) path 'SECTIONS_NAME' 
    ) s 
where 
    t.Status = 4; 

...這把表中的數據與PL/SQL塊相同。

在這兩個我都假設你想要一個鏈接兩個表的列,但也許他們不是唯一鏈接,你想單獨sectiondepartment_section表,這可以很容易地以同樣的方式生成。

另請注意,兩種方法都會爲DEP3創建一個department記錄,除非您使用以前的答案中的外部聯接,否則您的原始記錄不會這樣做;然後你必須注意到沒有部分信息,也沒有嘗試第二次插入。

1

這似乎是一個基本的基數問題 - 如果您的部門中有多個部分,那麼您將在結果中爲每個部門獲取多個行,因此您會看到重複的部門信息,因爲的程序代碼而不是輸入數據。

而不是試圖在一個查詢中做到這一點,爲什麼不把它分解成兩個遊標/ for循環?

事情是這樣的:

BEGIN 

    <<department_loop>> 
    FOR r_department IN (
    SELECT 
     d.department_id 
    , d.department_name 
    , d.sections 
    FROM xml_unit_download t 
    , XMLTABLE(
    '/ROWSET/DATA' 
    PASSING t.xml_file 
    COLUMNS 
     department_id VARCHAR2(20) PATH 'DEPARTMENT/DEPARTMENT_ID' 
    , department_name VARCHAR2(30) PATH 'DEPARTMENT/DEPARTMENT_NAME' 
    , sections  XMLTYPE  path 'SECTIONS' 
    ) d 
    WHERE t.status = 4 
) 
    LOOP 

    BEGIN 
     INSERT INTO departments (id, name) 
     VALUES (r_department.department_id, r_department.department_name); 
    EXCEPTION 
     WHEN DUP_VAL_ON_INDEX THEN 
     INSERT INTO department_duplicates (id, name) 
     VALUES (r_department.department_id, r_department.department_name); 
    END; 

    <<section_loop>> 
    FOR r_section IN (
     SELECT 
     s.sections_id 
     , s.sections_name 
     FROM XMLTABLE (
     '/SECTIONS' 
     PASSING r_department.sections 
     COLUMNS 
     sections_id VARCHAR2(20) PATH 'SECTIONS_ID' 
     , sections_name VARCHAR2(30) PATH 'SECTIONS_NAME' 
    ) s 
    ) 
    LOOP 

     BEGIN 
     INSERT INTO sections (id, name, department_id) 
     VALUES (r_section.sections_id, r_section.sections_name, r_department.department_id); 
     EXCEPTION 
     WHEN DUP_VAL_ON_INDEX THEN 
      INSERT INTO section_duplicates (id, name, department_id) 
      VALUES (r_section.sections_id, r_section.sections_name, r_department.department_id); 
     END; 

    END LOOP section_loop; 

    END LOOP department_loop; 

END; 
/

這有以下好處:

  • 你能夠捕獲單個副本(如果找到)很容易,在這兩個部門,部分條款。
  • 由於程序代碼,你沒有引入基數 - 任何重複都是真實的輸入數據重複。
  • 您不必擔心跟蹤您正在使用/使用的行,它隱含在嵌套的循環結構中。