获取csv的排序顺序和值的每种组合

时间:2014-08-28 01:08:24

标签: sql sql-server sql-server-2008 tsql

如果我有一个用逗号分隔数字的字符串,就像这样:

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.的顺序,并且只提供每个组合,这只是战斗的一半。

目前我不知道该尝试什么。如果有人可以提供一些帮助,我们将不胜感激。

1 个答案:

答案 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,则需要相应地扩展您的代码。