找到所有组合

时间:2014-09-06 06:31:49

标签: sql sql-server algorithm tsql stored-procedures

我的老师问一个找到所有组合的算法。我有一组数据,长度可以变化。所以组合应该是这样的:

a
b
c
aa
ab
ac
...
ccbc
ccca
cccb
cccc

它们将存储在包含单个varchar字段的“word”表中。 我用循环做了,因为我不喜欢递归,而jt有更好的性能:

DROP PROCEDURE combi;
CREATE PROCEDURE combi
AS
BEGIN
    DELETE FROM word
    DECLARE @i BIGINT
    DECLARE @j INT
    DECLARE @word NVARCHAR(24)
    DECLARE @str NVARCHAR(62)
    DECLARE @combinations BIGINT
    DECLARE @currentlength TINYINT
    DECLARE @maxcurrentlength TINYINT
    SET @maxcurrentlength=4
    SET @str='azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789' -- length=62
    SET @currentlength=1
    -- loop on the length of the text
    WHILE @currentlength<=@maxcurrentlength BEGIN
        SET @combinations=POWER(62,@currentlength)
        SET @i=0
        -- get all combinations
        WHILE i<@combinations BEGIN
            SET @word=''
            SET @j=0
            -- generate word
            WHILE @j<@currentlength BEGIN
                SET @word=@word+SUBSTRING(@str, (FLOOR(@i / POWER(62,@currentlength-@j-1) ) % 62) +1, 1)
                SET @j=@j+1
            END
            INSERT INTO word VALUES (@word)
            SET @i=@i+1
        END
        SET @currentlength=@currentlength+1
    END
END;
EXEC combi;

问题是,当我使用8的长度时,我的服务器崩溃了:似乎POWER(62,@currentlength-@j-1)是问题所在。

5 个答案:

答案 0 :(得分:1)

我对你如何提出问题感到有些困惑。你要求“找到所有组合”,这很容易用CROSS JOIN完成。如果您需要获得4的长度,那么您可以将表中的可用值加入表中4次,并且您已经完成了很多工作。如果你需要在1字段中获取字符串,可以在select中连接它们。像这样:

declare @values table (
value nvarchar(100))

insert @values values ('a'),('b'),('c')

select v1.value+v2.value+v3.value+v4.value
from @values v1 cross join 
    @values v2 cross join
    @values v3 cross join
    @values v4
order by v1.value+v2.value+v3.value+v4.value

答案 1 :(得分:1)

以下是通用解决方案,使用递归CTE

CREATE TABLE t (i nchar(1))
INSERT INTO t VALUES ('a'),('b'),('c')

;WITH cte AS (
   SELECT cast(i AS nvarchar(4000)) AS combo, 1 AS ct
   FROM   t

   UNION  ALL
   SELECT cte.combo + t.i, ct + 1
   FROM   cte
   CROSS  JOIN t
   WHERE  ct <= 4  -- your maximum length
   )
SELECT combo
FROM   cte
ORDER  BY ct, combo

SQL Fiddle.

您必须意识到结果数量会随着最大长度的增加而增加指数,因此随着最大长度的增加,性能会迅速恶化。

答案 2 :(得分:0)

由于documentation for power建议POWER()返回与您提供的相同类型,您可能会溢出传递给POWER()的int类型。

尝试使用:

SET @word=@word+SUBSTRING(@str, (FLOOR(@i / POWER(CAST(62 AS BIGINT),@currentlength-@j-1) ) % 62) +1, 1)

答案 3 :(得分:0)

如果你需要对它进行参数化以便你可以设置所需的长度,那么这个算法就可以做到这一点,而且它更关注数据库的定位。

declare @characters table (character nchar(1))
declare @words table (word nvarchar(100))
insert @characters values ('a'),('b'),('c')
INSERT @words (word ) VALUEs ('')
DECLARE @Required_length int
DECLARE @length int
SET @Required_length = 4
SET @length  = 0
WHILE @length <= @Required_length
BEGIN
SET @length  = @length+1
INSERT @words (word ) 
SELECT w.word + c.character
FROM @words w JOIN  @characters c ON LEN(w.word) = @length-1
END
SELECT word from @words where len(word) = @Required_length
  • 以零长度字开头
  • 将所有可能的字符添加到零长度字中以获取所有字符 一个字的单词
  • 将所有可能的字符添加到所有一个字符的末尾 得到所有两个字的单词
  • 将所有可能的字符添加到所有两个字符单词的末尾 获得所有三个字符
  • 等...

您可以通过在字表中包含长度作为列来提高其运行效率,这样您就不需要在他们通过它们进行过滤时计算长度,但是这已经由你的老师我不会为你做你所有的工作

答案 4 :(得分:0)

首次插入所有字符

SET NOCOUNT ON;
create table ##chars (col char(1))
declare @i int 
set @i=65
while @i<=90  /* A-Z */
begin
  insert into ##chars values( CHAR(@i))
  set @i=@i+1
end
set @i=97
while @i<=122 /* a-z */
begin
  insert into ##chars values( CHAR(@i))
  set @i=@i+1
end
set @i=48
while @i<=57  /* 0-9 */
begin
  insert into ##chars values( CHAR(@i))
  set @i=@i+1
end

现在,设置组合编号

create table ##result(word varchar(10))
declare @wide int
set @wide=4    /* set how many combinations are calculated  */


insert into ##result select * from ##chars
while @wide>1
begin
    begin tran w
    insert into ##result select a.word+b.col from ##result a, ##chars b
    commit tran w
set @wide=@wide-1
end
select * from ##result
/*
drop table ##chars
drop table ##result
*/