在t-sql中生成具有可变长度的给定字符集的所有可能的排列

时间:2012-07-18 19:27:10

标签: tsql

我已经编写了下面的脚本来生成指定字符集的所有可能的排列。

有没有办法有效地执行此操作,同时允许在运行时指定长度?

DECLARE @string NVARCHAR(MAX)
SELECT @string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

DECLARE @Chars TABLE (
    C CHAR(1) PRIMARY KEY
)

DECLARE @N INT 
SET @N = 1 
WHILE @N <= LEN(@string) BEGIN
    INSERT @Chars (
        C
    ) VALUES (
        SUBSTRING(@string, @N, 1)
    )

    SET @N = @N + 1
END

--SELECT * FROM @Chars


SELECT
    A.C + B.C + C.C
FROM @Chars A, @Chars B, @Chars C
ORDER BY
    A.C,
    B.C,
    C.C

2 个答案:

答案 0 :(得分:2)

如果您使用的是SQL Server 2005或更高版本,则可以尝试递归CTE:

DECLARE @length int;
SET @length = 3;

WITH expanded AS (
  SELECT
    C = SUBSTRING(@string, N, 1)
  FROM numbers
  WHERE number BETWEEN 1 AND LEN(@string)
),
permutations AS (
  SELECT
    S = CAST(C AS nvarchar(max)),
    L = 1
  FROM expanded
  UNION ALL
  SELECT
    S = S + C,
    L = L + 1
  FROM permutations p
  CROSS JOIN expanded e
  WHERE L < @length
)
SELECT *
FROM permutations
WHERE L = @length
;

此处numbersauxiliary table of numbers,用于将字符串扩展为单个字符列。

如果没有更多更改,此查询将使用最多100个@length值而不会出现问题。如果你想要更长的排列,你需要附加这一行:

OPTION (MAXRECURSION n)

其中 n 是一个0到32767之间的整数值,表示递归CTE的最大迭代次数,上面提到的100是默认值。无实际意味着没有限制,应该谨慎使用。

您可以尝试此查询(并使用它)at SQL Fiddle,我将@string缩减为仅8个字符(以便能够为@length指定更多不同的值而不制作查询返回太多行)并将numbers表定义为system table master..spt_values的子集。

答案 1 :(得分:0)

在收到与可能的排列数相关的评论之后,我意识到字符集的长度以及指定的长度应该有非常严格的限制。

鉴于可允许的长度非常小,我认为在我的脚本中使用条件没有坏处......就像这样:

DECLARE
    @string NVARCHAR(40), --limit the length of the character set to 40
    @length INT -- the limit for this is in a validation check below

SELECT
    @string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    @length = 2



IF (@length < 1 OR @length > 4) BEGIN
    RAISERROR('Invalid length specified. This function only supports lengths from 1 to 4', 16, 1)
END



DECLARE @Chars TABLE (
    C CHAR(1) PRIMARY KEY
)

;WITH numbers AS (
    SELECT TOP(LEN(@string)) number
    FROM master..spt_values
    WHERE type = 'P'
    AND number != 0
)

INSERT @Chars (
    C
)
SELECT
    C = SUBSTRING(@string, number, 1)
FROM numbers


IF (@length = 1) BEGIN
    SELECT C FROM @Chars ORDER BY C
END ELSE IF (@length = 2) BEGIN
    SELECT A.C + B.C
    FROM @Chars A, @Chars B
    ORDER BY A.C, B.C
END ELSE IF (@length = 3) BEGIN
    SELECT A.C + B.C + C.C
    FROM @Chars A, @Chars B, @Chars C
    ORDER BY A.C, B.C, C.C
END ELSE IF (@length = 4) BEGIN
    SELECT A.C + B.C + C.C + D.C
    FROM @Chars A, @Chars B, @Chars C, @Chars D
    ORDER BY A.C, B.C, C.C, D.C
END