【SQL】 借助游标来实现文本的分列与合并
有时我们会遇到需要把表中个别字段拆分成多条数据或是把多条数据合并到一起的情况。一般的编程语言都有函数“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】 借助游标来实现文本的分列与合并的更多相关文章
- SQL Server游标 C# DataTable.Select() 筛选数据 什么是SQL游标? SQL Server数据类型转换方法 LinQ是什么? SQL Server 分页方法汇总
SQL Server游标 转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html. 什么是游标 结果集,结果集就是select查询之后返回的所 ...
- SQL Server 游标运用:鼠标轨迹字符串分割
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 游标模板(Cursor Template) 鼠标轨迹字符串分割SQL脚本实现(SQL Code ...
- sql server 游标的简单用法
sql server游标: --定义游标 declare cursor1 cursor for select ID,Name from A --打开游标 open cursor1 declare @i ...
- Oracle_PL/SQL(3) 游标
引言:PLSQL数据类型标量数据类型:数字类.字符类.日期类.布尔类(boolean).复合数据类型:记录(%rowtype).表.数组引用类型:REF CURSORLOB类型:BLOB.CLOB 1 ...
- MySQL通过视图(或临时表)实现动态SQL(游标)
>参考de优秀文章 写MySQL存储过程实现动态执行SQL Dynamic cursor in stored procedure MySQL通过视图(或临时表)实现动态SQL(游标). 因在实现 ...
- (2.14)Mysql之SQL基础——游标
(2.14)Mysql之SQL基础——游标 关键词:Mysql游标 -- (1)定义游标 declare cur_name cursor for select * from table_name wh ...
- PL/SQL 美化器不能解析文本
1.问题:PL/SQL美化器不能解析文本 原始sql语句如下: CREATE OR REPLACE VIEW V_GGXZBM AS SELECT XZBM,XZMC,CASE WHEN PARENT ...
- Oracle学习2 视图 索引 sql编程 游标 存储过程 存储函数 触发器
---视图 ---视图的概念:视图就是提供一个查询的窗口,来操作数据库中的数据,不存储数据,数据在表中. ---一个由查询语句定义的虚拟表. ---查询语句创建表 create table emp a ...
- SQL Server 游标的应用
----------------SQL游标应用----------------- 今天由于业务需求,需要在存储过程中实现有一个表的主键去匹配在另一个表中作为外键所对应的数值 ,若在C#中则非常简单只需 ...
随机推荐
- spring security 学习
1.默认登录 user /df1fc617-bb94-494e-8adb-0234046bf092 取消校验 在启动类上添加下面的注解 @EnableAutoConfiguration(excl ...
- RAID配置多阵列
感谢: https://www.cnblogs.com/hystj/articles/8672029.html
- DD常用命令组合
管理一个系统经常需要备份磁盘数据,那么在UNIX/Linux系统中如何备份整个分区或整个硬盘的数据呢? dd命令就可以很方便实现这个功能. 1.把一个分区复制到一个文件中 dd if=/dev/sda ...
- C语法简单测试
1.未初始化的枚举变量 /* uninitialized-enum.c */ #include <stdio.h> , black, blue}; int main(void) { enu ...
- clusterware启动顺序——OHASD
Clusterware启动顺序 [root@ebsdb1 etc]# crsctl check crs CRS-4638: Oracle High Availability Services is ...
- web语言发展史
引用自CSDN,地址:https://blog.csdn.net/moshenglv/article/details/51590830 提到Web,不得不提一个词就是“互联网”.Web是World W ...
- mongo中的游标与数据一致性的取舍
除了特殊注释外,本文的测试结果均基于 spring-data-mongodb:1.10.6.RELEASE(spring-boot-starter:1.5.6.RELEASE),MongoDB 3.0 ...
- require的特点
通过把要加载的文件看作一个“功能”而不是一个文件,require对于用Ruby编写的扩展和用C语言编写的扩展都用一样的方式.另外,.rb扩展名的文件与其它扩展名为.so..dll或.bundle的文件 ...
- Promise学习使用
Promise是承诺的意思,“承诺可以获取异步操作的消息”,是一种异步执行的方案,Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持. Promise 对象有三种状态:pending ...
- GIT和SVN版本控制
Git 与SVN SVN 是集中式版本控制系统: 先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了, ...