SQL Server如何用SQL实现一批字符串的全部组合

在SQL Server中,如何用SQL去实现得到一批字符串的全部组合呢?这个是同事在实际需求当中遇到的一个问题,他的具体需求如下所示:

 

传入参数格式为'1,2,3,224,15,6'   'A,BC,GHT,TTY,B,E'

 

输出的内容为分割后字符串的所有非排列组合

!-阶乘,如!=5××××=120  (M!/(N!*((M-N)!)))  

 

公式描述:组合数公式是从m个不同元素中,任取n(n≤m)个元素并成一组,叫做从m个不同元素中取出n个元素的一个组合;

从m个不同元素中取出n(n≤m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数。用符号c(m,n) 表示。

如果有5个数字那么就是M=5  单个数字组合N=1   (M!/(N!*((M-N)!)))=5   

                    是M=5  2个数字组合N=2    (M!/(N!*((M-N)!)))=10

                    是M=5  3个数字组合N=3    (M!/(N!*((M-N)!)))=10

                    是M=5  4个数字组合N=4    (M!/(N!*((M-N)!)))=5

                    是M=5  5个数字组合N=5    (M!/(N!*((M-N)!)))=1   

可能全部的组合有 10 + 10 + 5+ 5 + 1 =31 种。传入的参数分割后越多,组合数也就越庞大。

 

             

他最开始的实现方式就是用多层循环实现(此处就不贴代码了),但是当要实现组合的字符串数量增多时,效率性能就下降得非常厉害,后面我参考一种写法写了下面SQL语句。

--创建辅助表SEQ_NUMBER
CREATE TABLE SEQ_NUMBER(COL_NUM INT);
DECLARE @Index INT =1;
 
WHILE @Index <=32
BEGIN
    INSERT INTO SEQ_NUMBER VALUES(@Index);
 
    SET @Index +=1;
END;
GO
 
 
--创建辅助表,用于保存拆分后的字符串
CREATE TABLE SplitString(COL_NUM INT IDENTITY(1,1) ,VAL  VARCHAR(32));
 
 
--创建函数
CREATE FUNCTION FN_GET_COMBINATIONS()
RETURNS @OutTable TABLE(COL VARCHAR(32), VAL  VARCHAR(32))
AS
BEGIN
    DECLARE @Str  VARCHAR(32)='';
    DECLARE @Index INT =1;
    DECLARE @RowCount INT;
 
    SELECT @RowCount=COUNT(*) FROM SplitString;
 
    
    --注意,如果字符串分隔后有5个字符串(A,BC,GHT,TTY,B,E),就使用12345, 如果分割后有6个字符串,就必须用123456,以此类推
    WHILE @Index <= @RowCount
        BEGIN
 
            SET @Str = @Str + CAST(@Index AS VARCHAR(2))
            SET @Index = @Index +1
        END
 
    INSERT INTO @OutTable
    SELECT   S.COL_NUM, T.VAL FROM SEQ_NUMBER S , SplitString T
    WHERE S.COL_NUM = T.COL_NUM ORDER BY T.COL_NUM;
 
    WHILE NOT EXISTS(SELECT 1 FROM @OutTable where COL = @Str)
    INSERT INTO @OutTable
    SELECT T3.COL + T2.COL, T3.VAL + T2.VAL FROM @OutTable AS T2,@OutTable AS T3 WHERE len(t3.col) = 1 and charindex(T3.COL,T2.COL) =0 and T2.COL > T3.COL
 
    RETURN;
END

 

然后假如,我们需要实现字符串'1,2,3,4,5'中1,2,3,4,5的所有组合方式,那么我们用下面SQL就能得到结果。如下所示,当然你也可以用诸如'A,BC,GHT,TTY,B,E'这样的字符串去获取字符串的所有组合。

 

DECLARE @String VARCHAR(200)
DECLARE @SqlText VARCHAR(MAX)
DECLARE @Index INT=1;
 
SET @String='A,BC,GHT,TTY,B';
SET @SqlText='SELECT COL='''+ REPLACE(@STRING,',',''' UNION ALL SELECT ''')+''''
 
 
--清空旧数据,保存需要进行组合的字符串数据。
TRUNCATE TABLE SplitString;
 
 
INSERT INTO SplitString
EXEC (@SqlText)
 
 
 
 
SELECT DISTINCT
        CHAR_VAL ,
        COL_NUM ,LEN(COL_NUM) AS STR_CNT 
FROM    dbo.FN_GET_COMBINATIONS()
WHERE   LEN(COL_NUM) >= 1
ORDER BY LEN(COL_NUM) ,COL_NUM;

 

后面测试发现,当组合的字符串数量超过或等于10个时,这个函数就有问题了(有兴趣的可以自行测试,例如传入的参数为’1,2,3,4,5,6,7,8,9,10’)。所以又对这个进行了一番修改。目前最多支持获取26个字符串的全部组合,这个已经完全满足业务需要了。如果再需要跟多的字符串组合,则还需修改函数。这个函数效率也是与需要组合的字符串个数有相关,如果组合11个字符串,基本上需要3~4秒的时间,如果组合的字符串个数越多,则所需时间越多。当然,如果组合的字符串个数7~8个,几乎就是1秒内。

 

CREATE TABLE SEQ_CHARACTER(COL_NUM INT ,COL_CHAR VARCHAR(36));
 
INSERT INTO SEQ_CHARACTER
SELECT 1 ,'A' UNION ALL
SELECT 2 ,'B' UNION ALL
SELECT 3 ,'C' UNION ALL
SELECT 4 ,'D' UNION ALL
SELECT 5 ,'E' UNION ALL
SELECT 6 ,'F' UNION ALL
SELECT 7 ,'G' UNION ALL
SELECT 8 ,'H' UNION ALL
SELECT 9 ,'I' UNION ALL
SELECT 10,'J' UNION ALL
SELECT 11,'K' UNION ALL
SELECT 12,'L' UNION ALL
SELECT 13,'M' UNION ALL
SELECT 14,'N' UNION ALL
SELECT 15,'O' UNION ALL
SELECT 16,'P' UNION ALL
SELECT 17,'Q' UNION ALL
SELECT 18,'R' UNION ALL
SELECT 19,'S' UNION ALL
SELECT 20,'T' UNION ALL
SELECT 21,'U' UNION ALL
SELECT 22,'V' UNION ALL
SELECT 23,'W' UNION ALL
SELECT 24,'X' UNION ALL
SELECT 25,'Y' UNION ALL
SELECT 26,'Z'
 
 
CREATE TABLE SplitString(COL_NUM INT IDENTITY(1,1) ,VAL  VARCHAR(32));
 
 
 
CREATE FUNCTION FN_GET_COMBINATIONS()
RETURNS @OutTable TABLE(COL_NUM VARCHAR(32), CHAR_VAL  VARCHAR(32))
AS
BEGIN
    DECLARE @Str  VARCHAR(32)='';
    DECLARE @Index INT =1;
    DECLARE @RowCount INT;
 
    SELECT @RowCount=COUNT(*) FROM SplitString;
 
    
    --注意,如果字符串分隔后有5个字符串(A,BC,GHT,TTY,B,E),就使用12345, 如果分割后有6个字符串,就必须用123456,以此类推
    WHILE @Index <= @RowCount
        BEGIN
 
            SELECT  @Str = @Str + LTRIM(RTRIM(COL_CHAR)) FROM SEQ_CHARACTER WHERE COL_NUM=@Index
            SET @Index = @Index +1
        END
 
    INSERT INTO @OutTable
    SELECT   S.COL_CHAR, T.VAL FROM SEQ_CHARACTER S , SplitString T
    WHERE S.COL_NUM = T.COL_NUM ORDER BY T.COL_NUM;
 
    WHILE NOT EXISTS(SELECT 1 FROM @OutTable where COL_NUM = @Str)
    INSERT INTO @OutTable
    SELECT T3.COL_NUM + T2.COL_NUM, T3.CHAR_VAL + T2.CHAR_VAL FROM @OutTable AS T2,@OutTable AS T3 WHERE len(T3.COL_NUM) = 1 and charindex(T3.COL_NUM,T2.COL_NUM) =0 and T2.COL_NUM > T3.COL_NUM
 
    RETURN;
END

 

测试脚本如下:

 

DECLARE @String VARCHAR(200)
DECLARE @SqlText VARCHAR(MAX)
DECLARE @Index INT=1;
 
SET @String='A,B,C,D,E,F,G,H,G,H,I';
SET @SqlText='SELECT COL='''+ REPLACE(@STRING,',',''' UNION ALL SELECT ''')+''''
 
 
--清空旧数据,保存需要进行组合的字符串数据。
TRUNCATE TABLE SplitString;
 
 
INSERT INTO SplitString
EXEC (@SqlText)
 
 
 
 
SELECT DISTINCT
        CHAR_VAL ,
        COL_NUM ,LEN(COL_NUM) AS STR_CNT 
FROM    dbo.FN_GET_COMBINATIONS()
WHERE   LEN(COL_NUM) >= 1
ORDER BY LEN(COL_NUM) ,COL_NUM;
时间: 2024-11-10 01:34:01

SQL Server如何用SQL实现一批字符串的全部组合的相关文章

[SQL Server]管理常用SQL语句

server|语句 [SQL Server]管理常用SQL语句 1. 查看数据库的版本        select @@version 2. 查看数据库所在机器操作系统参数        exec master..xp_msver 3. 查看数据库启动的参数         sp_configure 4. 查看数据库启动时间         select convert(varchar(30),login_time,120) from master..sysprocesses where spi

SQL Server执行动态SQL正确方式

SQL Server执行动态SQL的话,应该如何实现呢?下面就为您介绍SQL Server执行动态SQL两种正确方式,希望可以让您对SQL Server执行动态SQL有更深的了解. 动态SQL:code that is executed dynamically.它一般是根据用户输入或外部条件动态组合的SQL语句块.动态SQL能灵活的发挥SQL强大的功能.方便的解决一些其它方法难以解决的问题.相信使用过动态SQL的人都能体会到它带来的便利,然而动态SQL有时候在执行性能(效率)上面不如静态SQL,

SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第2部分)

原文:SQL Server 2012:SQL Server体系结构--一个查询的生命周期(第2部分) 计划缓存(Plan Cache) 如果SQL Server已经找到一个好的方式去执行一段代码时,应该把它作为随后的请求重用,因为生成执行计划是耗费时间且资源密集的,这样做是有有意义的. 如果没找到被缓存的计划,然后命令分析器(Command Parser)在T-SQL基础上生成一个查询树(query tree).查询树(query tree)的内部结构是通过树上的每个结点代表查询中需要的执行操作

分享一下SQL Server执行动态SQL的正确方式

SQL Server执行动态SQL的话,应该如何实现呢?下面就为您介绍SQL Server执行动态SQL两种正确方式,希望可以让您对SQL Server执行动态SQL有更深的了解 动态SQL:code that is executed dynamically.它一般是根据用户输入或外部条件动态组合的SQL语句块.动态SQL能灵活的发挥SQL强大的功能.方便的解决一些其它方法难以解决的问题.相信使用过动态SQL的人都能体会到它带来的便利,然而动态SQL有时候在执行性能(效率)上面不如静态SQL,而

关于SQL Server 2000和SQL Server 2005分布式事务能否协同工作的测试

server|分布式 关于SQL Server 2000和SQL Server 2005分布式事务能否协同工作的测试 MS DTC Report 1.      MS DTC 背景 2.      MSDTC 测试目的 3.      MSDTC 测试环境 3.1            本次验证测试环境: 3.2            环境配置 3.3            验证MSDTC 3.4            创建验证用表 4.      Linked Server测试 5.     

怎么让sql server中的sql语句自动换行

怎么让sql server中的sql语句自动换行呢? 如下图: 工具--选项--所有语言 查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/database/SQLServer/

你应该升级到SQL Server 2005还是SQL Server 2008?

虽然SQL Server2005已经推出了约3年了,奇怪的是,很多公司仍然没有将SQL Server2000升级.现在这些公司面临着再次作出决定--是跳过升级到SQL Server 2005 还是直接到SQL Server 2008?要作出这个选择并不简单,本文主要讨论有关这一问题必须要考虑的事情. 升级到SQL Server 2005 没有太大的意义,SQL Server 2005是SQL Server的一个版本,在此之后只有一格版本推出.在其他的版本中,你减少了服务器的支持窗口.如果升级到S

Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程

原文:Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程 Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程 Red Gate系列文章: Red Gate系列之一 SQL Compare 10.2.0.1337 Edition 数据库比较工具 完全破解+使用教程 Red Gate系列之二

sql点滴38—SQL Server 2008和SQL Server 2008 R2导出数据的选项略有不同

原文:sql点滴38-SQL Server 2008和SQL Server 2008 R2导出数据的选项略有不同 说明:       以前要将一个表中的数据导出为脚本,只有用存储过程.现在在SQL Server 2008中增加了一个新特性,除了导出表的定义外,还支持将表中的数据导出为脚本. 步骤:     右击需要导出数据的数据库,在弹出式菜单中选择"任务"下的"生成脚本"选项      在第二步选择"高级选项"如果不是2008(R2)的选择 &