SQL——用FOR XML Path完成字符串的聚合

CREATE TABLE #Temp(GroupName VARCHAR(100),FuncationName VARCHAR(100))
GO
INSERT INTO #Temp VALUES('Administrator','View')
INSERT INTO #Temp VALUES('Administrator','Add')
INSERT INTO #Temp VALUES('Administrator','Delete')
INSERT INTO #Temp VALUES('Administrator','Edit')
INSERT INTO #Temp VALUES('Guest','View')
INSERT INTO #Temp VALUES('Guest','Add')
INSERT INTO #Temp VALUES('GG','View')
INSERT INTO #Temp VALUES('Test',NULL)

SELECT FuncationName+',' FROM #Temp FOR XML PATH('')
-- View,Add,Delete,Edit,View,Add,View,
SELECT isnull(FuncationName,'')+',' FROM #Temp FOR XML PATH('')
-- View,Add,Delete,Edit,View,Add,View,,

SELECT FuncationName+',' FROM #Temp WHERE GroupName='Administrator' FOR XML PATH('')
-- View,Add,Delete,Edit,

SELECT GroupName,
	( SELECT FuncationName+',' FROM #Temp AS TA WHERE TA.GroupName=TB.GroupName FOR XML PATH('') ) 
FROM #Temp TB 
GROUP BY GroupName
--Administrator	View,Add,Delete,Edit,
--GG	View,
--Guest	View,Add,
--Test	

--注:这一步操作一定要用 case 判断, 因为在null值的情况下left函数会出错。
SELECT t.GroupName,CASE LEN(t.FunList) WHEN 0 THEN '' ELSE LEFT(t.FunList,len(t.FunList)-1) END FROM (
	SELECT GroupName,
		( SELECT FuncationName+',' FROM #Temp AS TA WHERE TA.GroupName=TB.GroupName FOR XML PATH('') ) AS FunList 
	FROM #Temp TB 
	GROUP BY GroupName
) AS T
--Administrator	View,Add,Delete,Edit
--GG	View
--Guest	View,Add
--Test	

--注:这一步,逗号必须放在最前面,stuff函数只有放在最前面才能准确判断
--此外,与上面不同的是,它会自动过滤掉NULL值的情况,不作处理
Select TB.GroupName,
     stuff((select ','+[FuncationName] from #Temp AS TA WHERE TA.GroupName=TB.GroupName for xml path('')),1,1,'') AS FunList
from #Temp TB
GROUP BY TB.GroupName
--Administrator    View,Add,Delete,Edit
--GG    View
--Guest    View,Add
--Test    NULL


下面是转载别人的。

——————————————————————————————————————————————

在SQL Server中利用 FOR XML PATH 语句能够把查询的数据生成XML数据,下面是它的一些应用示例。

?
1
2
3
4
5
DECLARE @TempTable table (UserID int , UserName nvarchar(50));
insert into @TempTable (UserID,UserName) values (1, 'a' )
insert into @TempTable (UserID,UserName) values (2, 'b' )
  
select UserID,UserName from @TempTable FOR XML PATH
运行这段脚本,将生成如下结果:
?
1
2
3
4
5
6
7
8
< row >
   < UserID >1</ UserID >
   < UserName >a</ UserName >
</ row >
< row >
   < UserID >2</ UserID >
   < UserName >b</ UserName >
</ row >
?
1
大家可以看到两行数据生成了两个节点,修改一下PATH的参数:
?
1
select UserID,UserName from @TempTable FOR XML PATH( 'lzy' )

再次运行上述脚本,将生成如下的结果:

?
1
2
3
4
5
6
7
8
< lzy >
   < UserID >1</ UserID >
   < UserName >a</ UserName >
</ lzy >
< lzy >
   < UserID >2</ UserID >
   < UserName >b</ UserName >
</ lzy >
?
1
可以看到节点变成,其实PATH() 括号内的参数是控制节点名称的,这样的话大家可以看一下如果是空字符串(不是没有参数)会是什么结果?
?
1
select UserID,UserName from @TempTable FOR XML PATH( '' )

执行上面这段脚本将生成结果:

?
1
2
3
4
< UserID >1</ UserID >
< UserName >a</ UserName >
< UserID >2</ UserID >
< UserName >b</ UserName >

这样就不显示上级节点了,大家知道在 PATH 模式中,列名或列别名被作为 XPath 表达式来处理,也就是说,是列的名字,这样大胆试验一下不给指定列名和别名会是怎么样?

?
1
select CAST (UserID AS varchar ) + '' ,UserName + '' from @TempTable FOR XML PATH( '' )

 

运行上面这句将生成结果

1a2b

所有数据都生成一行,而且还没有连接字符,这样的数据可能对大家没有用处,还可以再变化一下:

?
1
select CAST (UserID AS varchar ) + ',' ,UserName + '' , ';' from @TempTable FOR XML PATH( '' )

 

生成结果

1,a;2,b;

大家现在明白了吧,可以通过控制参数来生成自己想要的结果,例如:

 

?
1
select '{' + CAST (UserID AS varchar ) + ',' , '"' +UserName + '"' , '}' from @TempTable FOR XML PATH( '' )

 

生成结果

{1,"a"}{2,"b"}

还可以生成其他格式,大家可以根据自己需要的格式进行组合。

下面是一个数据统计的应用,希望大家可以通过下面的实例想到更多的应用

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
DECLARE @T1 table (UserID int , UserName nvarchar(50),CityName nvarchar(50));
insert into @T1 (UserID,UserName,CityName) values (1, 'a' , '上海' )
insert into @T1 (UserID,UserName,CityName) values (2, 'b' , '北京' )
insert into @T1 (UserID,UserName,CityName) values (3, 'c' , '上海' )
insert into @T1 (UserID,UserName,CityName) values (4, 'd' , '北京' )
insert into @T1 (UserID,UserName,CityName) values (5, 'e' , '上海' )
  
SELECT B.CityName, LEFT (UserList,LEN(UserList)-1) FROM (
SELECT CityName,
     ( SELECT UserName+ ',' FROM @T1 WHERE CityName=A.CityName  FOR XML PATH( '' )) AS UserList
FROM @T1 A
GROUP BY CityName
) B

 

生成结果(每个城市的用户名)

北京 b,d
上海 a,c,e

————————————————————————————————————————————————————————————

FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作。那么以一个实例为主.

        一.FOR XML PATH 简单介绍

             那么还是首先来介绍一下FOR XML PATH ,假设现在有一张兴趣爱好表(hobby)用来存放兴趣爱好,表结构如下:

       接下来我们来看应用FOR XML PATH的查询结果语句如下:

SELECT   *   FROM   @hobby   FOR  XML PATH

       结果:

< row >
   < hobbyID > 1 </ hobbyID >
   < hName > 爬山 </ hName >
</ row >
< row >
   < hobbyID > 2 </ hobbyID >
   < hName > 游泳 </ hName >
</ row >
< row >
   < hobbyID > 3 </ hobbyID >
   < hName > 美食 </ hName >
</ row >

      由此可见FOR XML PATH 可以将查询结果根据行输出成XML各式!

      那么,如何改变XML行节点的名称呢?代码如下:     

SELECT   *   FROM   @hobby   FOR  XML PATH( ' MyHobby ' )

      结果一定也可想而知了吧?没错原来的行节点<row> 变成了我们在PATH后面括号()中,自定义的名称<MyHobby>,结果如下:

< MyHobby >
   < hobbyID > 1 </ hobbyID >
   < hName > 爬山 </ hName >
</ MyHobby >
< MyHobby >
   < hobbyID > 2 </ hobbyID >
   < hName > 游泳 </ hName >
</ MyHobby >
< MyHobby >
   < hobbyID > 3 </ hobbyID >
   < hName > 美食 </ hName >
</ MyHobby >

      这个时候细心的朋友一定又会问那么列节点如何改变呢?还记的给列起别名的关键字AS吗?对了就是用它!代码如下:

SELECT  hobbyID  as   ' MyCode ' ,hName  as   ' MyName '   FROM   @hobby   FOR  XML PATH( ' MyHobby ' )
      那么这个时候我们列的节点名称也会编程我们自定义的名称 <MyCode>与<MyName>结果如下:
< MyHobby >
   < MyCode > 1 </ MyCode >
   < MyName > 爬山 </ MyName >
</ MyHobby >
< MyHobby >
   < MyCode > 2 </ MyCode >
   < MyName > 游泳 </ MyName >
</ MyHobby >
< MyHobby >
   < MyCode > 3 </ MyCode >
   < MyName > 美食 </ MyName >
</ MyHobby >
    噢! 既然行的节点与列的节点我们都可以自定义,我们是否可以构建我们喜欢的输出方式呢?还是看代码: 
SELECT   ' [  ' + hName + '  ] '   FROM   @hobby   FOR  XML PATH( '' )

    没错我们还可以通过符号+号,来对字符串类型字段的输出格式进行定义。结果如下:

[ 爬山 ][ 游泳 ][ 美食 ]

    那么其他类型的列怎么自定义? 没关系,我们将它们转换成字符串类型就行啦!例如:

SELECT   ' { ' + STR (hobbyID) + ' } ' , ' [  ' + hName + '  ] '   FROM   @hobby   FOR  XML PATH( '' )

    好的 FOR XML PATH就基本介绍到这里吧,更多关于FOR XML的知识请查阅帮助文档!

    接下来我们来看一个FOR XML PATH的应用场景吧!那么开始吧。。。。。。

        二.一个应用场景与FOR XML PATH应用

        首先呢!我们在增加一张学生表,列分别为(stuID,sName,hobby),stuID代表学生编号,sName代表学生姓名,hobby列存学生的爱好!那么现在表结构如下:

           

        这时,我们的要求是查询学生表,显示所有学生的爱好的结果集,代码如下:

SELECT  B.sName, LEFT (StuList, LEN (StuList) - 1 )  as  hobby  FROM  (
SELECT  sName,
( SELECT  hobby + ' , '   FROM  student 
   WHERE  sName = A.sName 
   FOR  XML PATH( '' ))  AS  StuList
FROM  student A 
GROUP   BY  sName
) B

         结果如下:

分析: 好的,那么我们来分析一下,首先看这句:

SELECT  hobby + ' , '   FROM  student 
   WHERE  sName = A.sName 
   FOR  XML PATH( '' )

这句是通过FOR XML PATH 将某一姓名如张三的爱好,显示成格式为:“ 爱好1,爱好2,爱好3,”的格式!

那么接着看:

SELECT  B.sName, LEFT (StuList, LEN (StuList) - 1 )  as  hobby  FROM  (
SELECT  sName,
( SELECT  hobby + ' , '   FROM  student 
   WHERE  sName = A.sName 
   FOR  XML PATH( '' ))  AS  StuList
FROM  student A 
GROUP   BY  sName
) B 

剩下的代码首先是将表分组,在执行FOR XML PATH 格式化,这时当还没有执行最外层的SELECT时查询出的结构为:

可以看到StuList列里面的数据都会多出一个逗号,这时随外层的语句:SELECT B.sName,LEFT(StuList,LEN(StuList)-1) as hobby 就是来去掉逗号,并赋予有意义的列名!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值