6

有一个繁重的查询(需要 15 分钟才能运行),但它返回的结果比我需要的要多。这是一个 CONNECT BY 查询,我得到的是根节点结果中的后代节点。IE:

Ted
  Bob
    John
Bob
  John
John

通常,解决此问题的方法是使用 START WITH 条件,通常要求节点的父节点为空。但是由于查询的性质,在获得完整结果集之前,我没有需要比较的 START WITH 值。我基本上是在尝试对我的结果进行双重查询,以说出 QUERY STUFF START WITH RECORDS THAT ART IN THE STUFF。


这是查询(在Nicholas Krasnov 的帮助下构建,这里: Oracle Self-Join on multiple possible column matches - 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 分钟查询。

我查看了在查询中使用分区,但实际上并没有分区...我想查看 new_user_ids 的完整结果集。还探索了rank()等分析函数……我的花招是空的。

有任何想法吗?


澄清

我不想要根列表中的额外记录的原因是因为我只想要每个用户的一组结果。IE,如果 Bob Smith 在他的职业生涯中有四个账户(人们经常来来往往,作为员工和/或承包商),我想使用一组都属于 Bob Smith 的账户。

如果 Bob 作为承包商来到这里,转换为员工,离开,作为承包商回到另一个国家,然后离开/返回到现在在我们 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在用户重命名时设置的字段或通过具有相同的 SAP ID 进行链接。

由于 HR 经常无法遵循业务流程,因此返回的用户最终可能会将这四个 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                 

这会导致两个问题:

  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

我想我有。我们已经让自己变得专注于时间顺序,而实际上这并不重要。您的 START WITH 子句应该是“NEW_USER_ID IS NULL”。

要获得时间顺序,您可以'ORDER BY cudroot.node_level * -1'。

我还建议您考虑使用 WITH 子句来形成您的基础数据并对其执行分层查询。

于 2012-10-19T08:27:22.407 回答
1

也许您在这里需要的是多个查询。每个查询都会找到您尝试查找的记录的子集。每个查询都有望比单个庞大的查询更简单、更快。就像是:

  1. 其中 new_user_id 为空,SAP ID 为空
  2. 其中 new_user_id 不为空且 SAP ID 为空
  3. 其中 new_user_id 为空且 SAP ID 不为空
  4. 其中 new_user_id 不为空且 SAP ID 不为空

(这些是袖口示例)

我认为解决这个难题的部分问题是问题空间太大。通过将这个问题细分为更小的部分,每个部分都是可行的。

于 2012-10-30T05:44:43.653 回答