6

重いクエリ (実行に 15 分かかる) がありますが、必要以上の結果が返されます。これは CONNECT BY クエリであり、ルート ノードの結果で子孫であるノードを取得しています。いいえ:

Ted
  Bob
    John
Bob
  John
John

通常、これを解決する方法は START WITH 条件を使用することであり、通常はノードの親を null にする必要があります。しかし、クエリの性質上、完全な結果セットが得られるまで、比較する必要がある START WITH 値がありません。私は基本的に、結果をダブルクエリして、QUERY STUFF START WITH RECORDS THAT AREN'T IN THAT STUFF と言おうとしています。


これがクエリです(Nicholas Krasnovの助けを借りて作成されました。ここで は、複数の可能な列一致での Oracle Self-Join - CONNECT BY?):

select cudroot.root_user, cudroot.node_level, cudroot.user_id, cudroot.new_user_id,
       cudbase.*  -- Not really, just simplyfing
from   css.user_desc cudbase
  join (select connect_by_root(user_id) root_user,   
               user_id                  user_id,        
               new_user_id              new_user_id,
               level                    node_level
        from   (select cudordered.user_id,      
                       coalesce(cudordered.new_user_id, cudordered.nextUser) new_user_id
                from   (select cud.user_id, 
                               cud.new_user_id, 
                               decode(cud.global_hr_id, null, null, lead(cud.user_id ignore nulls) over (partition by cud.global_hr_id order by cud.user_id)) nextUser
                        from   css.user_desc cud
                          left join gsu.stg_userdata gstgu
                            on (gstgu.user_id = cud.user_id 
                                or (gstgu.sap_asoc_global_id = cud.global_hr_id))
                        where  upper(cud.user_type_code) in ('EMPLOYEE','CONTRACTOR','DIV_EMPLOYEE','DIV_CONTRACTOR','DIV_MYTEAPPROVED')) cudordered)
        connect by nocycle user_id = prior new_user_id) cudroot
    on cudbase.user_id = cudroot.user_id
order by 
       cudroot.root_user, cudroot.node_level, cudroot.user_id;


これにより、関連するユーザー (user_id の名前変更または関連付けられた SAP ID に基づく) に関する結果が次のように得られます。

ROOT_ID     LEVEL   USER_ID         NEW_USER_ID
------------------------------------------------
A5093522    1       A5093522        FG096489
A5093522    2       FG096489        A5093665
A5093522    3       A5093665        
FG096489    1       FG096489        A5093665
FG096489    2       A5093665
A5093665    1       A5093665

