有时我们会遇到需要把表中个别字段拆分成多条数据或是把多条数据合并到一起的情况。一般的编程语言都有函数“split”和“join”来实现,而SQL中既没有这些函数也没有类似数组和列表这类方便保存成组数据的数据类型,一些对于字符串的处理功能实现起来比较麻烦。直到SQL Server 2016才新增了string_split函数,专门用来拆分字符串但在此之前的版本,我们只能通过其他方式来实现这些功能。


一、文本分列的实现


现有测试数据表如下图,“学科”和“成绩”都是多条数据通过逗号连接的。如果想把他们拆分出多条数据,让每门学科和成绩都对应一条记录,自然需要把“学科”与“成绩”两列数据中按照逗号作为分隔符进行拆分。

  • 利用xml对字符串进行拆分

在网上搜索的比较简便和常用的方法是利用xml对字符串进行拆分,在此不再细说,代码如下:

 declare @x xml,@str nvarchar(200)
set @str='aaa,bbb,ccc'
SELECT @x = CONVERT(xml,
'<v>' + REPLACE(@str, ',', '</v><v>') + '</v>')
SELECT N.v.value('.', 'varchar(100)')
FROM @x.nodes('/v') N(v)
  • 利用游标配合函数substring来实现表中文本的分列

思路:通过建立游标逐条获取表内信息,并对此进行加工,使用函数substring分段读取“学科”和“成绩”,将结果插入到另外一个新建立的表“test_split”中。

实现方法:建立一个新表"test_split",通过建立游标逐条获取表“test”内信息,针对从游标中获取的每一条记录,进行如下的操作。因为“学科”与“成绩”都是通过逗号进行连接的一组数据,所以分别用函数charindex定位到“学科”与“成绩”中逗号第一次出现的位置,随后使用函数substring截取从开头(也就是索引号1的位置)到逗号第一次出现位置(通过charindex获取到的索引号减去1,因为我们不需要那个逗号)的部分,将获取到的新字符串作为新表“test_split”中的“学科”与“成绩”连同“姓名”一起插入到新表“test_split”中。再将原字符串从开头到第一个逗号的部分删除作为新的字符串循环重复前面的操作,直到字符串中没有逗号为止。这样我们就把原表“test”中原本的一条数据根据“学科”与“成绩”的内容拆分成了多条数据。

代码与实现效果如下:

 if exists(select name from sys.tables where name='test_split')
drop table test_split
CREATE TABLE test_split(姓名 nvarchar(50),学科 nvarchar(200),成绩 nvarchar(200))
go DECLARE MyCursor CURSOR
for select * FROM dbo.test
open MyCursor
DECLARE @姓名 nvarchar(50),@学科 nvarchar(200),@成绩 nvarchar(200),@学科Temp nvarchar(200),@成绩Temp nvarchar(200)
declare @getindex1 int,@getindex2 int
FETCH NEXT FROM MyCursor INTO @姓名,@学科,@成绩
WHILE @@FETCH_STATUS =0
BEGIN
set @getindex1=charindex(',',@学科)
set @getindex2=charindex(',',@成绩)
while(@getindex1<>0)
begin
set @学科Temp=substring(@学科,1,@getIndex1-1)
set @成绩Temp=substring(@成绩,1,@getIndex2-1)
insert into test_split values (@姓名,@学科Temp,@成绩Temp)
set @学科=stuff(@学科,1,@getindex1,'')
set @成绩=stuff(@成绩,1,@getindex2,'')
set @getindex1=charindex(',',@学科)
set @getindex2=charindex(',',@成绩)
end
insert into test_split values (@姓名,@学科,@成绩)
FETCH NEXT FROM MyCursor INTO @姓名,@学科,@成绩
END CLOSE MyCursor
DEALLOCATE MyCursor

原表“test"中的四条记录给拆分成了对应的9条记录。

二、文本合并的实现


与文本的分列对应的,可以采用同样的方法来实现文本的合并。下面我们来尝试将之前生成的表“test_split”重新合并成新表“test_join”,实现字段“学科”与“成绩”的合并。

思路:通过建立游标逐条获取表内信息,设置一个变量“@姓名Temp”,将每次获取到的数据中的“姓名”与该变量进行对比,相同的就将其中的“学科”与“成绩”进行合并。

实现方法:建立一个新表“test_join”,同时建立一个游标来读取"test_split"中的数据(表中数据需要按照“姓名”进行排序),将每次游标获取到的数据中的“姓名”与“@姓名Temp”对比,如果相同就把“学科”与“成绩”累加到变量“@学科”与“@成绩”中,并使用逗号分隔;如果不同,就将变量值插入到新建立的表“test_join”中,同时使用新获取到的“姓名”、“学科“、”成绩“更新变量”@姓名”、“@学科”、“@成绩”。

代码及实现效果如下:

 if exists(select name from sys.tables where name='test_join')
drop table test_join
CREATE TABLE test_join(姓名 nvarchar(50),学科 nvarchar(200),成绩 nvarchar(200));
go DECLARE MyCursor CURSOR
for select 姓名,学科,成绩 FROM dbo.test_split
open MyCursor
DECLARE @姓名 nvarchar(50),@学科 nvarchar(200),@成绩 nvarchar(200)
declare @姓名Temp nvarchar(50),@学科Temp nvarchar(200),@成绩Temp nvarchar(200)
set @姓名Temp = ''
FETCH NEXT FROM MyCursor INTO @姓名,@学科,@成绩 WHILE @@FETCH_STATUS =0
BEGIN
if @姓名 <> @姓名Temp
begin
insert into test_join values (@姓名Temp,@学科Temp,@成绩Temp)
set @姓名Temp=@姓名
set @学科Temp=@学科
set @成绩Temp=@成绩
end
else
begin
set @学科Temp=@学科Temp+','+@学科
set @成绩Temp=@成绩Temp+','+@成绩
end
FETCH NEXT FROM MyCursor INTO @姓名,@学科,@成绩
END insert into test_join values (@姓名Temp,@学科Temp,@成绩Temp) CLOSE MyCursor
DEALLOCATE MyCursor

