网上已有人实现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. ImageMagick使用小节

    ImageMagick是一个强大的开源图形处理软件,国内应该很少人用,至今仍在更新,放出全版本下载链接 http://ftp.icm.edu.pl/packages/ImageMagick/binar ...

  2. sqlserver compact sdf, sqlite 数据库 在net中相对路径设置方法 - 摘自网络

    You should use: Data Source=|DataDirectory|\MyDb.sdf |DataDirectory| points to the App_Data folder. ...

  3. light oj 1155 - Power Transmission【拆点网络流】

    1155 - Power Transmission   PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 ...

  4. 用lambda构建ORM查询语句

    本文介绍如何解析lambda表达式来获取一个满足条件的查询语句. 先看个截图  通过设置实体对象Article_Content的查询表达式,就可以获取对应的参数化SQL语句,使用起来很方便,减少了代码 ...

  5. 用HiveDB横向切分MySQL数据库

    HiveDB是一个用来横向切分mysql数据库的开源框架,构建一个高性能和可扩展的基于mysql的系统需要大量的系统设计经验和良好的代码的实现,一个比较好的策略是将你的数据横向切分在多个server上 ...

  6. CAS SSO对手机应用支持的一种思路

    原文地址: http://architecture3.riaos.com/?p=3095368 手机和桌面应用访问CAS,我们不能直接使用CAS提供的web api.不过CAS提供了一个插件,叫CAS ...

  7. asp.net C#母版页和内容页事件排版载入顺序生命周期

    asp.net C#母版页和内容页事件排版载入顺序生命周期 关于ASP页面Page_Load发生在事件之前而导致的问题已经喜闻乐见,对于问题的解释也非常全面.可是怎样解决这个问题则较少有人说明,我就再 ...

  8. 【03】尽可能使用const

    1.为什么搞出const关键字? const指定一个语义约束,指定一个对象不可修改.如果一个对象不可修改,就应该说出来. 2.const与指针 const可以修饰指向之物,也可以修改指针本身.STL中 ...

  9. jQuery 编辑div内容

    div显示如下 <div id="showResult"></div> div中添加的html,进行拼接 $("#showResult" ...

  10. C++ ComboBox基础

    关键点 实现过程 //添加 //添加字符串 m_cbo1.AddString("AAA"); m_cbo1.AddString("BBB"); m_cbo1.A ...