2012-10-14 2 views
3

----에서 쿼리 요구 사항이 있습니다. CONNECT BY으로 해결하려고하지만 필요한 결과를 얻지 못하는 것 같습니다.여러 가능한 열 일치에서 Oracle Self-Join - CONNECT BY?


표 (간체) :

create table CSS.USER_DESC (
    USER_ID   VARCHAR2(30) not null, 
    NEW_USER_ID  VARCHAR2(30), 
    GLOBAL_HR_ID  CHAR(8) 
) 

-- USER_ID  is the primary key 
-- NEW_USER_ID is a self-referencing key 
-- GLOBAL_HR_ID is an ID field from another system 

사용자 데이터 (datafeeds)의 두 가지 소스가 있습니다 ... 나는 정보를 업데이트 할 때 둘 중 하나의 실수를 감시해야합니다.


시나리오 :

사용자가 새로운 사용자 ID가 주어집니다 ... 이전 기록은 따라 설정되고
  • 사용자 잎 (풀 타임이 될 계약을 위해 일반적으로 이름 변경)을 비활성화
    1. 및 언젠가 나중에 돌아온다. HR이 이전 사용자 ID를 보내지 않아 계정을 연결할 수 없습니다.
    2. 시스템이 망가졌으며 이전 레코드에 새 사용자 ID가 설정되지 않았습니다.
    3. 데이터는 I가 동일한 사용자는 다음과 알 필요가 수백 다른 방법


  • 에 나쁜 될 수 있으며, 내가 이름 또는 다른 필드에 의존 할 수 없다 ... 그들은 일치마다 다릅니다 기록 :

    ROOTUSER NUMROOTS NODELEVEL ISLEAF USER_ID NEW_USER_ID GLOBAL_HR_ID USERTYPE  LAST_NAME   FIRST_NAME 
    ----------------------------------------------------------------------------------------------------------------------------- 
    EX0T1100 2   1   0   EX0T1100 EX000005     CONTRACTOR VON DER HAAVEN VERONICA  
    EX0T1100 2   2   1   EX000005    00126121  EMPLOYEE  HAAVEN, VON DER VERONICA  
    GL110456 1   1   1   GL110456    00126121  EMPLOYEE  VONDERHAAVEN  VERONICA  
    


    EXOT1100EX000005NEW_USER_ID 필드에 의해 적절하게 연결되어 있습니다. 글로벌 HR ID가 있기 전에 이름이 변경되었으므로 EX0T1100에는 이름이 없습니다. EX000005에 새 사용자 ID 인 'GL110456'이 부여되었으며 둘은 동일한 글로벌 HR ID를 사용하여 연결됩니다.

    데이터 정리는 옵션이 아닙니다.


    지금까지 쿼리 : 나는 다양한 CONNECT BY 절을 시도했습니다

    select connect_by_root cud.user_id RootUser, 
         count(connect_by_root cud.user_id) over (partition by connect_by_root cud.user_id) NumRoots, 
         level NodeLevel, connect_by_isleaf IsLeaf, --connect_by_iscycle IsCycle, 
         cud.user_id, cud.new_user_id, cud.global_hr_id, 
         cud.user_type_code UserType, ccud.last_name, cud.first_name 
    from css.user_desc cud 
    where cud.user_id in ('EX000005','EX0T1100','GL110456') 
    -- Using this so I don't get sub-users in my list of root users... 
    -- It complicates the matches with GLOBAL_HR_ID, however 
    start with cud.user_id not in (select cudsub.new_user_id 
               from css.user_desc cudsub 
               where cudsub.new_user_id is not null) 
    connect by nocycle (prior new_user_id = user_id); 
    


    ,하지만 그들 중 누구도 확실히 맞다 :

    -- As a multiple CONNECT BY 
    connect by nocycle (prior global_hr_id = global_hr_id) 
    connect by nocycle (prior new_user_id = user_id) 
    
    -- As a compound CONNECT BY 
    connect by nocycle ((prior new_user_id = user_id) 
            or (prior global_hr_id = global_hr_id 
             and user_id != prior user_Id)) 
    


    UNIONing이 CONNECT BY 쿼리가 작동하지 않습니다 ... 나는 레벨링을 얻지 못했습니다.

    다음은 내가보고 싶은 것입니다 ... 나는 별개로 사용해야하고 하위 쿼리로 사용해야하는 결과 세트는 괜찮습니다. ROOTUSER 열에있는 세 명의 사용자 ID 중 하나라도 사용해도 괜찮습니다 ... 나는 단지 그들이 동일한 사용자임을 알아야합니다.

    ROOTUSER NUMROOTS NODELEVEL ISLEAF USER_ID NEW_USER_ID GLOBAL_HR_ID USERTYPE  LAST_NAME   FIRST_NAME 
    ----------------------------------------------------------------------------------------------------------------------------- 
    EX0T1100 3   1   0   EX0T1100 EX000005     CONTRACTOR VON DER HAAVEN VERONICA  
    EX0T1100 3   2   1   EX000005    00126121  EMPLOYEE  HAAVEN, VON DER VERONICA  
    EX0T1100 3   (2 or 3) 1   GL110456    00126121  EMPLOYEE  VONDERHAAVEN  VERONICA  
    


    아이디어가 있습니까?


    업데이트

    니콜라스, 당신의 코드는 ... 아주 많이 바른 길처럼 보이는 global_hr_id가 null의 경우 순간의 lead(user_id) over (partition by global_hr_id) 거짓 안타를 가져옵니다. 예를 들어 :

    USER_ID NEW_USER_ID CHAINNEWUSER GLOBAL_HR_ID LAST_NAME FIRST_NAME 
    FP004468    FP004469      AARON  TIMOTHY 
    FP004469            FOONG  KOK WAH 
    

    나는 종종 파티션에 별도의 기록과 같은 널 (null)을 치료하기 위해 싶었던,하지만 난 ignore nulls 작품을 만들 수있는 방법을 찾은 적이 없다. 이것은 내가 원했던 것입니다 :

    decode(global_hr_id,null,null,lead(cud.user_id ignore nulls) over (partition by global_hr_id order by user_id) 
    

    ...하지만 더 좋은 방법이 있어야합니다. 필자는 본격적인 사용자 데이터 (약 4 만 명의 사용자)에 대한 쿼리를 아직 완료하지 못했습니다. global_hr_idnew_user_id 모두 색인이 생성됩니다. 약 750 초 후에


    업데이트

    쿼리 반환 ... 긴하지만, 관리. 그것은 루트에서 2 레벨 히트를 필터링하는 좋은 방법이 없기 때문에 93k 레코드를 반환합니다 - 당신은 start with global_hr_id is null입니다.하지만 불행히도, 항상 그런 것은 아닙니다. 나는 그것들을 걸러 낼 수있는 방법에 대해 좀 더 생각해야 할 것입니다.

    이전에 더 복잡한 시작 절을 추가하려고 시도했지만 이전에는 < 1 초 ... 같이 실행하면 90 분이 소요됩니다. <

    도와 주셔서 다시 한 번 감사드립니다 ...이 문제에 대해 다시 생각해보십시오.

    답변

    3

    한 명의 사용자에 대해서만 샘플 데이터를 제공했습니다. 조금 더하는 것이 낫다. 어쨌든 이걸 보게.

    SQL> with user_desc(USER_ID, NEW_USER_ID, GLOBAL_HR_ID)as(
        2 select 'EX0T1100', 'EX000005', null   from dual union all 
        3 select 'EX000005', null,  00126121  from dual union all 
        4 select 'GL110456', null,  00126121  from dual 
        5 ) 
        6 select connect_by_root(user_id) rootuser 
        7  , count(connect_by_root(user_id)) over(partition by connect_by_root(user_id)) numroot 
        8  , level nodlevel 
        9  , connect_by_isleaf 
    10  , user_id 
    11  , new_user_id 
    12  , global_hr_id 
    13 from (select user_id 
    14    , coalesce(new_user_id, usr) new_user_id1 
    15    , new_user_id 
    16    , global_hr_id 
    17   from (select user_id 
    18      , new_user_id 
    19      , global_hr_id 
    20      , decode(global_hr_id,null,null,lead(user_id) over (partition by global_hr_id order by user_id)) usr 
    21     from user_desc 
    22    ) 
    23  ) 
    24 start with global_hr_id is null 
    25 connect by prior new_user_id1 = user_id 
    26 ; 
    

    결과 :

    ROOTUSER NUMROOT NODLEVEL CONNECT_BY_ISLEAF USER_ID NEW_USER_ID GLOBAL_HR_ID 
    -------- ---------- ---------- ----------------- -------- ----------- ------------ 
    EX0T1100   3   1     0 EX0T1100 EX000005  
    EX0T1100   3   2     0 EX000005     126121 
    EX0T1100   3   3     1 GL110456     126121 
    
    +0

    우와. 나는 그렇게 가치가 없다. 지금 이걸 가지고 놀고 있어요 ... 임시 테이블 공간이 부족해서 실행하려고 합니다만, 이걸로 작동시켜야한다고 생각합니다. 감사합니다! –

    +0

    추신 : 완전히 대표적인 데이터 세트를 찾는 것은 어렵습니다 ... 그 사건을 작동시킬 수 있다면, 나는 다른 사람들의 대부분이 일치한다고 생각합니다. 확실한지 테스트 할 것입니다. –

    +0

    더 많은 정보가 담긴 업데이트를 올리십시오 ... 저에게 주신 내용으로 계속 게임하십시오. –