使用间接加入的组创建定界列表

时间:2018-08-02 04:58:11

标签: sql oracle plsql

我正在尝试找到一种以逗号分隔的相关行字符串的方法,该行可以由两列之一链接,但是并非每一行都不需要彼此直接连接组中的行。例如,假设表脚本为:

select 'A' col1, null col2, 2000 year from dual
union all select 'B' col1, 'A' col2, 2000 year from dual
union all select 'C' col1, 'B' col2, 2000 year from dual
union all select 'D' col1, null col2, 2000 year from dual
union all select 'D' col1, null col2, 2001 year from dual
union all select 'C' col1, 'E' col2, 2000 year from dual
union all select 'C' col1, null col2, 2000 year from dual
union all select 'A' col1, 'B' col2, 2002 year from dual

所以表看起来像这样:

+------+------+------+
| col1 | col2 | year |
+------+------+------+
| A    |      | 2000 |
| B    | A    | 2000 |
| C    | B    | 2000 |
| D    |      | 2000 |
| D    |      | 2001 |
| C    | E    | 2000 |
| C    |      | 2000 |
| A    | B    | 2002 |
+------+------+------+

定界列表基于链接的col1或col2的每种组合以及年份。排除null和重复项,并且列表中的值按名称排序。因此,新列希望每行下面都有列表列:

+------+------+------+---------+
| col1 | col2 | year |  list   |
+------+------+------+---------+
| A    |      | 2000 | A,B,C,E |
| B    | A    | 2000 | A,B,C,E |
| C    | B    | 2000 | A,B,C,E |
| D    |      | 2000 | D       |
| D    |      | 2001 | D       |
| C    | E    | 2000 | A,B,C,E |
| C    |      | 2000 | A,B,C,E |
| A    | B    | 2002 | A,B     |
+------+------+------+---------+

我当时正考虑使用listagg,但由于不可能将组中的每一行都直接连接到组中的其他某些行,因此这似乎是不可能的。

编辑:此操作的目的是创建一个唯一的标识符,该标识符可用于按年份对表格进行排序,将各组保持在一起。

例如,我们可以有一个示例表:

  +-----+------+------+
  |col1 | col2 | year |
  +-----+------+------+
 1| F   |      | 2000 |
 2| G   |      | 2000 |
 3| H   | I    | 2000 |
 4| L   | N    | 2000 |
 5| F   | R    | 2000 |
 6| Z   | R    | 2000 |
 7| G   | Z    | 2000 |
 8| X   | T    | 2000 |
 9| R   |      | 2000 |
10| T   | Y    | 2000 |
  +-----+------+------+

因此,在此示例表中,行1、2、5、6、7和9将属于同一组,然后是行3,行4,然后是由行8和10组成的另一组

将组一起移动的表排序如下:

  +-----+------+------+
  |col1 | col2 | year |
  +-----+------+------+
 1| F   |      | 2000 |
 5| F   | R    | 2000 |
 2| G   |      | 2000 |
 7| G   | Z    | 2000 |
 9| R   |      | 2000 |
 6| Z   | R    | 2000 |
 3| H   | I    | 2000 |
 4| L   | N    | 2000 |
10| T   | Y    | 2000 |
 8| X   | T    | 2000 |
  +-----+------+------+

1 个答案:

答案 0 :(得分:2)

这是一种相当程序化的方法,但是会产生所需的输出。

第一个子查询给出了链接的COL1,COL2值的集合;您的问题未定义“已链接” ,但是您似乎是想说,在给定年份中,COL2的值以及填充了COL2的任何COL1实例。第二个子查询产生未链接的COL1值的正面集合。第三个子查询从前两个子查询的输出中生成串联列表。

with cte as 
  ( select year, col1 from t23 where col2 is not null
    union 
    select year, col2 as col1 from t23 where col2 is not null
    )
    , cte2 as 
    ( select year, col1 from t23 
       where (year, col1) not in (select year, col1 from cte) 
       )
    , cte3 as (
       select year, col1
              , listagg (cte.col1, ', ') within group (order by cte.col1) 
                                                  over (partition by year) as list
       from cte 
        union 
       select year, col1
              , listagg (cte2.col1, ', ') within group (order by cte2.col1) 
                                                 over ( partition by year) as list
       from cte2 
   )
select t23.*
       , cte3.list
from t23
     join cte3 on cte3.year = t23.year 
     and cte3.col1 = t23.col1
;

这里是a LiveSQL demo。 (A,需要免费的Oracle登录;我本来会使用SQLFiddle,但该站点目前不支持Oracle。)