2009-08-09 8 views
4

J'ai cherché haut et bas pour la réponse à cela, mais je ne peux pas comprendre. Je suis relativement nouveau à SQL Server et n'ai pas encore la syntaxe vers le bas. J'ai cette structure de données (simplifié):Comment concattez-vous plusieurs lignes dans une colonne dans 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  | 

Je cherche un moyen d'obtenir la toutes les informations de photos (facile) ainsi que tous les tags pour cette photo concaténé comme CONCAT(username, ', ') AS Tags bien sûr avec la virgule retirée. Je suis un ours d'un temps à essayer de le faire. J'ai essayé la méthode dans this article mais j'obtiens une erreur quand j'essaie d'exécuter la requête en disant que je ne peux pas utiliser les déclarations DECLARE ... avez-vous une idée de la façon dont cela peut être fait? J'utilise VS08 et quel que soit le DB qui y est installé (j'utilise normalement MySQL donc je ne sais pas quelle est la saveur de DB ... c'est un fichier .mdf?)

Répondre

3

Je créerais une FDU :

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 

Ensuite, tout ce que vous avez à faire est:

select GetTags(photoID) as tagList from photos 
+0

est qu'une "ligne", "valeur table", ou la fonction "valeur scalaire"? ce sont les options VS me donne ... – Jason

+0

Scalar Valued - désolé je n'ai pas précisé. – Eric

+0

Elaboration d'un bit: les fonctions Table et Inline renvoient toutes deux une table de type. Ces options sont pour vous aider avec une partie de la syntaxe, mais si vous avez exécuté ce SQL directement, ce serait automatiquement scalaire. – Eric

13

Ok, je sens que je dois sauter pour commenter au sujet How do you concat multiple rows into one column in SQL Server? et de fournir une réponse plus préférée. Je suis vraiment désolé, mais l'utilisation de fonctions à valeur scalaire comme celle-ci va tuer les performances. Ouvrez SQL Profiler et regardez ce qui se passe lorsque vous utilisez une fonction scalaire qui appelle une table.

De plus, la technique de mise à jour d'une variable pour la concaténation n'est pas encouragée car cette fonctionnalité pourrait ne pas continuer dans les futures versions.

La méthode préférée de concaténation de chaînes pour utiliser FOR XML PATH à la place.

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; 

Pour des exemples de la façon dont pour les travaux XML PATH, considérez ce qui suit, en imaginant que vous avez une table avec deux champs appelés 'id' et 'nom'

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

donne:

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

Mais si vous omettez la racine, vous obtenez quelque chose de légèrement différent:

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> 

Et si vous mettez une chaîne de chemin vide, vous obtenez encore plus proche de la concaténation de chaîne ordinaire:

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

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

est maintenant le peu vraiment difficile ... Si vous nommez une colonne en commençant par un signe @, il devient un attribut, et si une colonne ne dispose pas d'un nom (ou vous l'appelez [*]), il laisse à cette étiquette aussi:

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

,Aardvark,Zebra 

maintenant, enfin, à dépouiller la virgule de premier plan, la commande STUFF entre. STUFF (s, x, n, s2) enlève n caractères de s, en commençant à la position x. À leur place, ça met s2.Donc:

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

donne:

a123456e

ont donc maintenant un coup d'œil à ma requête ci-dessus pour votre taglist.

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; 

Pour chaque photo, j'ai une sous-requête qui saisit les balises et les concaténer (dans l'ordre) avec un commma et un espace. Ensuite, j'entoure cette sous-requête dans une commande stuff pour supprimer la virgule et l'espace.

Je m'excuse pour les fautes de frappe - Je n'ai pas créé les tables sur ma propre machine pour le tester.

Rob

+0

+ 1 pour l'effort, mais ça renvoie en fait du XML, ce que je ne veux pas. pour quelque raison, il change votre 'SELECT' original, '+ nom d'utilisateur' à 'SELECT TOP (100) PERCENT', '+ dbo.users.username AS tags' ... – Jason

+0

Débarrassez-vous de" as tags ". Et ne le mettez pas dans une fonction. Exécutez-le tel quel. Qu'avez-vous réellement exécuté? –

+0

Je ne peux pas me débarrasser du "as" car il met "comme Expr1" par défaut, et je ne l'ai pas exécuté en tant que fonction. J'ai couru comme une requête SQL standard: \ – Jason

Questions connexes