【问题标题】:Generate data combinations for a column dynamically based on another column SQL根据另一列 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。

【问题讨论】:

  • 请向我们展示您的尝试。

标签: sql sql-server window-functions hana-sql-script


【解决方案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 ServerOraclePostgreSQL

【讨论】:

    【解决方案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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-23
      • 1970-01-01
      • 1970-01-01
      • 2022-07-22
      • 2022-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多