根据另一列 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 动态生成一列的数据组合的主要内容,如果未能解决你的问题,请参考以下文章