我的老师问一个找到所有组合的算法。我有一组数据,长度可以变化。所以组合应该是这样的:
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)
是问题所在。
答案 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
您必须意识到结果数量会随着最大长度的增加而增加指数,因此随着最大长度的增加,性能会迅速恶化。
答案 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
*/