如果我有一个用逗号分隔数字的字符串,就像这样:
Declare @string varchar(20) = '123,456,789'
并希望通过执行以下操作返回每个可能的组合+值的排序顺序:
Select Combination FROM dbo.GetAllCombinations(@string)
结果会返回这个:
123
456
789
123,456
456,123
123,789
789,123
456,789
789,456
123,456,789
123,789,456
456,789,123
456,123,789
789,456,123
789,123,456
正如您所看到的,不仅返回了每个组合,而且还返回了每个组合+排序顺序。该示例仅显示以逗号分隔的3个值,但应解析任何数量 - 递归。
所需的逻辑将在使用WITH CUBE
语句的某个地方,但使用WITH CUBE
(在表结构而不是CSV中)的问题是它不会改变值123,456 456,123 etc.
的顺序,并且只提供每个组合,这只是战斗的一半。
目前我不知道该尝试什么。如果有人可以提供一些帮助,我们将不胜感激。
答案 0 :(得分:0)
我使用一个名为split_delimiter的用户定义的表值函数,该函数有2个值:@ delimited_string和@delimiter_type。
CREATE FUNCTION [dbo].[split_delimiter](@delimited_string VARCHAR(8000), @delimiter_type CHAR(1))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,cte100(num) AS
(
SELECT 1
FROM cte10 t1, cte10 t2
)
,cte10000(num) AS
(
SELECT 1
FROM cte100 t1, cte100 t2
)
,cte1(num) AS
(
SELECT TOP (ISNULL(DATALENGTH(@delimited_string),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
,cte2(num) AS
(
SELECT 1
UNION ALL
SELECT t.num+1
FROM cte1 t
WHERE SUBSTRING(@delimited_string,t.num,1) = @delimiter_type
)
,cte3(num,[len]) AS
(
SELECT t.num
,ISNULL(NULLIF(CHARINDEX(@delimiter_type,@delimited_string,t.num),0)-t.num,8000)
FROM cte2 t
)
SELECT delimited_item_num = ROW_NUMBER() OVER(ORDER BY t.num)
,delimited_value = SUBSTRING(@delimited_string, t.num, t.[len])
FROM cte3 t;
使用它我可以将CSV解析为表并将其多次连接回自身并使用WITH ROLLUP来获取您正在寻找的排列。
WITH Numbers as
(
SELECT delimited_value
FROM dbo.split_delimiter('123,456,789',',')
)
SELECT CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR)
FROM Numbers as Nums1
LEFT JOIN Numbers as Nums2
ON Nums2.delimited_value not in (Nums1.delimited_value)
LEFT JOIN Numbers as Nums3
ON Nums3.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value)
LEFT JOIN Numbers as Nums4
ON Nums4.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value, Nums3.delimited_value)
GROUP BY CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR) WITH ROLLUP
如果您可能超过3或4,则需要相应地扩展您的代码。