我正在尝试将一些数据汇总到报告中,并且需要连接其中一个表的行值。这是基本的表结构:
评论
ReviewID
ReviewDate
审稿人
ReviewerID
ReviewID
UserID
用户
UserID
FName
LName
这是M:M关系。每个评论都可以有很多评论者;每个用户都可以与许多评论相关联。
基本上,我想要看的是Reviews.ReviewID,Reviews.ReviewDate,以及该评论的所有相关用户的FName的串联字符串(逗号分隔)。
而不是:
ReviewID---ReviewDate---User
1----------12/1/2009----Bob
1----------12/1/2009----Joe
1----------12/1/2009----Frank
2----------12/9/2009----Sue
2----------12/9/2009----Alice
显示:
ReviewID---ReviewDate----Users
1----------12/1/2009-----Bob, Joe, Frank
2----------12/9/2009-----Sue, Alice
我发现this文章描述了一些方法,但其中大多数似乎只涉及一个表,而不是多个;不幸的是,我的SQL-fu不够强大,无法根据我的情况进行调整。我对该网站上使用FOR XML PATH()的示例特别感兴趣,因为它看起来最干净,最直接。
SELECT p1.CategoryId,
( SELECT ProductName + ', '
FROM Northwind.dbo.Products p2
WHERE p2.CategoryId = p1.CategoryId
ORDER BY ProductName FOR XML PATH('')
) AS Products
FROM Northwind.dbo.Products p1
GROUP BY CategoryId;
任何人都可以帮我一把吗?任何帮助将不胜感激!
答案 0 :(得分:33)
看看这个
DECLARE @Reviews TABLE(
ReviewID INT,
ReviewDate DATETIME
)
DECLARE @Reviewers TABLE(
ReviewerID INT,
ReviewID INT,
UserID INT
)
DECLARE @Users TABLE(
UserID INT,
FName VARCHAR(50),
LName VARCHAR(50)
)
INSERT INTO @Reviews SELECT 1, '12 Jan 2009'
INSERT INTO @Reviews SELECT 2, '25 Jan 2009'
INSERT INTO @Users SELECT 1, 'Bob', ''
INSERT INTO @Users SELECT 2, 'Joe', ''
INSERT INTO @Users SELECT 3, 'Frank', ''
INSERT INTO @Users SELECT 4, 'Sue', ''
INSERT INTO @Users SELECT 5, 'Alice', ''
INSERT INTO @Reviewers SELECT 1, 1, 1
INSERT INTO @Reviewers SELECT 2, 1, 2
INSERT INTO @Reviewers SELECT 3, 1, 3
INSERT INTO @Reviewers SELECT 4, 2, 4
INSERT INTO @Reviewers SELECT 5, 2, 5
SELECT *,
(
SELECT u.FName + ','
FROM @Users u INNER JOIN
@Reviewers rs ON u.UserID = rs.UserID
WHERE rs.ReviewID = r.ReviewID
FOR XML PATH('')
) AS Products
FROM @Reviews r
答案 1 :(得分:20)
事实证明,有一种更简单的方法可以做到这一点,不需要UDF:
select replace(replace(replace((cast((
select distinct columnName as X
from tableName
for xml path('')) as varchar(max))),
'</X><X>', ', '),'<X>', ''),'</X>','')
答案 2 :(得分:10)
有类似的问题,并在使用代码15分钟后找到了一个很好的解决方案
declare @result varchar(1000)
select @result = COALESCE(@result+','+A.col1, A.col1)
FROM ( select col1
from [table]
) A
select @result
以value1,value2,value3,value4
返回结果享受;)
答案 3 :(得分:7)
SqlServer 2017现在有STRING_AGG,它使用给定的分隔符将多个字符串聚合为一个。
答案 4 :(得分:6)
正如您所描述的,有三种处理汇总数据的方法,1。使用游标,2。使用UDF或3.使用自定义聚合(用.NET CLR编写)。 /> Cursor和UDF非常慢。 (每行大约0.1秒)。 CLR自定义聚合速度惊人的快。 (每行大约0.001秒)
Microsoft提供代码(完全按照您的意愿)作为SDK for SQL 2005的一部分。如果安装了它,您应该能够在此文件夹中找到代码: C:\ Program Files \ Microsoft SQL Server \ 90 \ Samples \ Engine \ Programmability \ CLR \ StringUtilities。 您可能还想在MSDN中阅读本文。它讨论了安装自定义聚合并启用它: http://msdn.microsoft.com/en-us/library/ms161551(SQL.90).aspx
编译并安装自定义聚合后,您应该可以这样查询:
SELECT Reviews.ReviewID, ReviewDate, dbo.StringUtilities.Concat(FName) AS [User]
FROM Reviews INNER JOIN Reviewers ON Reviews.ReviewID = Reviewers.ReviewID
INNER JOIN Users ON Reviews.UserID = Users.UserID
GROUP BY ReviewID, ReviewDate;
并获得与您展示的结果集(上图)
答案 5 :(得分:5)
select p1.Availability ,COUNT(*),
(select name+',' from AdventureWorks2008.Production.Location p2 where
p1.Availability=p2.Availability for XML path(''),type).value('.','varchar(max)')
as Name from AdventureWorks2008.Production.Location p1 group by Availability
结果
Availability COUNT Name
---------------------------------------------------------------------------------
0.00 7 Tool Crib,Sheet Metal Racks,Paint Shop,Paint Storage,Metal
Storage,Miscellaneous Storage,Finished Goods Storage,
80.00 1 Specialized Paint,
96.00 1 Frame Forming,
108.00 1 Frame Welding,
120.00 4 Debur and Polish,Paint,Subassembly,Final Assembly,
答案 6 :(得分:3)
UDF是解决这个问题的好方法。
只需定义一个T-SQL函数(UDF),它接受一个int参数(产品ID)并返回一个字符串(与产品关联的名称的串联。)如果您的方法名称是GetProductNames,那么您的查询可能如下所示:
SELECT p1.CategoryId, dbo.GetProductNames(p1.CategoryId)
FROM Northwind.dbo.Products p1
GROUP BY CategoryId
答案 7 :(得分:3)
试试这个:
Declare @Revs Table
(RevId int Priimary Key Not Null,
RevDt DateTime Null,
users varChar(1000) default '')
Insert @Revs (RevId, RevDt)
Select Distinct ReviewId, ReviewDate
From Reviews
Declare @UId Integer
Set @Uid = 0
While Exists (Select * From Users
Where UserID > @Uid)
Begin
Update @Revs Set
users = users + u.fName + ', '
From @Revs R
Join Reviewers uR On ur.ReviewId = R.RId
Join users u On u.UserId = uR.UserId
Where uR.UserId = @UId
Select @Uid = Min(UserId)
From users
Where UserId > @UId
End
Select * From @Revs
答案 8 :(得分:3)
Select R.ReviewID, ReviewDate
, (Select FName + ', '
from Users
where UserID = R.UserID
order by FName FOR XML PATH(')
) as [Users]
from Reviews
inner join Reviewers AS R
On Reviews.ReviewID = R.ReviewID
Group By R.ReviewID, ReviewDate;
答案 9 :(得分:3)
现在,从SQL server 2017开始,有一个名为STRING_AGG
的新 T-SQL 函数:
它是一个新的聚合函数,它连接字符串表达式的值并在它们之间放置分隔符值
字符串末尾没有添加分隔符。
示例:
SELECT STRING_AGG ( ISNULL(FirstName,'N/A'), ',') AS csv
FROM Person.Person;
结果集:
John,N/A,Mike,Peter,N/A,N/A,Alice,Bob
答案 10 :(得分:2)
好像你需要group_concat的功能(来自mysql)。这里已针对另一个测试数据集进行了解决:How to return multiple values in one column (T-SQL)?
答案 11 :(得分:2)
创建临时表以转储数据。然后使用FOR XML PATH方法。需要使用外部查询来修剪列表中的最后一个逗号。
CREATE TABLE #ReviewInfo (
ReviewId INT,
ReviewDate DATETIME,
Reviewer VARCHAR(1000))
INSERT INTO #ReviewInfo (ReviewId, ReviewDate, Reviewer)
SELECT r.ReviewId, r.ReviewDate, u.FName
FROM Reviews r
JOIN Reviewers rs ON r.ReviewId = rs.ReviewId
JOIN Users u ON u.UserId = rs.UserId
SELECT ReviewId, ReviewDate, LEFT(Users, LEN(Users)-1)
FROM (
SELECT ReviewId, ReviewDate,
(
SELECT Reviewer + ', '
FROM #ReviewInfo ri2
WHERE ri2.ReviewId = ri1.ReviewId
ORDER BY Reviewer
FOR XML PATH('')
) AS Users
FROM #ReviewInfo ri1
GROUP BY ReviewId, ReviewDate
) a
DROP TABLE #ReviewInfo
答案 12 :(得分:2)
select
p1.Availability,
COUNT(*),
(
select name+','
from AdventureWorks2008.Production.Location p2
where p1.Availability=p2.Availability
for XML path(''),type
).value('.','varchar(max)') as Name
from AdventureWorks2008.Production.Location p1
group by Availability
答案 13 :(得分:0)
当项目数量很少时,可以使用ROW_NUMBER()OVER PARTITION BY:
declare @t table (col1 int, col2 varchar)
insert into @t VALUES (1,'A')
insert into @t VALUES (1,'B')
insert into @t VALUES (1,'C')
insert into @t VALUES (1,'D')
insert into @t VALUES (1,'E')
insert into @t VALUES (2,'X')
insert into @t VALUES (3,'Y')
select col1,
MAX(CASE seq WHEN 1 THEN col2 ELSE '' END ) +
MAX(CASE seq WHEN 2 THEN ', ' + col2 ELSE '' END ) +
MAX(CASE seq WHEN 3 THEN ', ' + col2 ELSE '' END ) +
MAX(CASE seq WHEN 4 THEN ', ' + col2 ELSE '' END ) +
MAX(CASE seq WHEN 5 THEN ',...' ELSE '' END )
as col2
from (
select col1, col2, ROW_NUMBER() OVER ( PARTITION BY col1 ORDER BY col2 ) seq
from @t
group by col1, col2
) x
group by col1
答案 14 :(得分:0)
STRING_AGG ( expression, separator ) [ <order_clause> ]
<order_clause> ::=
WITHIN GROUP ( ORDER BY <order_by_expression_list> [ ASC | DESC ] )
我来到Stackoverflow寻找SQL Server字符串聚合函数。
相关问题已经关闭,标记为该问题的重复项,因此我被迫在此处回答或根本不回答。
有关详细信息,请参见https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-2017。