×

MSSQL中的多行数据合并到一行

小飞侠 小飞侠 发表于2020-11-22 15:48:04 浏览1655 评论0

抢沙发发表评论


SC表数据如下:

studentcourse
张三大学语文
李四大学语文
张三书法鉴赏
张三音乐欣赏
李四电影赏析

期望得到的结果如下:

studentcourse
张三大学语文,书法鉴赏,音乐欣赏
李四大学语文,电影赏析

有两种方式可以实现,一种是函数,一种是FOR XML PATH(SQL2005及以后支持)

创建SC表的代码如下:

IF OBJECT_ID(N'SC') IS NOT NULL

     BEGIN

           DROP TABLE SC

     END

ELSE

     BEGIN

           CREATE TABLE SC

           (

                 Student NVARCHAR(50),

                 Course NVARCHAR(50)

           )

           INSERT INTO SC

           SELECT N'张三',N'大学语文' UNION ALL

           SELECT N'李四',N'大学语文' UNION ALL

           SELECT N'张三',N'书法鉴赏' UNION ALL

           SELECT N'张三',N'音乐赏析' UNION ALL

           SELECT N'李四',N'电影赏析'          

     END

方法一:用户自定义函数

CREATE FUNCTION [dbo].[f_hebin](@sname varchar(50))
RETURNS varchar(8000)
AS
BEGIN
 DECLARE @course varchar(50)
 SELECT @course = ISNULL(@course+',','')+course
 FROM SC
 WHERE student=@sname
 RETURN @course
END

SELECT DISTINCT [Student]

     ,dbo.f_hebin([Student]) AS Course

FROM [dbo].[SC]

方法二:FOR XML PATH

SELECT distinct student,
STUFF(
(
SELECT ','+course
FROM SC
WHERE student=A.student
FOR XML PATH('')
),1,1,''
)as course

FROM SC AS A

用法说明: ①stuff: 1、作用 stuff(param1, startIndex, length, param2) 将param1中自startIndex(SQL中都是从1开始,而非0)起,删除length个字符,然后用param2替换删掉的字符。

2、参数 param1 一个字符数据表达式。param1可以是常量、变量,也可以是字符列或二进制数据列。 startIndex 一个整数值,指定删除和插入的开始位置。如果 startIndex或 length 为负,则返回空字符串。如果startIndex比param1长,则返回空字符串。startIndex可以是 bigint 类型。 length 一个整数,指定要删除的字符数。如果 length 比param1长,则最多删除到param1 中的最后一个字符。length 可以是 bigint 类型。

3、返回类型 如果param1是受支持的字符数据类型,则返回字符数据。如果param1是一个受支持的 binary 数据类型,则返回二进制数据。 4、备注 如果结果值大于返回类型支持的最大值,则产生错误。

select STUFF('abcdefg',1,0,'|zwxy|')       --结果为'|zwxy|abcdefg'
select STUFF('abcdefg',1,1,'|zwxy|')       --结果为'|zwxy|bcdefg'
select STUFF('abcdefg',2,1,'|zwxy|')       --结果为'a|zwxy|cdefg'
select STUFF('abcdefg',2,2,'|zwxy|')       --结果为'a|zwxy|defg'

以上是stuff的用法 ②for xml path: for xml path有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作。那么以一个实例为主. 我们还是通过列子引入: 还是以SC表为例子

SELECT student,course from sc for xml path

结果如下:

<row>
 <student>张三</student>
 <course>大学语文</course>
</row>
<row>
 <student>李四</student>
 <course>大学语文</course>
</row>
<row>
 <student>张三</student>
 <course>书法鉴赏</course>
</row>
<row>
 <student>张三</student>
 <course>音乐赏析</course>
</row>
<row>
 <student>李四</student>
 <course>电影赏析</course>
</row>

由此可以看出 FOR XML PATH 可以将查询结果根据行输出成XML各式!而且我们还可以改变XML行节点的名称,代码如下:

SELECT student,course from sc for xml path('课程名称')

看显示结果,原来的行节点<row>变成了我们在PATH后面括号()中自定义的名称<课程名称>

<课程名称>
 <student>张三</student>
 <course>大学语文</course>
</课程名称>
<课程名称>
 <student>李四</student>
 <course>大学语文</course>
</课程名称>
<课程名称>
 <student>张三</student>
 <course>书法鉴赏</course>
</课程名称>
<课程名称>
 <student>张三</student>
 <course>音乐赏析</course>
</课程名称>
<课程名称>
 <student>李四</student>
 <course>电影赏析</course>
</课程名称>

其实我们还可以改变列节点,还记的给列起别名的关键字AS吗?就是用它!代码如下:

SELECT student as 学生,course as 课程 from sc for xml path('课程名称')

显示结果:

<课程名称>
 <学生>张三</学生>
 <课程>大学语文</课程>
</课程名称>
<课程名称>
 <学生>李四</学生>
 <课程>大学语文</课程>
</课程名称>
<课程名称>
 <学生>张三</学生>
 <课程>书法鉴赏</课程>
</课程名称>
<课程名称>
 <学生>张三</学生>
 <课程>音乐赏析</课程>
</课程名称>
<课程名称>
 <学生>李四</学生>
 <课程>电影赏析</课程>
</课程名称>

我们还可以构建我们喜欢的输出方式,看代码

SELECT '['+student +':'+course+'],'  from sc for xml path('')

显示结果

[张三:大学语文],[李四:大学语文],[张三:书法鉴赏],[张三:音乐赏析],[李四:电影赏析],


欢迎评论

访客