2010-12-04 5 views
5

Comment transformer un champ de liste de virgules en ligne et l'afficher dans une colonne?TSQL Sélectionner la liste des virgules dans les rangées

Par exemple,

ID | Colour 
------------ 
1 | 1,2,3,4,5 

à:

ID | Colour 
------------ 
1 | 1 
1 | 2 
1 | 3 
1 | 4 
1 | 5 
+0

et une question qui a été posée plusieurs fois auparavant ... un tel exemple: http://stackoverflow.com/questions/4250475/split-one-column-into-multiple-rows –

+0

@Mark Byers: Cette base de données Le design est optimisé pour stocker des listes à partir de quelque chose comme un site web PHP. C'est horrible pour les gens SQL mais pratique pour les développeurs frontaux. – Andomar

Répondre

5

La manière habituelle de résoudre ce problème est de créer une fonction split. Vous pouvez en obtenir un de Google, par exemple this one from SQL Team. Une fois que vous avez créé la fonction, vous pouvez l'utiliser comme:

create table colours (id int, colour varchar(255)) 
insert colours values (1,'1,2,3,4,5') 

select colours.id 
,  split.data 
from colours 
cross apply 
     dbo.Split(colours.colour, ',') as split 

Cette impression:

id data 
1  1 
1  2 
1  3 
1  4 
1  5 
+0

sélectionnez dbo.XW_Wheels.ID, dbo.Splitter (XW_Wheels.Colours, ' ') de XW_Wheels croisée se dbo.Splitter (XW_Wheels.Colours,',') comme Split et je reçois ce message « Vous ne trouvez pas non plus colonne "dbo" ou la fonction définie par l'utilisateur ou l'agrégat "dbo.Splitter", ou le nom est ambigu. " – Rya

+0

sélectionnez dbo.XW_Wheels.ID, diviser de XW_Wheels croisée se dbo.Splitter (XW_Wheels.Colours, '') comme divisée et je reçois "nom de colonne non valide 'divisé'." – Rya

+0

La fonction 'dbo.Split' renvoie une table. Essayez de sélectionner 'split.data' au lieu de simplement' split'. – Andomar

2

Une autre solution possible est d'utiliser XML (en supposant que travaillent avec SQL Server 2005 ou plus):

DECLARE @s TABLE 
    (
     ID INT 
    , COLOUR VARCHAR(MAX) 
    ) 

INSERT INTO @s 
VALUES (1, '1,2,3,4,5') 

SELECT s.ID, T.Colour.value('.', 'int') AS Colour 
FROM (SELECT ID 
        , CONVERT(XML, '<row>' + REPLACE(Colour, ',', '</row><row>') + '</row>') AS Colour 
      FROM  @s a 
     ) s 
     CROSS APPLY s.Colour.nodes('row') AS T(Colour) 
+0

mieux encore: SELECT T.name.value ('.' 'Nvarchar (4000)') AS Couleur FROM (SELECT CONVERT (XML, '' + REPLACE (nom,', '' ') +' ') AS Nom FROM (SELECT' 1, Nom de 2,3,4,5 ') a ) s CROSS APPLIQUER s.Noms.Nodes (' row ') AS T (nom) – kerem

1

Je sais que c'est un post plus ancien mais j'ai pensé ajouter une mise à jour. La table de pointage et les séparateurs basés sur la table CTETally ont tous un problème majeur. Ils utilisent des délimiteurs concaténés et cela tue leur vitesse quand les éléments s'élargissent et que les cordes s'allongent.

J'ai corrigé ce problème et j'ai écrit un article à ce sujet qui se trouve à l'URL suivant. http://www.sqlservercentral.com/articles/Tally+Table/72993/

La nouvelle méthode souffle les portes hors de tout en boucle, CTE récursive et méthodes XML pour VARCHAR (8000).

Je vous dirai aussi qu'un gars du nom de "Peter" a fait une amélioration même à ce code (dans la discussion pour l'article). L'article est toujours intéressant et je mettrai à jour les pièces jointes avec les améliorations de Peter dans les prochains jours. Entre mon amélioration majeure et le tweet de Peter, je ne crois pas que vous trouverez une solution T-SQL-Only plus rapide pour scinder VARCHAR (8000). J'ai également résolu le problème pour cette race de séparateurs pour VARCHAR (MAX) et je suis en train d'écrire un article pour ça aussi.