连接行值T-SQL

我正在试图将一些数据汇总在一起,需要连接其中一个表的行值。 这里是基本的表结构:

评测

ReviewID ReviewDate 

评审

  ReviewerID ReviewID UserID 

用户

 UserID FName LName 

这是M:M的关系。 每个评论可以有许多评论者; 每个用户可以与许多评论相关联。

基本上,我只想看到的是Review.ReviewID,Reviews.ReviewDate和该评论的所有关联用户的FName的连接string(逗号分隔)。

代替:

 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 

我发现这篇文章描述了一些方法来做到这一点,但其中大多数似乎只处理一个表,而不是多个; 不幸的是,我的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; 

任何人都可以帮我一个这个吗? 任何帮助将不胜感激!

看看这个

 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 

原来,有一个更简单的方法来做到这一点,不需要UDF:

 select replace(replace(replace((cast(( select distinct columnName as X from tableName for xml path('')) as varchar(max))), '</X><X>', ', '),'<X>', ''),'</X>','') 

有类似的问题,并发现代码15分钟后,甜蜜的解决scheme

 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种方式处理汇总数据:使用游标,使用UDF或使用自定义聚合(使用.NET CLR编写)。
游标和UDF是相当缓慢的。 (每行约0.1秒)。 CLR自定义聚合速度惊人地快。 (每行约0.001秒)

作为SQL 2005 SDK的一部分,Microsoft提供了代码(按照您的需要进行操作)。如果安装了该代码,则应该能够在该文件夹中find代码:C:\ Program Files \ Microsoft SQL Server \ 90 \样本\发动机\可编程\ 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; 

并得到像你所示的结果集(上图)

 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, 

UDF是解决这个问题的好方法。

只需定义一个T-SQL函数(UDF),它接受一个int参数(产品ID)并返回一个string(与产品关联的名称的拼接)。如果您的方法名称是GetProductNames,那么您的查询可能如下所示:

 SELECT p1.CategoryId, dbo.GetProductNames(p1.CategoryId) FROM Northwind.dbo.Products p1 GROUP BY CategoryId 

尝试这个:

  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 
 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; 

SqlServer 2017现在有STRING_AGG ,它使用给定的分隔符将多个string聚合为一个。

似乎你需要group_concat(从MySQL)的function。 这已经在这里解决了另一个testing数据集: 如何返回一列中的多个值(T-SQL)?

创build一个临时表来转储数据。然后使用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 
 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