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

原文: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 [email protected]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;

原文地址:https://www.cnblogs.com/lonelyxmas/p/9411430.html

时间: 2024-10-07 05:16:12

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

SQL Server如何用触发器捕获DML操作的会话信息

原文:SQL Server如何用触发器捕获DML操作的会话信息 需求背景 上周遇到了这样一个需求,维护人员发现一个表的数据经常被修改,由于历史原因:文档缺少:以及维护人员的经常变更,导致他们对系统也业务也不完全熟悉,他们也不完全清楚哪些系统和应用程序会对这个表的数据进行操作.现在他们想找出有哪些服务器,哪些应用程序会对这个表进行INSERT.UPDATE操作.那么问题来了,怎么去解决这个问题呢? 解决方案 由于数据库版本是标准版,我们选择了使用触发器来捕获进行DML操作的会话的相关信息,例如,H

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

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

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

为了缩小读取操作所涉及范围,本文首先着眼于简单的SELECT查询,然后引入执行更新操作有关的附加过程.最后你会读到,优化性能时SQLServer使用还原工具的相关术语和流程. 关系和存储引擎 如图所示,SQL Server被分为2个主要引擎:关系引擎和存储引擎.关系引擎有时也被称为查询处理器,因为它的主要功能是查询优化和执行.它包含检查查询语法和准备查询树的命令解析器:查询优化器毫无疑问是任何数据库系统中皇冠上的宝石:查询执行器对执行(查询计划)负责. 存储引擎对所有数据输入.输出管理负责.它包

SQL Server快速生成SQL增删改查语句

你还在手敲代码生成SQL语句吗?你还在为因为马虎出错的SQL语句而感到无语吗?你还在为不知怎样表达复杂的SQL语句而纠结吗?如果你的回答为"是",那你就OUT啦,快来试试应用SQL Server资源管理器快速生成SQL语句吧. 首先,打开SQL Server2008,在菜单栏"查询"下拉菜单中找到"在编辑器中设计查询",如下图: 在打开的查询设计器窗口中添加要进行操作的数据库表. 在添加的表内下方空白部分右键单击鼠标,在弹出菜单中单击"

SQL Server -&gt;&gt; 深入探讨SQL Server 2016新特性之 --- Temporal Table(历史表)

原文:SQL Server ->> 深入探讨SQL Server 2016新特性之 --- Temporal Table(历史表) 作为SQL Server 2016(CTP3.x)的另一个新特性,Temporal Table(历史表)记录了表历史上任何时间点所有的数据改动.Temporal Table其实早在ANSI SQL 2011就提出了,而SAP HANA, DB2和Oracle早已在它们的产品中加入/实现了这一特性.所以说微软其实是落后了几个竞争对手.既然在CTP3.0中加入了,相信

SQL SERVER – Beginning of SQL Server Architecture – Terminology – Guest Post

AUGUST 30, 2012 BY PINAL DAVE SQL SERVER – Beginning of SQL Server Architecture – Terminology – Guest Post SQL Server Architecture is a very deep subject. Covering it in a single post is an almost impossible task. However, this subject is very popula

sql server 2012 打开sql server configuration manager 报错

Error message when you open SQL Server Configuration Manager in SQL Server: "Cannot connect to WMI provider. You do not have permission or the server is unreachable" Workaround解决办法 To work around this problem, open a command prompt, type the fol

22. SQL -- SQL Server 2005 和SQL Server 2008新特性

SQL SERVER 2005 与SQL SERVER 2008 新特性   SQLSERVER 2005 新特性 Enhanced Data Types:存储最大8K-2G Partitioned Table(分区表):数据拆分管理 背景:一个公司,有目前现存数据以及历史数据,各在一台SER 上,服务器访问方式: SQL 2000 TABLE 1:在一张table 中,对数据进行分区 Enhanced Indexing Features SER 1 SER 2 现存数据 TABLE 1 TAB

SQL Server里面导出SQL脚本(表数据的insert语句)

转载自:http://hi.baidu.com/pigarmy/blog/item/109894c445eab0a28326ac5a.html 最近需要导出一个表的数据并生成insert语句,发现SQL Server的自带工具并米有此功能.BAIDU一下得到如下方法(亲测OK) 用这个存储过程可以实现: CREATE PROCEDURE dbo.UspOutputData @tablename sysname AS declare @column varchar(1000) declare @c