SQLServer实现split分割字符串到列

网上已有人实现sqlserver的split函数可将字符串分割成行,但是我们习惯了split返回数组或者列表,因此这里对其做一些改动,最终实现也许不尽如意,但是也能解决一些问题。

先贴上某大牛写的split函数(来自:Split function in SQL Server to break Comma separated strings,注意我这里将其命名为splitl):

1ALTER FUNCTION dbo.splitl ( 2 @String VARCHAR(MAX), 3 @Delimiter VARCHAR(MAX) 4) RETURNS @temptable TABLE (items VARCHAR(MAX)) AS 5BEGIN 6 DECLARE @idx INT=1 7 DECLARE @slice VARCHAR(MAX) 8 IF LEN(@String) < 1 OR LEN(ISNULL(@String,'')) = 0 9 RETURN 10 WHILE @idx != 0 11 BEGIN 12 SET @idx = CHARINDEX(@Delimiter,@String) 13 IF @idx != 0 14 SET @slice = LEFT(@String,@idx - 1) 15 ELSE 16 SET @slice = @String 17 IF LEN(@slice) > 0 18 INSERT INTO @temptable(items) VALUES(@slice) 19 SET @String = RIGHT (@String, LEN(@String) - @idx) 20 IF LEN(@String) = 0 21 BREAK 22 END 23 RETURN 24END

其原理还是比较简单的,一看便知。调用该函数返回的结果是:

SELECT * FROM dbo.splitl('a#b#c#d','#')

然而我希望得到的结果是:

SELECT 'a' a,'b' b,'c' c,'d' d

这就要用到sqlserver行转列的技巧,网上有很多方法可以参照。下面真正的split“过程”来了:

1ALTER PROC [dbo].[split] @strs VARCHAR(MAX),@delimiter VARCHAR(MAX) AS 2SELECT items,id=IDENTITY(INT,1,1) INTO #ccc FROM dbo.splitl(@strs,@delimiter) 3DECLARE @str VARCHAR(MAX)='',@SQL VARCHAR(MAX)=''  4SELECT @str = @str + ',' + '[' + CONVERT(VARCHAR(MAX),id) + ']' FROM #ccc 5SET @SQL = 'SELECT * FROM #ccc PIVOT(MAX(items) FOR id IN(' + SUBSTRING(@str,2,LEN(@str)) + ')) b' 6EXEC (@SQL) 7DROP TABLE #ccc

该过程中使用了pivot语法,参见:使用 PIVOT 和 UNPIVOT

注意这个过程调用了splitl函数,是在其基础上开发的。我们再来看看执行结果:

EXEC dbo.split 'a#b#c#d','#'

发现与上面期望的效果完全一致了!

但是这只是针对一行数据做split,如果是查询结果有多行都要分割怎么办呢?

我没有找到办法,因为sqlserver查询语句中不能嵌套过程,只能调用函数,而函数返回的结果集不能是多行。

but..世上无难事,只要写过程:

1-- 删除结果表 2IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id=object_id(N'test_result') AND OBJECTPROPERTY(id, N'IsUserTable')=1) 3 DROP TABLE test_result 4 5-- 建立数据表 6CREATE TABLE #tmp ( 7 id INT NOT NULL IDENTITY(0,1), 8 str VARCHAR(MAX) 9) 10INSERT INTO #tmp SELECT 'a#b#c#d' UNION SELECT 'f#g#h' 11 12-- 生成结果表 13DECLARE @maxc INT=(SELECT MAX(LEN(str)-LEN(REPLACE(str,'#','')))+1 FROM #tmp) 14DECLARE @sql0 VARCHAR(MAX)='CREATE TABLE test_result (' 15DECLARE @x INT=0 16WHILE @x<@maxc BEGIN 17 SET @sql0 = @sql0 + 'a' + CONVERT(VARCHAR(MAX),@x) + ' VARCHAR(MAX),' 18 SET @x=@x+1 19END 20SET @sql0 = SUBSTRING(@sql0,0,LEN(@sql0)) + ')' 21EXEC (@sql0) 22 23-- 遍历数据表 24DECLARE @i INT=0 25WHILE @i<(SELECT COUNT(1) FROM #tmp) BEGIN 26 DECLARE @strs VARCHAR(MAX)=(SELECT str FROM #tmp WHERE id=@i) 27 DECLARE @cols INT=(SELECT LEN(@strs)-LEN(REPLACE(@strs,'#','')))+1 28 DECLARE @y INT=0 29 DECLARE @sql1 VARCHAR(MAX)='INSERT INTO test_result(' 30 WHILE @y<@cols BEGIN 31 SET @sql1 = @sql1 + 'a' + CONVERT(VARCHAR(MAX),@y) + ',' 32 SET @y=@y+1 33 END 34-- -- 分割字符串 35 SET @sql1 = SUBSTRING(@sql1,0,LEN(@sql1)) + ') EXEC split "' + @strs + '","#"' 36 EXEC (@sql1) 37 SET @i=@i+1 38END 39 40SELECT * FROM test_result

暂时就到此为止八~sqlserver毕竟不够完美,这样的函数系统提供能够最好,自己实现的话遇到太多瓶颈,比如函数不支持动态语句,不能将查询结果传入过程等等。

至于实际应用,将上面这个栗子建立临时数据表的部分替换成要查询的真实表列即可,最后结果如下所示:

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

python中的split()函数的用法

函数:split()Python中有split()和os.path.split()两个函数,具体作用如下:split():拆分字符串。通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list)os.path.split():按照路径将文件名和路径分割开一、函数说明1、split()函数语法:str.split(str