所有值的组合(Oracle)

时间:2019-10-10 14:32:55

标签: oracle combinations

我想从给定的数据集中获得所有可能的组合,但即使是空元素(即元素数量可变)

示例我们有数据和一个简单的查询来显示它们:

with t as (   select 1 as COL1, 2 as COL2, 3 as COL3 from dual )  
select * from t;

或更佳的示例:(也许很容易解决)

select 1 as col from dual 
union all 
select 2 from dual 
union all 
select 3 from dual

是否可以创建显示以下结果的查询:

1     -     -
1     2     -
1     2     3
1     3     -
1     3     2

2     -     -
2     1     -
2     1     3
2     3     -
2     3     1

3     -     -
3     1     -
3     1     2
3     2     -
3     2     1

1 个答案:

答案 0 :(得分:1)

这里的一个困难是,您将输入分为三列,而希望将结果分为三列。除非您愿意使用动态SQL(这是一个单独的主题,这是一种高级技术,在大多数情况下也是一种不好的做法,并且实际上与组合语言的问题无关),否则您必须对数字进行硬编码(并且名称)中的列。

您可以按行而不是按列显示输入数据,并以

格式查询结果
row_num  col_num  val
-------  -------  ---
      1        1    1
      1        2    -
      1        3    -

(这仅模仿您的第一个输出行)-与所有其他行类似-然后您不必对查询中的列数进行硬编码;然后,您可以轻松地修改下面的代码来解决这个更普遍的问题。

我在下面使用SYS_CONNECT_BY_PATH,它限制了列数(以及输入中每列中值的长度);可以避免这种情况,但是用这种方式编写查询很有趣。

我假设您期望的输出中的破折号-代表NULL;如果您实际上想显示破折号,请在最后的NVL(..., -)子句中使用SELECT

with
  t (col1, col2, col3) as (
    select 1 as col1, 2 as col2, 3 as col3 from dual
  )
, prep (pth) as (
    select  sys_connect_by_path(val, '/') || '/' 
    from    t 
    unpivot (val for col in (col1, col2, col3))
    connect by nocycle prior col is not null
  )
select to_number(substr(pth, instr(pth, '/', 1, 1) + 1, 
                        instr(pth, '/', 1, 2) - instr(pth, '/', 1, 1) - 1)) col1,
       to_number(substr(pth, instr(pth, '/', 1, 2) + 1, 
                        instr(pth, '/', 1, 3) - instr(pth, '/', 1, 2) - 1)) col2,
       to_number(substr(pth, instr(pth, '/', 1, 3) + 1, 
                        instr(pth, '/', 1, 4) - instr(pth, '/', 1, 3) - 1)) col3
from   prep
order  by col1 nulls first, col2 nulls first, col3 nulls first
;

输出:

 COL1  COL2  COL3
----- ----- -----
    1            
    1     2      
    1     2     3
    1     3      
    1     3     2
    2            
    2     1      
    2     1     3
    2     3      
    2     3     1
    3            
    3     1      
    3     1     2
    3     2      
    3     2     1