【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#中则非常简单只需 ...
随机推荐
- grep用法
正则表达式只是一种表示法,只要工具支持这种表示法, 那么该工具就可以处理正则表达式的字符串.vim.grep.awk .sed 都支持正则表达式,也正是因为由于它们支持正则,才显得它们强大:在以前上班 ...
- 七月在线爬虫班学习笔记(六)——scrapy爬虫整体示例
第六课主要内容: 爬豆瓣文本例程 douban 图片例程 douban_imgs 1.爬豆瓣文本例程 douban 目录结构 douban --douban --spiders --__init__. ...
- Timer 的学习
Timer 实例化多个对象就会启动多个线程 TimerTask 中 捕获异常为基类Exception,那么出现异常后就继续执行.及时报错 TimerTask中未捕获异常或者捕获异常与程序抛出异常不一致 ...
- 使用spring框架,用xml方式进行bean装配出现“The fully qualified name of the bean's class, except if it serves...”
使用spring框架,用xml方式进行bean装配出现“The fully qualified name of the bean's class, except if it serves...”. 原 ...
- 第一周CTF (合天CTF)
0X00 第一周 0x01 基础 50 . 下载下来发现是一个exe文件 ,尝试了一下没打开,然后把后缀名一个一个的试一试,改成txt用记事本打开,得到了一个“假冒的flag” *(别问我怎么知道的) ...
- pytest自动化5:pytest-html插件--生成html报告
前言:pytest-HTML是一个插件,pytest用于生成测试结果的HTML报告.兼容Python 2.7,3.6 pytest-html 1. pip 安装: pip install pytes ...
- 2016/12/21 dplの课练
1.将/etc/passwd第行的最后一段全部改成/bin/bash cat 1 |sed -n '1,$p' |egrep '.*:' -o |sed 's/$/\bin\/bash/' 2.将/e ...
- 在eclipse上集成安装阿里巴巴代码规约P3C插件
在eclipse上集成安装阿里巴巴代码规约P3C插件 参照网址: https://jingyan.baidu.com/article/2d5afd6923e78b85a3e28e5e.html 首先进 ...
- freeswitch配置功能二
<?xml version="1.0" encoding="utf-8"?><include> <context n ...
- python基础语法三
集合: 1.不同元素组成 2.无序 3.集合中的元素必须是不可变类型 s = {1, 2, 3 } #定义集合 s = set('hello') print(s) s.pop() #指定删除 s.r ...