在项目开发中,有时会碰到将列记录合并为一行的状况,例如根据地区将人员姓名合并,或根据拼音首字母合并城市等,下面就以根据地区将人员姓名合并为例,详细讲一下合并的方法。函数
首先,先建一个表,并添加一些数据,建表代码以下:测试
If OBJECT_ID(N'Demo') Is Not Null
Begin
Drop Table Demo
End
Else
Begin
Create Table Demo(
Area nvarchar(30),
Name nvarchar(20))spaInsert Into Demo(Area,Name)
Values(N'北京',N'张三'),
(N'上海',N'李四'),
(N'深圳',N'王五'),
(N'深圳',N'钱六'),
(N'北京',N'赵七'),
(N'北京','Tom'),
(N'上海','Amy'),
(N'北京','Joe'),
(N'深圳','Leo')
End
Go3d
建完后查询一下,可见表中数据以下:blog
若是仅将Name列合并,不遵循任何条件的话,咱们能够采用两种方法,第一种就是采用FOR XML PATH方式,代码以下:开发
SELECT ','+Name FROM dbo.Demo FOR XML PATH('')get
运行结果以下:it
关于FOR XML PATH的详细介绍可参考MSDN:搭配 FOR XML 使用 PATH 模式io
第二种方法就是定义一个变量用来装载查询的结果,代码以下:function
Declare @NameCollection nvarchar(500)
Select @NameCollection=ISNULL(@NameCollection+',','')+Name From dbo.Demo
Select @NameCollection as NameCollection
运行结果以下:
加了ISNULL是由于最开始变量@NameCollection为NULL,为了不“张三”前多一个逗号(“,”)而采用的替换。
上面讲了在无条件的状况下合并一列,可是在项目中几乎不会遇到这样的状况,通常都是根据某一列来合并另外一列的数据,例如咱们如今要根据Area将Name合并,获得这样的结果:
有了上面的基础,要合并成这样的数据就容易了,咱们只须要针对Area列采用聚合GROUP BY或取不重复值DISTINCT,而后根据Area列合并Name列,有了思路,下面就来讲说如何实现,首先仍是采用FOR XML PATH方式,结合自链接,首先先按Area列对Name列进行合并,代码以下:
SELECT Area,
(SELECT ','+Name FROM dbo.Demo WHERE Area = t.Area FOR XML PATH(''))
AS NameCollection FROM dbo.Demo AS t
运行结果以下:
如今有两点还没实现,第一是结果重复了,第二是NameCollection列最开始都多了一个逗号,先去掉逗号,采用STUFF 函数来进行替换,代码修改以下:
SELECT Area,
STUFF((SELECT ','+Name FROM dbo.Demo WHERE Area = t.Area FOR XML PATH('')),1,1,'')
AS NameCollection FROM dbo.Demo AS t
如今运行后结果以下:
下面就剩下去掉重复数据了,分别采用GROUP BY和DISTINCT,代码以下:
SELECT DISTINCT Area,
STUFF((SELECT ','+Name FROM dbo.Demo WHERE Area = t.Area FOR XML PATH('')),1,1,'')
AS NameCollection FROM dbo.Demo AS t
SELECT Area,
STUFF((SELECT ','+Name FROM dbo.Demo WHERE Area = t.Area FOR XML PATH('')),1,1,'')
AS NameCollection FROM dbo.Demo AS t GROUP BY Area
关于STUFF函数能够参考MSDN介绍:STUFF函数
运行结果即为最终咱们须要的结果,最开始在上面讲到了一种用变量来装载查询结果实现合并一列的方法,下面详细介绍如何采用上述方法来实现咱们的需求,咱们能够根据上面的方法建一个函数,传入一个Area参数,根据Area来进行合并,返回合并值,函数以下:
CREATE FUNCTION MergeByColumn
(
-- Add the parameters for the function here
@Area nvarchar(30)
)
RETURNS nvarchar(500)
AS
BEGIN
-- Declare the return variable here
DECLARE @NC nvarchar(500)-- Add the T-SQL statements to compute the return value here
SELECT @NC=ISNULL(@NC+',','')+Name FROM dbo.Demo WHERE Area=@Area-- Return the result of the function
RETURN @NCEND
GO
建好后测试下,以传入参数为“北京”为例,运行以下代码:
SELECT dbo.MergeByColumn('北京') AS NameCollection
获得结果以下:
如今只需将Area列也加入查询便可,修改代码以下:
SELECT Area,dbo.MergeByColumn(Area) AS NameCollection From dbo.Demo
如今也获得了重复的结果,以下:
去重复一样能够用GROUP BY和DISTINCT,代码以下,便可以获得咱们最终的结果:
SELECT DISTINCT Area,dbo.MergeByColumn(Area) AS NameCollection From dbo.Demo
SELECT Area,dbo.MergeByColumn(Area) AS NameCollection From dbo.Demo GROUP BY Area