【问题标题】:PLSQL - Connect By Prior (many to many)PLSQL - 按先验连接(多对多)
【发布时间】:2013-07-02 14:11:42
【问题描述】:

我有一个使用 connect by 语句对递归数据进行排序的查询。我遇到的问题是偶尔会有一对多或多对一的关系,我不知道如何处理它。

  SELECT  *  
FROM (SELECT * FROM bdTable WHERE parentek = t_parKey)
START WITH source is null
CONNECT BY PRIOR target = source 

所以解释一下。我有一个源列和目标列。大约 99% 的时间,这些都是一个唯一的 ID。不幸的是,另外 1% 的时间在其中一列中有一组 ID。该表是流程图类型工具的平面表示,因此可以有许多输出的拆分和决策和可以有许多输入的合并。

为了在为表加载数据时处理这个问题,使用 listagg 函数将唯一 ID 连接在一起。所以我最终得到的目标值类似于“1254143,2356334,6346436,3454363,3462354,442356”。

因此,当我的 connect by 语句被执行时,它会完美运行,直到遇到其中一种情况,此时它就会停止(当然这是意料之中的)。
我想我可能能够以某种方式使用 IN 或 INSTR 来让它工作,但还没有运气,我在网上找不到任何东西。

任何帮助将不胜感激.....

【问题讨论】:

  • 您能提供某种模式吗?此外,串联的“唯一”ID 通常不是最佳策略,您可能希望创建自己的唯一 ID。
  • 虽然我不认为创建自己的唯一 ID 作为答案,但它确实让我想到了一个可能的解决方案。暂时让我来吧。还是谢谢。

标签: oracle plsql hierarchical-query


【解决方案1】:

如果您想使用某种逻辑加入target 和source,基于每列中列出的一组值的交集,那么最可靠的方法是将字符串拆分为集合并进行操作从前一行收集并从当前行收集来构建一棵树。

在 Oracle 中有许多技术可以从分隔的字符串中构建集合,其中一种技术说明了 in this answer to another question。

创建所需的集合类型:

create or replace type TIdList as table of varchar2(100);

在您的情况下,内部选择如下所示:

SELECT
  t.*,
  (
    cast(multiset( -- Convert set of values into collection
      select  -- Build list of values from separated string
          substr(
            source,
            decode( level, 1, 1, instr(source,',',1,level-1)+1 ),
            decode( instr(source,',',1,level), 0, length(source)+1, instr(source,',',1,level) )
              -
              decode( level, 1, 1, instr(source,',',1,level-1)+1 )
          ) code
      from dual
      start with source is not null
      connect by instr(source,',',1,level-1) > 0

    ) as TIdList )
  )                          source_id_list,
  (
    cast(multiset( -- Convert set of values into collection
      select  -- Build list of values from separated string
          substr(
            target,
            decode( level, 1, 1, instr(target,',',1,level-1)+1 ),
            decode( instr(target,',',1,level), 0, length(target)+1, instr(target,',',1,level) )
              -
              decode( level, 1, 1, instr(target,',',1,level-1)+1 )
          ) code
      from dual
      start with target is not null
      connect by instr(target,',',1,level-1) > 0
    ) as TIdList )
  )                          target_id_list
FROM bdTable t
WHERE t.parentek = t_parKey

因为我不知道哪一列(source 或 target)包含分隔列表,所以我为每个列都包含。

构建集合后,可以使用multiset operators 和可用的test functions 将目标与源匹配。例如。

with inner_query as (
  SELECT
    t.*,
    (
      cast(multiset( -- Convert set of values into collection
        select  -- Build list of values from separated string
            substr(
              source,
              decode( level, 1, 1, instr(source,',',1,level-1)+1 ),
              decode( instr(source,',',1,level), 0, length(source)+1, instr(source,',',1,level) )
                -
                decode( level, 1, 1, instr(source,',',1,level-1)+1 )
            ) code
        from dual
        start with source is not null
        connect by instr(source,',',1,level-1) > 0

      ) as TIdList )
    )                          source_id_list,
    (
      cast(multiset( -- Convert set of values into collection
        select  -- Build list of values from separated string
            substr(
              target,
              decode( level, 1, 1, instr(target,',',1,level-1)+1 ),
              decode( instr(target,',',1,level), 0, length(target)+1, instr(target,',',1,level) )
                -
                decode( level, 1, 1, instr(target,',',1,level-1)+1 )
            ) code
        from dual
        start with target is not null
        connect by instr(target,',',1,level-1) > 0
      ) as TIdList )
    )                          target_id_list
  FROM bdTable t
  WHERE t.parentek = t_parKey
)
select 
  level       lvl,
  tree_list.*
from
  inner_query tree_list
start with  
  source is null
connect by 
  nvl(cardinality(prior target_id_list MULTISET INTERSECT source_id_list),0) > 0

如果只有一列可以包含值列表,那么MEMBER OF 构造很有用。

【讨论】:

    猜你喜欢
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 2015-02-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多