1

我有一个使用 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 来让它工作,但还没有运气,我在网上找不到任何东西。

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

4

1 回答 1

0

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

有许多技术可以在 Oracle 中从分隔字符串构建集合,其中一种技术在对另一个问题的回答中进行了说明。

创建所需的集合类型:

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

因为我不知道哪一列 (sourcetarget) 包含分隔列表,所以我为每个列添加了列。

在构建集合之后,可以使用多集运算符和可用的测试函数来匹配目标和源。例如

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构造很有用。

于 2013-07-02T17:57:15.427 回答