3

我有一个来自----的查询要求。试图用 解决它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

有两种用户数据来源(数据馈送)...在更新信息时,我必须注意其中任何一个中的错误。


场景:

  1. 一个用户被赋予了一个新的用户 ID... 旧记录被相应地设置并被停用(通常为成为全职的承包商重命名)
  2. 用户离开并稍后返回。HR 未能将旧用户 ID 发送给我们,以便我们可以连接帐户。
  3. 系统搞砸了,没有在旧记录上设置新的用户 ID。
  4. 数据可能以其他一百种方式变坏


我需要知道以下是同一个用户,我不能依赖名称或其他字段......它们在匹配记录中有所不同:

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    


EXOT1100EX000005通过NEW_USER_ID现场正确连接。重命名发生在全球 HR ID 之前,因此EX0T1100没有。 EX000005被赋予了一个新的用户 ID,“GL110456”,并且两者仅通过具有相同的全局 HR ID 来连接。

清理数据不是一种选择。


到目前为止的查询:

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);


我尝试了各种CONNECT BY条款,但没有一个是完全正确的:

-- 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    


想法?


更新

Nicholas,您的代码看起来非常像正确的轨道......目前,当为空时,lead(user_id) over (partition by global_hr_id)得到错误命中。global_hr_id例如:

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

我经常想将空值视为分区中的单独记录,但我从来没有找到一种方法来ignore nulls工作。这做了我想要的:

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

...但必须有更好的方法。我还没有能够完成对完整用户数据(大约 40,000 个用户)的查询。global_hr_id和都new_user_id被索引。


更新

查询在大约 750 秒后返回……很长,但易于管理。它返回 93k 记录,因为我没有从根目录中过滤级别 2 命中的好方法 - 你有start with global_hr_id is null,但不幸的是,情况并非总是如此。我将不得不考虑更多关于如何过滤掉这些内容。

我之前尝试过添加更复杂的 start with 子句,但我发现它们单独运行 < 1 秒......一起,它们需要 90 分钟 >.<

再次感谢您的帮助...为此而步履蹒跚。

4

1 回答 1

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
于 2012-10-15T02:38:06.270 回答