首页 > 解决方案 > 前 N 个案例的无重复组合的 SQL 查询

问题描述

我需要一个可以在(或作为)函数中使用并从表中检索 M 值的 N 组合的查询。

示例:输入:多行中一列中的值的表

情况1

N=2
M=4 (Record1 to Record4)

桌子

Record1
Record2
Record3
Record4

输出

Record1
Record2
Record3
Record4
Record1,Record2
Record1,Record3
Record1,Record4
Record2,Record3
Record2,Record4
Record3,Record4

案例2

N=3
M=4 (Record1 to Record4)

桌子

Record1
Record2
Record3
Record4

输出

Record1
Record2
Record3
Record4
Record1,Record2
Record1,Record3
Record1,Record4
Record2,Record3
Record2,Record4
Record3,Record4
Record1,Record2,Record3
Record1,Record2,Record4
Record1,Record3,Record4
Record2,Record3,Record4

我使用这个问题作为执行的基本代码

标签: sqlsql-servertsql

解决方案


如果每个组合只需要固定数量的 N 个值,那么可以在普通 SQL 中轻松完成。

只需使用 N-1 个自连接。

例如,如果 N = 3,则 2 个自连接:

SELECT 
CONCAT(t1.name, ',', t2.name, ',', t3.name) AS names
FROM yourtable t1
JOIN yourtable t2 ON t2.name > t1.name
JOIN yourtable t3 ON t3.name > t2.name;

由于>在连接中使用了,这不会以不同的顺序返回相同组合的重复项。
(因为A,B,C= A,C,B = B,A,C= B,C,A= C,A,B= C,B,A

如果 N 是可变的,那么可以在将 N-1 个连接添加到查询字符串的动态 Sql 中使用这种方法。

但是,为了获得问题的预期输出,也返回 N=1 & N=2 & N=3,那么我们可以将该技巧与递归 CTE 结合使用。

例如这个 T-SQL 片段:

declare @yourtable table ([name] varchar(30));
insert into @yourtable ([name]) values 
('Record1'), 
('Record2'), 
('Record3'), 
('Record4');

WITH RCTE AS 
(
    SELECT 1 as N, t.name as prev_name, cast(t.name as varchar(max)) AS names
    FROM @yourtable t

    UNION ALL

    SELECT N + 1, t.name, CONCAT(r.names,','+ t.name)
    FROM @yourtable t
    JOIN RCTE r ON t.name > r.prev_name AND r.N < 3
)
SELECT names
FROM RCTE
ORDER BY N, names;

回报:

names
------------------------
Record1
Record2
Record3
Record4
Record1,Record2
Record1,Record3
Record1,Record4
Record2,Record3
Record2,Record4
Record3,Record4
Record1,Record2,Record3
Record1,Record2,Record4
Record1,Record3,Record4
Record2,Record3,Record4

推荐阅读