根据另一列 SQL 动态生成一列的数据组合

Posted

技术标签:

【中文标题】根据另一列 SQL 动态生成一列的数据组合【英文标题】:Generate data combinations for a column dynamically based on another column SQL 【发布时间】:2020-12-16 08:35:15 【问题描述】:

我有一张如下表 -

COL1    COL2
-------------
101     A
102     B
102     C
102     D
103     C
103     E

我需要为COL1 中的一组唯一值生成所有可能的组合以及 uniqueID,如下所示 - 例如 - COL1 中有 3 个唯一值,可能有 6 种组合,因此应该有 18 行结果。可以有“n”个唯一值。我需要一个可以处理任意数量的组合和值的动态解决方案

1,101,A
1,102,B
1,103,C
2,101,A
2,102,B
2,103,E
3,101,A
3,102,C
3,103,C
4,101,A
4,102,C
4,103,E
5,101,A
5,102,D
5,103,C
6,101,A
6,102,D
6,103,E

请帮助并提出答案。我尝试使用 LAG、LEAD、CROSS JOIN,但无法找到解决方案。

答案可以使用任何 HANA SQL 脚本或 Oracle SQL 或 MS-SQL。

【问题讨论】:

请向我们展示您的尝试。 【参考方案1】:

我提出了以下基于递归 CTE、窗口函数和算术的解决方案。

with
  a as (
    select 101 as col1, 'A' as col2
    union all select 102, 'B'
    union all select 102, 'C'
    union all select 102, 'D'
    union all select 103, 'C'
    union all select 103, 'E'
  ),
  b as (
    select
      col1, col2,
      count(*) over() as ct,
      count(*) over(partition by col1) as cc1,
      dense_rank() over(order by col1 desc) as rk1,
      row_number() over(partition by col1
                        order by col2) as rn12
    from a
  ),
  r as (
    select
      col1, col2, ct / cc1 as rq, ct / cc1 as ll, cc1, rk1, rn12
    from b
    union all
    select col1, col2, rq, ll - 1, cc1, rk1, rn12
    from r
    where ll > 1
  )
select
  iif(rk1 = 1, (ll - 1) * cc1 + rn12, (rn12 - 1) * rq + ll) as id,
  col1, col2
from r
order by id, col1, col2
option (maxrecursion 0);

输出:

+----+------+------+
| id | col1 | col2 |
+----+------+------+
|  1 |  101 | A    |
|  1 |  102 | B    |
|  1 |  103 | C    |
|  2 |  101 | A    |
|  2 |  102 | B    |
|  2 |  103 | E    |
|  3 |  101 | A    |
|  3 |  102 | C    |
|  3 |  103 | C    |
|  4 |  101 | A    |
|  4 |  102 | C    |
|  4 |  103 | E    |
|  5 |  101 | A    |
|  5 |  102 | D    |
|  5 |  103 | C    |
|  6 |  101 | A    |
|  6 |  102 | D    |
|  6 |  103 | E    |
+----+------+------+

在 rextester.com 上试用 Microsoft SQL Server、Oracle 和 PostgreSQL。

【讨论】:

【参考方案2】:
declare @t table (col1 int, col2 varchar(5));
insert into @t(col1, col2)
values
(101, 'A'), (101, 'B'), (101, 'C'), (101, 'D'),
(102, 'E'), (102, 'F'), (102, 'G'),
(103, 'H'), (103, 'I'), 
(104, 'J'), (104, 'K');


select t.combid, o.col1, o.col2
from 
(
    --number of combinations
    select agr.col1, agr.col2cnt, 
        --float-->decimal:truncate --> int
        cast(cast(exp(sum(log(agr.col2cnt)) over(order by agr.col1 desc)) as decimal(38,0)) as int)  as restcombs,     
        cast(cast(exp(sum(log(agr.col2cnt)) over()) as decimal(38,0)) as int)  as combsint
    from
    (
    --count of col2 per col1
    select col1, count(*) as col2cnt
    from @t
    group by col1
    ) as agr
) as dc
cross apply
(

    select jt.combid,
        1 + (1+(jt.combid-1)/(dc.restcombs/dc.col2cnt)-1)%dc.col2cnt  as col2ordinal --ordinal of col2 within the combination            
    from
    (
    --just a tally, from 1 till combinations:=combsint
    select top (dc.combsint) row_number() over(order by @@spid) as combid
    from sys.all_objects as a
    cross join sys.all_objects as b
    cross join sys.all_objects as c 
    ) as jt
) as t
join
(
    --ordinal of col2 per col1
    select col1, col2, row_number() over(partition by col1 order by col2) as col2ordinal
    from @t
) as o on dc.col1 = o.col1 and t.col2ordinal = o.col2ordinal
order by t.combid, o.col1;

【讨论】:

以上是关于根据另一列 SQL 动态生成一列的数据组合的主要内容,如果未能解决你的问题,请参考以下文章

如何根据另一列的单元格值由其他列动态更新A列

基于数据列中的值生成动态图像

根据不同数据类型的另一列设置一列的默认值

SQL - 根据另一列中的日期过滤一列的结果

求sql语句!在同一表中,如何根据一列包含的内容,替换另一列的数据?

mysql如何根据一列值更新另一列的值?