连接行值 T-SQL

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1874966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 04:42:12  来源:igfitidea点击:

Concatenate row values T-SQL

sqlsql-servertsqlconcatenation

提问by Sesame

I am trying to pull together some data for a report and need to concatenate the row values of one of the tables. Here is the basic table structure:

我正在尝试为报告汇总一些数据,并且需要连接其中一个表的行值。下面是基本的表结构:

Reviews

评论

 ReviewID  
 ReviewDate  

Reviewers

审稿人

 ReviewerID  
 ReviewID  
 UserID  

Users

用户

UserID  
FName  
LName  

This is a M:M relationship. Each Review can have many Reviewers; each User can be associated with many Reviews.

这是一种 M:M 关系。每个Review可以有多个Reviewer;每个用户可以与许多评论相关联。

Basically, all I want to see is Reviews.ReviewID, Reviews.ReviewDate, and a concatenated string of the FName's of all the associated Users for that Review (comma delimited).

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

Instead of:

代替:

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  

Display this:

显示这个:

ReviewID---ReviewDate----Users  
1----------12/1/2009-----Bob, Joe, Frank  
2----------12/9/2009-----Sue, Alice

I have found thisarticle describing some ways to do this, but most of these seem to only deal with one table, not multiple; unfortunately, my SQL-fu is not strong enough to adapt these to my circumstances. I am particularly interested in the example on that site which utilizes FOR XML PATH() as that looks the cleanest and most straight forward.

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

Can anyone give me a hand with this? Any help would be greatly appreciated!

任何人都可以帮我解决这个问题吗?任何帮助将不胜感激!

采纳答案by Adriaan Stander

Have a look at this

看看这个

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

回答by Digital Mindspring

Turns out there is an even easier way to do this which doesn't require a UDF:

事实证明,有一种更简单的方法可以做到这一点,它不需要 UDF:

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

回答by Talha

Had similar problem and found a sweet solution after playing with code for 15 minutes

遇到了类似的问题,玩了 15 分钟的代码后找到了一个甜蜜的解决方案

declare @result varchar(1000)
select @result = COALESCE(@result+','+A.col1, A.col1)
                FROM (  select  col1
                        from [table] 
                ) A
select @result

Returns result as value1,value2,value3,value4

返回结果为 value1,value2,value3,value4

Enjoy ;)

享受 ;)

回答by John

SqlServer 2017 now has STRING_AGGthat aggregates multiple strings into one using a given separator.

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

回答by TimG

There are 3 ways I have dealt with rolling-up data, as you have described, 1.use a cursor, 2.use a UDF or 3. use the a Custom Aggregate (written in .NET CLR).
The Cursor and UDF are pretty slow. (approx 0.1 sec per row). The CLR custom aggregate is surprisingly fast. (approx 0.001 sec per row)

正如您所描述的,我有 3 种处理汇总数据的方法,1. 使用游标,2. 使用 UDF 或 3. 使用自定义聚合(用 .NET CLR 编写)。
Cursor 和 UDF 非常慢。(每行约 0.1 秒)。CLR 自定义聚合的速度惊人地快。(每行约 0.001 秒)

Microsoft ships the code (to do exactly what you want) as part of the SDK for SQL 2005. If you have it installed, you should be able to find the code in this folder: C:\Program Files\Microsoft SQL Server\90\Samples\Engine\Programmability\CLR\StringUtilities. You might also want to this article in MSDN. It talks about installing the custom aggregate and enabling it: http://msdn.microsoft.com/en-us/library/ms161551(SQL.90).aspx

Microsoft 将代码(完全按照您的要求)作为 SQL 2005 SDK 的一部分提供。如果您安装了它,您应该能够在以下文件夹中找到代码:C:\Program Files\Microsoft SQL Server\90 \Samples\Engine\Programmability\CLR\StringUtilities。您可能还想阅读 MSDN 中的这篇文章。它谈到安装自定义聚合并启用它:http: //msdn.microsoft.com/en-us/library/ms161551(SQL.90).aspx

Once you compile and install the custom aggregate, you should be able to query like this:

编译并安装自定义聚合后,您应该能够像这样查询:

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;

and get a result set like you showed (above)

并获得您显示的结果集(上图)

回答by Wael Ali

Now from SQL server 2017 there is a new T-SQLfunction called STRING_AGG:
it is a new aggregate function that concatenates the values of string expressions and places separator values between them.
The separator is not added at the end of string.

现在从 SQL Server 2017 开始,有一个名为的新T-SQL函数STRING_AGG
它是一个新的聚合函数,用于连接字符串表达式的值并在它们之间放置分隔符值。
字符串末尾不添加分隔符。

Example:

例子:

SELECT STRING_AGG ( ISNULL(FirstName,'N/A'), ',') AS csv 
FROM Person.Person; 

the result set:

结果集:

John,N/A,Mike,Peter,N/A,N/A,Alice,Bob

回答by pradeep

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

Result

结果

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,

回答by Charles Bretana

Try this:

尝试这个:

 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

回答by JeffO

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;

回答by Paul Sasik

A UDFwould be an ok way to solve this.

一个UDF将是解决这个的确定方式。

Just define a T-SQL function (UDF) that takes an int param (product ID) and returns a string (concatenation of names associated with the product.) If your method's name is GetProductNames then your query might look like this:

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

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