私が必要としているのは、最初join (select connect_by_root(user_id)...に除外するものFG096489A5093665ルート リストからフィルタリングする方法です。


私が考えることができる最高START WITHのものは次のようになります(まだテストされていません):

start with user_id not in (select new_user_id 
                           from   (select coalesce(cudordered.new_user_id, cudordered.nextUser) new_user_id
                                   from   (select cud.new_user_id, 
                                                  decode(cud.global_hr_id, null, null, lead(cud.user_id ignore nulls) over (partition by cud.global_hr_id order by cud.user_id)) nextUser
                                           from   css.user_desc cud
                                           where  upper(cud.user_type_code) in ('EMPLOYEE','CONTRACTOR','DIV_EMPLOYEE','DIV_CONTRACTOR','DIV_MYTEAPPROVED')) cudordered)
                           connect by nocycle user_id = prior new_user_id)

...しかし、15 分間のクエリを効果的に 2 回実行しています。

クエリでパーティションを使用することを見てきましたが、実際にはパーティションはありません... new_user_ids の完全な結果セットを見たいと思います。rank() などの分析関数も調べました...私のトリックのバッグは空です。

何か案は?


明確化

ルート リストに余分なレコードを入れたくない理由は、ユーザーごとに 1 つのグループの結果だけが必要だからです。IE、Bob Smith がここでのキャリアの中で 4 つのアカウントを持っていた場合 (人々は従業員や請負業者として頻繁に出入りします)、すべて Bob Smith に属している一連のアカウントで作業したいと思います。

ボブが請負業者としてここに来て、従業員に転向し、去り、別の国で請負業者として戻ってきて、現在 SAP システムにある法的組織を離れて/戻った場合、彼のアカウントの名前変更/チェーンは次のようになります。

Bob Smith  CONTRACTOR   ----    US0T0001  ->  US001101  (given a new ID as an employee)
Bob Smith  EMPLOYEE     ----    US001101  ->  EB0T0001  (contractor ID for  the UK)
Bob Smith  CONTRACTOR  SAP001   EB0T000T                (no rename performed)
Bob Smith  EMPLOYEE    SAP001   TE110001                (currently-active ID)

new_user_id上記の例では、4 つのアカウントは、ユーザーの名前が変更されたときに設定されたフィールドによって、または同じ SAP ID を持つことによってリンクされています。

HR はビジネス プロセスに従わないことがよくあるため、リピーター ユーザーはこれら 4 つの ID のいずれかが復元されてしまう可能性があります。Bob Smith のすべての ID を分析し、「Bob Smith が復元できるのは TE110001 だけです」と言って、他の何かを復元しようとするとエラーを返さなければなりません。私は90,000以上のレコードに対してそれをしなければなりません。

最初の列「Bob Smith」は、関連付けられたアカウントのグループの単なる識別子です。元の例では、ルート ユーザー ID を識別子として使用しています (例: US0T0001)。ユーザーを識別するために姓名を使用すると、競合が発生します。

したがって、ボブ・スミスは次のようになります。

US0T0001  1  CONTRACTOR   ----    US0T0001  ->  US001101  (given a new ID as an employee)
US0T0001  2  EMPLOYEE     ----    US001101  ->  EB0T0001  (contractor ID for  the UK)
US0T0001  3  CONTRACTOR  SAP001   EB0T0001                (no rename performed)
US0T0001  4  EMPLOYEE    SAP001   TE110001                (currently-active ID)

... ここで、1、2、3、4 は階層のレベルです。

US0T0001、US001101、EB0T0001、および TE110001 はすべて説明されているため、別のグループは必要ありません。しかし、私が得た結果では、これらのアカウントが複数のグループにリストされています。

US001101  1  EMPLOYEE     ----    US001101  ->  EB0T0001  (
US001101  2  CONTRACTOR  SAP001   EB0T0001                
US001101  3  EMPLOYEE    SAP001   TE110001               

EB0T0001  1  CONTRACTOR  SAP001   EB0T0001               
EB0T0001  2  EMPLOYEE    SAP001   TE110001                

US001101  1  EMPLOYEE    SAP001   TE110001                 

これにより、次の 2 つの問題が発生します。

  1. ユーザー ID の結果をクエリすると、複数のグループからヒットします
  2. 各グループは、Bob Smith の予想される異なるユーザー ID を報告します。


あなたはレコードの拡張セットを求めました...ここにいくつかの実際のデータがあります:

-- NumRootUsers tells me how many accounts are associated with a user.
-- The new user ID field is explicitly set in the database, but may be null.
-- The calculated new user ID analyzes records to determine what the next related record is

          NumRoot                   New User    Calculated
RootUser  Users    Level  UserId    ID Field    New User ID   SapId       LastName        FirstName
-----------------------------------------------------------------------------------------------
BG100502  3        1      BG100502  BG1T0873    BG1T0873                  GRIENS VAN      KION
BG100502  3        2      BG1T0873  BG103443    BG103443                  GRIENS VAN      KION
BG100502  3        3      BG103443                            41008318    VAN GRIENS      KION

-- This group causes bad matches for Kion van Griens... the IDs are already accounted for,
-- and this group doesn't even grab all of the accounts for Kion.  It's also using a new 
-- ID to identify the group
BG1T0873  2        1      BG1T0873  BG103443    BG103443                  GRIENS VAN      KION
BG1T0873  2        2      BG103443                            41008318    VAN GRIENS      KION

-- Same here...
BG103443  1        1      BG103443                            41008318    VAN GRIENS      KION

-- Good group of records 
BG100506  3        1      BG100506              BG100778      41008640    MALEN VAN       LARS
BG100506  3        2      BG100778              BG1T0877      41008640    MALEN VAN       LARS
BG100506  3        3      BG1T0877                            41008640    VAN MALEN       LARS

-- Bad, unwanted group of records
BG100778  2        1      BG100778              BG1T0877      41008640    MALEN VAN       LARS
BG100778  2        2      BG1T0877                            41008640    VAN MALEN       LARS

-- Third group for Lars
BG1T0877  1        1      BG1T0877                            41008640    VAN MALEN       LARS


-- Jan... fields are set differently than the above examples, but the chain is calculated correctly
BG100525  3        1      BG100525              BG1T0894      41008651    ZANWIJK VAN     JAN
BG100525  3        2      BG1T0894  TE035165    TE035165      41008651    VAN ZANWIJK     JAN
BG100525  3        3      TE035165                            41008651    VAN ZANWIJK     JAN

-- Bad
BG1T0894  2        1      BG1T0894  TE035165    TE035165      41008651    VAN ZANWIJK     JAN
BG1T0894  2        2      TE035165                            41008651    VAN ZANWIJK     JAN

-- Bad bad
TE035165  1        1      TE035165                            41008651    VAN ZANWIJK     JAN


-- Somebody goofed and gave Ziano a second SAP ID... but we still matched correctly
BG100527  3        1      BG100527              BG1T0896      41008652    STEFANI DE      ZIANO
BG100527  3        2      BG1T0896  TE033030    TE033030      41008652    STEFANI DE      ZIANO
BG100527  3        3      TE033030                            42006172    DE STEFANI      ZIANO

-- And we still got extra, unwanted groups
BG1T0896  3        2      BG1T0896  TE033030    TE033030      41008652    STEFANI DE      ZIANO
BG1T0896  3        3      TE033030                            42006172    DE STEFANI      ZIANO

TE033030  3        3      TE033030                            42006172    DE STEFANI      ZIANO


-- Mark's a perfect example of the missing/frustrating data I'm dealing with... but we still matched correctly
BG102188  3        1      BG102188              BG1T0543      41008250    BULINS          MARK
BG102188  3        2      BG1T0543              TE908583      41008250    BULINS          R.J.M.A.
BG102188  3        3      TE908583                            41008250    BULINS          RICHARD JOHANNES MARTINUS ALPHISIUS

-- Not wanted
BG1T0543  3        2      BG1T0543              TE908583      41008250    BULINS          R.J.M.A.
BG1T0543  3        3      TE908583                            41008250    BULINS          RICHARD JOHANNES MARTINUS ALPHISIUS

TE908583  3        3      TE908583                            41008250    BULINS          RICHARD JOHANNES MARTINUS ALPHISIUS


-- One more for good measure
BG1T0146  3        1      BG1T0146  BG105905    BG105905                  LUIJENT         VALERIE
BG1T0146  3        2      BG105905              TE034165      42006121    LUIJENT         VALERIE
BG1T0146  3        3      TE034165                            42006121    LUIJENT         VALERIE

BG105905  3        2      BG105905              TE034165      42006121    LUIJENT         VALERIE
BG105905  3        3      TE034165                            42006121    LUIJENT         VALERIE

TE034165  3        3      TE034165                            42006121    LUIJENT         VALERIE

そのすべての情報がより明確になるのか、それとも目が頭に戻ってくるのかはわかりません:)

これを見てくれてありがとう!

4

2 に答える 2

1

おそらく、ここで必要なのは複数のクエリです。各クエリは、検索しようとしているレコードのサブセットを検索します。各クエリは、単一の巨大なクエリよりも単純で高速であることが望まれます。何かのようなもの:

  1. ここで、new_user_idはnullで、SAPIDはnullです。
  2. ここで、new_user_idはnullではなく、SAPIDはnullです。
  3. ここで、new_user_idはnullであり、SAPIDはnullではありません
  4. ここで、new_user_idはnullではなく、SAPIDはnullではありません

(これらは袖口の例です)

この難問を解決する上での問題の一部は、問題空間が大きすぎることだと思います。この問題をより小さな部分に分割することにより、各部分が実行可能になります。

于 2012-10-30T05:44:43.653 に答える
1

私はそれを持っていると思います。私たちは時系列に固執することを許してきましたが、実際には問題ではありません。START WITH 句は「NEW_USER_ID IS NULL」にする必要があります。

時系列の順序を取得するには、「ORDER BY cudroot.node_level * -1」を実行できます。

また、WITH 句を使用してベース データを形成し、それに対して階層クエリを実行することを検討することをお勧めします。

于 2012-10-19T08:27:22.407 に答える