有时我们会遇到需要把表中个别字段拆分成多条数据或是把多条数据合并到一起的情况。一般的编程语言都有函数“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. 展示金额的方法(1元-->1.00元)

    public static String showMoneyByTwoDecimal(String account) { DecimalFormat doubleFormatter = new Dec ...

  2. 解决tomcat内存溢出,java.lang.OutOfMemoryError: PermGen space

    一.通过eclipse启动tomcat. 1.选择window>>preferences 2.搜索tomcat,找到自己安装的tomcat版本对应的JDK,在Optional Java V ...

  3. 区间dp之四边形不等式优化详解及证明

    看了那么久的四边形不等式优化的原理,今天终于要写一篇关于它的证明了. 在平时的做题中,我们会遇到这样的区间dp问题 它的状态转移方程形式一般为dp[i][j]=min(dp[i][k]+dp[k+1] ...

  4. mysql远程访问1045的问题解决

    mysql远程访问1045的问题解决 首先进入mysql数据库,然后输入下面两个命令 grant all privileges on *.* to 'root'@'%' identified by ' ...

  5. 2019-04-25-day040-数据库的查询

    内容回顾 数据的增删改查 插入数据 insert into 表 values (值1,值2...) insert into 表(指定字段名1,字段名2) values (值1,值2...) 删除数据 ...

  6. VUE处理 组件赋值 watch 监听不到赋值问题

    开发中,遇到了一个BUG,做的页面类似于 导航切换效果.两个组件传值. 上方导航组件   (主动) 左侧导航组件   (被动) 点击上方导航,左侧导航实现变换对应的栏目. 实现过程中,遇到了点问题.左 ...

  7. 剑指Offer 60. 把二叉树打印成多行 (二叉树)

    题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 题目地址 https://www.nowcoder.com/practice/445c44d982d04483b04a54f ...

  8. L2-007 家庭房产 (25 分)

    L2-007 家庭房产 (25 分)   给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数.人均房产面积及房产套数. 输入格式: 输入第一行给出一个正整数N(≤),随后N行,每行按下 ...

  9. OpenSSL生成RSA公私钥(java)

    生成私钥:genrsa -out rsa_private_key.pem 1024 生成公钥:rsa -in rsa_private_key.pem -out rsa_public_key.pem - ...

  10. gulp在项目中的基本使用

    在项目中用gulp做项目的代码的管理,用起来很方便.主要用到了下面一些功能 关于js的处理,包括合并.压缩.加hash. 关于css的处理,编辑scss,合并css,加hash,自动加入前缀 本地开发 ...