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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

SQLServer实现split分割字符串到列的更多相关文章

  1. Replace是替代 Split分割字符串

    Replace是替代 Split分割字符串string[] ReadText = str.Replace("\r\n", "@").Split('@'); Sp ...

  2. C# Split的用法,Split分割字符串

    C# Split的用法,Split分割字符串 分割单个字串:string str="来自张三的亲切问候!;string[] strarry=str.Split(new string[] { ...

  3. C#的String.Split 分割字符串用法详解的代码

    代码期间,把代码过程经常用的内容做个珍藏,下边代码是关于C#的String.Split 分割字符串用法详解的代码,应该对码农们有些用途. 1) public string[] Split(params ...

  4. java关于split分割字符串,空的字符串不能得到的问题

    java关于split分割字符串,空的字符串不能得到的问题   class T { public static void main(String args[]) { String num[] = ne ...

  5. PLSQL Split分割字符串

    系统自带的split,使用起来方便,但是如果字符串太长,可能会出现异常,这里,我自己写了一个也是该名字,放在自己的包中,引用的时候带包名就好了. --系统自带的函数 /*CURSOR cur_temp ...

  6. String.split()分割字符串方法

    split方法的主要用处就是:分割字符串 split方法返回的是数组类型 主要由以下几种用法: 1.比如有一个字符串var str = "bcadeab";对str使用split方 ...

  7. C#中使用split分割字符串的几种方法小结

    1.用字符串分隔: using System.Text.RegularExpressions;string str="aaajsbbbjsccc";string[] sArray= ...

  8. C++ split分割字符串函数

    将字符串绑定到输入流istringstream,然后使用getline的第三个参数,自定义使用什么符号进行分割就可以了. #include <iostream> #include < ...

  9. SQL Server 分割字符串转列

    CREATE FUNCTION dbo.sf_DS_SplitNVarchar ( @strValues nvarchar(4000) ) RETURNS @tblStrList TABLE (id ...

随机推荐

  1. table显示json数据传递

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. 类加载器classCloader

    ref: http://blog.csdn.net/studyvcmfc/article/details/7720322 得复习一下深入java虚拟机 1.类加载器干啥的? 把 class文件加载到虚 ...

  3. vijosP1115 火星人

    vijosP1115 火星人 链接:https://vijos.org/p/1115 [思路] 排列组合. 题目要求为求第下m个排列. 这里有两种方法,首选的是调用algorithm中的next_pe ...

  4. 无法连接 mysql

    ==================================================================================================== ...

  5. POJ1423 - Big Number(Stirling公式)

    题目大意 求N!有多少位 题解 用公式直接秒杀... 代码: #include<iostream> #include<cmath> using namespace std; # ...

  6. linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例

    除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnblogs.com/Anker/p/3265058.html 最简单的select示例: #incl ...

  7. 问题.NETSystem.Data.OleDb.OleDbException 操作必须使用一个可更新的查询

    问题:System.Data.OleDb.OleDbException 操作必须使用一个可更新的查询 问题现象:用asp.net连access数据库,查询可以,插入数据报错.在.NET中F5可以使用方 ...

  8. Oracle- 用户管理

    Oracle一个数据库里可以分配多个用户,用户创建自己的表,自己创建的表如果不想分配给其他用户使用,其他用户是看不到自己的创建的表的. 用户管理: 创建用户: create user chunxiao ...

  9. UVA 557 - Burger(概率 递推)

     Burger  When Mr. and Mrs. Clinton's twin sons Ben and Bill had their tenth birthday, the party was ...

  10. Java正则表达式:Pattern类和Matcher类

    一.捕获组的概念 捕获组可以通过从左到右计算其开括号来编号,编号是从1 开始的.例如,在表达式 ((A)(B(C)))中,存在四个这样的组: 1     ((A)(B(C))) 2     (A) 3 ...