从最终的运行结果可以看到,这里还存在一个小问题,就是因为一开始把变量“@姓名”初始化成空值,所以在新表"test_join"中会产生一条无用记录,但为了代码中循环体的条件判断,没有太好的消除办法。

【SQL】 借助游标来实现文本的分列与合并的更多相关文章

  1. SQL Server游标 C# DataTable.Select() 筛选数据 什么是SQL游标? SQL Server数据类型转换方法 LinQ是什么? SQL Server 分页方法汇总

    SQL Server游标   转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html. 什么是游标 结果集,结果集就是select查询之后返回的所 ...

  2. SQL Server 游标运用:鼠标轨迹字符串分割

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 游标模板(Cursor Template) 鼠标轨迹字符串分割SQL脚本实现(SQL Code ...

  3. sql server 游标的简单用法

    sql server游标: --定义游标 declare cursor1 cursor for select ID,Name from A --打开游标 open cursor1 declare @i ...

  4. Oracle_PL/SQL(3) 游标

    引言:PLSQL数据类型标量数据类型:数字类.字符类.日期类.布尔类(boolean).复合数据类型:记录(%rowtype).表.数组引用类型:REF CURSORLOB类型:BLOB.CLOB 1 ...

  5. MySQL通过视图(或临时表)实现动态SQL(游标)

    >参考de优秀文章 写MySQL存储过程实现动态执行SQL Dynamic cursor in stored procedure MySQL通过视图(或临时表)实现动态SQL(游标). 因在实现 ...

  6. (2.14)Mysql之SQL基础——游标

    (2.14)Mysql之SQL基础——游标 关键词:Mysql游标 -- (1)定义游标 declare cur_name cursor for select * from table_name wh ...

  7. PL/SQL 美化器不能解析文本

    1.问题:PL/SQL美化器不能解析文本 原始sql语句如下: CREATE OR REPLACE VIEW V_GGXZBM AS SELECT XZBM,XZMC,CASE WHEN PARENT ...

  8. Oracle学习2 视图 索引 sql编程 游标 存储过程 存储函数 触发器

    ---视图 ---视图的概念:视图就是提供一个查询的窗口,来操作数据库中的数据,不存储数据,数据在表中. ---一个由查询语句定义的虚拟表. ---查询语句创建表 create table emp a ...

  9. SQL Server 游标的应用

    ----------------SQL游标应用----------------- 今天由于业务需求,需要在存储过程中实现有一个表的主键去匹配在另一个表中作为外键所对应的数值 ,若在C#中则非常简单只需 ...

随机推荐

  1. python列表的学习笔记

    列表的操作 第一个例子: #names = "zhangyang guyun xiangpeng xuliangchen"  #通过空格或逗号存变量 names = [" ...

  2. jQuery dataTables 列不对齐的原因

    如果把 jQuery dataTables 用在初始化时为隐藏的区域中,会发现表头和内容的列是不对齐的. 解决方案: 如果是折叠的,可以加上: $('#myCollapsible').on('show ...

  3. Charles篡改请求,在手机上抓包,以及弱网设置

    篡改请求 可以测试各种异常 原理:clint->server正常是客户端发送请求到服务端,charles相当于一个拦截器,拦住客户端的请求,并进行修改,修改后再发送到server端 Server ...

  4. vim替换tab到4空格

    ~/.vimrc 中设置 # 设置tab宽度 set ts= #也可以用 set tabstop= #空格替换tab set expandtab 如果对于已保存的文件 :%retab! !用于修改所有 ...

  5. IP通信基础课堂笔记----第三章(自认为的重点)

    网络层协议IP IP数据包格式:固定部分        {  标识(16):计数器,源站每发送一个分组,标识+1:源IP地址的标识是全网唯一的. (包含TCP/UDP首部)  |  标志(3):当最低 ...

  6. Archlinux安装总结

    Archlinux安装总结 一.引导 1.BIOS与UEFI root@archiso ~ # ls /sys/firmware/efi/efivars ls: cannot access '/sys ...

  7. echarts绘制k线图为什么写candlestick类型就报错

    错误提示:echarts-en.common.js:11713 Uncaught Error: Component series.candlestick not exists. Load it fir ...

  8. svg的使用集合

    1.效果 https://www.zhangxinxu.com/wordpress/2017/03/offset-path-css-animation/ 2.用法 https://www.cnblog ...

  9. 【Python】随机数random模块randint、shuffle、random、sample、choice、uniform、

    1 ).random() 返回0<=n<1之间的随机实数n:2 ).choice(seq) 从序列seq中返回随机的元素:3 ).getrandbits(n) 以长整型形式返回n个随机位: ...

  10. 移动终端设备ID

    转自:https://wetest.qq.com/lab/view/116.html 一.前言 对于移动端产品的常规统计分析和运营推广,渠道结算来说,能精准的识别区分并且跟踪一台终端设备(一个终端用户 ...