2013-05-04 3 views
1

XML 데이터를 여러 테이블로 구문 분석하는 프로 시저를 만들었습니다. 기본 키 제약 조건에 대한 예외를 잡아 내고 결과에 중복이 있으면 DUPLICATE라는 테이블에 삽입됩니다. 내가 커서를 사용할 때
지금이 시대의 필요한 수보다 더 많은 반복하는 경향 즉 1
어떻게이 상황을 처리하기 위하여려고하고있다중첩 된 XQUERY에 대한 중복 항목을 만드는 커서 for 루프

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에는 SECTIONS가없는 인스턴스가있을 수 있습니다.

XML 구조는 태그가 DEPARTMENT와 해당 SECTIONS 세트를 식별하는 것과 같습니다. 각 부서의 여러 섹션을 가질 수 있기 때문에
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

부서에 두 개의 섹션이있는 경우 검색어는 동일한 부서 정보와 다른 섹션 정보로 두 행을 반환합니다 (자체적으로 쿼리를 실행하는 것처럼 볼 수 있음). 따라서 중복 부서가 '유효'하며 한 부서의 두 섹션과 한 섹션을 가진 두 개의 동일한 부서를 구분할 수 없습니다. 어느 쪽이든, 당신의 중복 부서가 예외를 얻었 기 때문에, 두 번째 섹션은 절대로 삽입되지 않습니다. 첫 번째 삽입 주위에 예외 처리기를 넣을 수도 있지만 이것이 최선의 접근 방식처럼 보이지는 않습니다. –

답변

1

, 당신은 중복을 기대할 수 있습니다. 당신은 당신이 예외를 catch 곳으로 이동하여 당신이 원하는 것을 얻을 수있을 것, 그래서 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은) 단지 sections 삽입을 수행합니다 department 레코드를 삽입하지 마십시오, 또는 당신은 중첩 루프 사용할 수 있습니다 (

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 확장. 를 붙이있는 ...

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; 

:

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; 

... 그리고 :

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을 사용할 필요가 없습니다 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; 
/

이 다음과 같은 이점이 있습니다

  • 당신은 모두 부서 및 섹션의 측면에서 비교적 쉽게 (발견 된 경우) 개별 중복 트랩 할 수있어 .
  • 프로그램 코드로 인해 카디널리티가 도입되지 않습니다. 중복 된 항목은 입력 된 데이터의 중복입니다.
  • 사용중인 행/사용 된 행을 추적 할 필요가 없습니다. 중첩 된 루프 구조에서 암시 적입니다.