如何在SQL Server中将多行连接成一列?

Jas*_*son 4 sql t-sql sql-server

我已经高低搜索了这个答案,但我无法弄明白.我对SQL Server比较陌生,但还没有很好的语法.我有这个数据结构(简化):

Table "Users"         | Table "Tags":
UserID    UserName    | TagID    UserID    PhotoID
1         Bob         | 1        1         1
2         Bill        | 2        2         1
3         Jane        | 3        3         1
4         Sam         | 4        2         2
-----------------------------------------------------
Table "Photos":              | Table "Albums":
PhotoID   UserID    AlbumID  | AlbumID     UserID
1         1         1        | 1           1
2         1         1        | 2           3
3         1         1        | 3           2
4         3         2        |
5         3         2        |

我正在寻找一种方法来获取所有照片信息(简单)以及该照片的所有标签连接CONCAT(username, ', ') AS Tags,当然最后删除了逗号.我有一段时间试图这样做.我已经尝试过本文中的方法,但是当我尝试运行查询说我无法使用DECLARE语句时出现错误...你们有什么想法可以做到这一点吗?我正在使用VS08和其中安装的任何数据库(我通常使用MySQL,所以我不知道这是什么类型的DB真的是......它是一个.mdf文件?)

Rob*_*ley 13

好吧,我觉得我需要深入评论如何在SQL Server中将多行连接成一列?并提供更优选的答案.

我很抱歉,但使用这样的标量值函数会破坏性能.只需打开SQL事件探查器,看看当你使用调用表的标量函数时发生了什么.

此外,不鼓励使用"更新变量"技术进行连接,因为该功能可能在将来的版本中不会继续.

执行字符串连接以使用FOR XML PATH的首选方法.

select
 stuff((select ', ' + t.tag from tags t where t.photoid = p.photoid order by tag for xml path('')),1,2,'') as taglist
 ,*
from photos
order by photoid;
Run Code Online (Sandbox Code Playgroud)

有关FOR XML PATH如何工作的示例,请考虑以下内容,假设您有一个包含两个名为"id"和"name"的字段的表

SELECT id, name
FROM table
order by name
FOR XML PATH('item'),root('itemlist')
;
Run Code Online (Sandbox Code Playgroud)

得到:

<itemlist><item><id>2</id><name>Aardvark</a></item><item><id>1</id><name>Zebra</name></item></itemlist>
Run Code Online (Sandbox Code Playgroud)

但如果你忽略ROOT,你会得到一些略有不同的东西:

SELECT id, name
FROM table
order by name
FOR XML PATH('item')
;

<item><id>2</id><name>Aardvark</a></item><item><id>1</id><name>Zebra</name></item>
Run Code Online (Sandbox Code Playgroud)

如果你输入一个空的PATH字符串,你会更接近普通的字符串连接:

SELECT id, name
FROM table
order by name
FOR XML PATH('')
;

<id>2</id><name>Aardvark</a><id>1</id><name>Zebra</name>
Run Code Online (Sandbox Code Playgroud)

现在来了一个非常棘手的问题......如果你命名一个以@符号开头的列,它就会变成一个属性,如果一个列没有名字(或者你称之为[*]),那么它就会省略标签也是:

SELECT ',' + name
FROM table
order by name
FOR XML PATH('')
;

,Aardvark,Zebra
Run Code Online (Sandbox Code Playgroud)

最后,为了去除前导逗号,STUFF命令进入.STUFF(s,x,n,s2)从位置x开始抽出s的n个字符.取而代之的是s2.所以:

SELECT STUFF('abcde',2,3,'123456');

得到:

a123456e

现在看看我上面的标记列表查询.

select
 stuff((select ', ' + t.tag from tags t where t.photoid = p.photoid order by tag for xml path('')),1,2,'') as taglist
 ,*
from photos
order by photoid;
Run Code Online (Sandbox Code Playgroud)

对于每张照片,我都有一个子查询,它抓取标签并将它们(按顺序)与一个commma和一个空格连接起来.然后我在一个stuff命令中包围该子查询以去除前导逗号和空格.

我为任何打字错误道歉 - 我实际上并没有在我自己的机器上创建表来测试它.