2009-08-09 76 views
4

我已經搜索了高和低的答案,但我無法弄清楚。我對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去掉最後一個逗號。我有一段時間想做這件事。我嘗試了this article中的方法,但是當我嘗試運行查詢時說我不能使用DECLARE語句時出現錯誤...您是否有任何想法可以做到這一點?我正在使用VS08和任何數據庫安裝在它(我通常使用MySQL,所以我不知道這是什麼味道的DB這是一個.mdf文件?)

回答

3

我會創建一個UDF :

create function GetTags(PhotoID int) returns @tags varchar(max) 
as 
begin 
    declare @mytags varchar(max) 
    set @mytags = '' 

    select @mytags = @mytags + ', ' + tag from tags where photoid = @photoid 

    return substring(@mytags, 3, 8000) 
end 

然後,所有你需要做的是:

select GetTags(photoID) as tagList from photos 
+0

是「內聯」,「表值」還是「標量值」函數?這些是VS給我的選項... – Jason 2009-08-09 03:07:17

+0

標量值 - 抱歉,我沒有指定。 – Eric 2009-08-09 03:07:43

+0

詳細闡述一下:表值和內聯函數都返回類型表。這些選項可以幫助您掌握一些語法,但如果您直接運行此SQL,它將自動成爲標量。 – Eric 2009-08-09 03:14:18

13

好吧,我覺得我需要跳轉到評論有關How do you concat multiple rows into one column in SQL Server?,並提供一個更優選的答案。

我真的很抱歉,但使用像這樣的標量值函數會導致性能下降。只需打開SQL Profiler並查看當您使用調用表的標量函數時發生了什麼。

另外,不鼓勵「連接更新變量」技術,因爲該功能在未來的版本中可能不會繼續。

改爲使用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; 

有關如何FOR XML PATH的作品,請考慮以下,想象你有兩個字段的表稱爲 '身份證' 和 '名'

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

給出一些例子:

<itemlist><item><id>2</id><name>Aardvark</a></item><item><id>1</id><name>Zebra</name></item></itemlist> 

但是如果你遺漏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> 

如果你把一個空的路徑字符串,你會得到更接近普通字符串連接:

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

<id>2</id><name>Aardvark</a><id>1</id><name>Zebra</name> 

現在到了真正棘手位......如果你的名字開始與一個@符號欄,就變成一個屬性,如果一列沒有名稱(或你叫它[*]),那麼它留下的是太多的標籤:

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

,Aardvark,Zebra 

如今終於,剝奪領先逗號,東東命令STUFF(s,x,n,s2)從位置x開始拉出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; 

對於每張照片,我有抓住標籤和與commma和一個空間連接它們(按順序)的子查詢。然後,我用stuff命令將該子查詢包圍起來,以去掉前導逗號和空格。

對於任何錯別字,我表示歉意 - 我沒有在我自己的機器上真正創建表來測試它。

Rob

+0

+1,但它實際上返回XML,我不想要。出於某種原因,它將您原來的'SELECT','+ username'更改爲'SELECT TOP(100)PERCENT','+ dbo.users.username AS tags' ... – Jason 2009-08-09 04:03:34

+0

擺脫「as tags」。 而不要把它放在一個函數。按原樣運行。你真的跑了什麼? – 2009-08-09 04:30:04

+0

我無法擺脫「as」,因爲它將「作爲Expr1」作爲默認值,並且我沒有將它作爲函數運行。我把它作爲一個標準的SQL查詢來運行:\ – Jason 2009-08-09 04:48:05