T-SQL"动态"加入

Dav*_*ler 7 sql t-sql sql-server permutation common-table-expression

给定以下带有单个char(1)列的SQL Server表:

Value
------
'1'
'2'
'3'
Run Code Online (Sandbox Code Playgroud)

如何在T-SQL中获得以下结果?

Result
------
'1+2+3'
'1+3+2'
'2+1+3'
'2+3+1'
'3+2+1'
'3+1+2'
Run Code Online (Sandbox Code Playgroud)

这也需要是动态的,所以如果我的表只保存行'1'和'2',我期望:

Result
------
'1+2'
'2+1'
Run Code Online (Sandbox Code Playgroud)

看起来我应该能够使用CROSS JOIN来做到这一点,但由于我不知道会提前有多少行,所以我不确定CROSS JOIN会多少次回到自己身上......?

SELECT a.Value + '+' + b.Value
FROM MyTable a
CROSS JOIN MyTable b
WHERE a.Value <> b.Value
Run Code Online (Sandbox Code Playgroud)

在任何给定时间总是会有少于10行(实际上更像是1-3行).我可以在SQL Server中即时执行此操作吗?

编辑:理想情况下,我希望这发生在一个存储过程中,但如果我必须使用另一个proc或一些用户定义的函数来解决这个问题,我就可以了.

Dav*_*vid 12

此SQL将计算排列而不重复:

WITH recurse(Result, Depth) AS
(
    SELECT CAST(Value AS VarChar(100)), 1
    FROM MyTable

    UNION ALL

    SELECT CAST(r.Result + '+' + a.Value AS VarChar(100)), r.Depth + 1
    FROM MyTable a
    INNER JOIN recurse r
    ON CHARINDEX(a.Value, r.Result) = 0
)

SELECT Result
FROM recurse
WHERE Depth = (SELECT COUNT(*) FROM MyTable)
ORDER BY Result
Run Code Online (Sandbox Code Playgroud)

如果MyTable包含9行,则需要一些时间来计算,但它将返回362,880行.

更新说明:

WITH语句用于定义递归公用表表达式.实际上,WITH语句循环多次执行a UNION直到递归完成.

SQL的第一部分设置起始记录.假设3行名为"A","B"和"C" MyTable,这将生成以下行:

    Result     Depth
    ------     -----
    A          1
    B          1
    C          1
Run Code Online (Sandbox Code Playgroud)

然后下一个SQL块执行第一级递归:

    SELECT CAST(r.Result + '+' + a.Value AS VarChar(100)), r.Depth + 1
    FROM MyTable a
    INNER JOIN recurse r
    ON CHARINDEX(a.Value, r.Result) = 0
Run Code Online (Sandbox Code Playgroud)

这将获取到目前为止生成的所有记录(将在recurse表中)并MyTable再次将它们连接到所有记录.该ON子句过滤记录列表,MyTable仅返回此行排列中不存在的记录.这将导致这些行:

    Result     Depth
    ------     -----
    A          1
    B          1
    C          1
    A+B        2
    A+C        2
    B+A        2
    B+C        2
    C+A        2
    C+B        2
Run Code Online (Sandbox Code Playgroud)

然后递归循环再次给出这些行:

    Result     Depth
    ------     -----
    A          1
    B          1
    C          1
    A+B        2
    A+C        2
    B+A        2
    B+C        2
    C+A        2
    C+B        2
    A+B+C      3
    A+C+B      3
    B+A+C      3
    B+C+A      3
    C+A+B      3
    C+B+A      3
Run Code Online (Sandbox Code Playgroud)

此时,递归停止,因为它UNION不会再创建任何行,因为它CHARINDEX总是如此0.

最后一个SQL过滤计算Depth列与其中的记录数匹配的所有结果行MyTable.抛出除最后一次递归深度生成的行之外的所有行.所以最终的结果将是这些行:

    Result
    ------
    A+B+C
    A+C+B
    B+A+C
    B+C+A
    C+A+B
    C+B+A
Run Code Online (Sandbox Code Playgroud)