SQL: SELECT Imbriquée avec plusieurs valeurs dans un champ unique
Dans mon SQL 2005 DB, j'ai un tableau avec des valeurs stockées en tant que Id avec des relations avec d'autres tables. Donc, à mon MyDBO.garantie table, je suis le stockage product_id au lieu de produit_nom, afin d'économiser de l'espace. Le produit_nom est stocké dans MyDBO.produits.
Lorsque le service marketing tire les informations démographiques, la requête sélectionne le nom correspondant pour chaque ID de tables liées (réduite pour des raisons de concision):
SELECT w1.warranty_id AS "No.",
w1.created AS "Register Date"
w1.full_name AS "Name",
w1.purchase_date AS "Purchased",
(
SELECT p1.product_name
FROM WarrDBO.products p1 WITH(NOLOCK)
WHERE p1.product_id = i1.product_id
) AS "Product Purchased",
i1.accessories
FROM WarrDBO.warranty w1
LEFT OUTER JOIN WarrDBO.warranty_info i1
ON i1.warranty_id = w1.warranty_id
ORDER BY w1.warranty_id ASC
Maintenant, mon problème, c'est que les "accessoires" de la colonne sur la warranty_info table stocke plusieurs valeurs:
No. Register Date Name Purchased Accessories
---------------------------------------------------------------------
1500 1/1/2008 Smith, John Some Product 5,7,9
1501 1/1/2008 Hancock, John Another 2,3
1502 1/1/2008 Brown, James And Another 2,9
J'ai besoin de faire quelque chose de similaire avec les "Accessoires" que j'ai fait avec "Produit" et de tirer accessory_name de la MyDBO.accessoires table à l'aide de accessory_id. Je ne suis pas sûr où commencer, parce que d'abord j'avais besoin d'extraire les Id et puis en quelque sorte concaténer plusieurs valeurs dans une chaîne de caractères. De sorte que chaque ligne aurait "accessoryname1,accessoryname2,accessoryname3":
No. Register Date Name Purchased Accessories
---------------------------------------------------------------------
1500 1/1/2008 Smith, John Some Product Case,Bag,Padding
1501 1/1/2008 Hancock, John Another Wrap,Label
1502 1/1/2008 Brown, James And Another Wrap,Padding
Comment puis-je faire cela?
EDIT>> Poster mon code final:
J'ai créé cette fonction:
CREATE FUNCTION SQL_GTOInc.Split
(
@delimited varchar(50),
@delimiter varchar(1)
) RETURNS @t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id INT identity(1,1), -- I use this column for numbering splitted parts
val INT
)
AS
BEGIN
declare @xml xml
set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'
insert into @t(val)
select
r.value('.','varchar(5)') as item
from @xml.nodes('//root/r') as records(r)
RETURN
END
Et mis à jour mon code en conséquence:
SELECT w1.warranty_id,
i1.accessories,
(
CASE
WHEN i1.accessories <> '' AND i1.accessories <> 'NULL' AND LEN(i1.accessories) > 0 THEN
STUFF(
(
SELECT ', ' + a1.accessory
FROM MyDBO.accessories a1
INNER JOIN MyDBO.Split(i1.accessories, ',') a2
ON a1.accessory_id = a2.val
FOR XML PATH('')
), 1, 1, ''
)
ELSE ''
END
) AS "Accessories"
FROM MyDBO.warranty w1
LEFT OUTER JOIN MyDBO.warranty_info i1
ON i1.warranty_id = w1.warranty_id
Je suis d'accord, c'est ce que j'aurais fait si j'avais construit la structure. Malheureusement, la DB auteur était en train de faire tout ce qu'il pouvait pour économiser de l'espace, et ce fut l'une des méthodes qu'il utilise.
J'apprécie toute l'aide les gars, et si je pouvais choisir plus d'une réponse, je le ferais. Apparemment, j'étais juste ne pas lire assez attentivement et à gauche hors de la
FOR XML PATH('')
dans ma déclaration, l'origine de l'erreur. J'ai appliqué toutes les suggestions, et il ne fonctionne pas parfaitement.OriginalL'auteur Dexter | 2011-04-01
Vous devez vous connecter pour publier un commentaire.
Vous pouvez écrire une fonction à valeur de table que tout simplement divise séparées par des virgules chaîne en XML et tourne les nœuds XML pour les lignes.
Voir:
http://www.kodyaz.com/articles//t-sql-convert-split-delimeted-string-as-rows-using-xml.aspx
Se joindre à des accessoires à travers le résultat de l'appel de fonction, et d'autres choses, le résultat retour à la liste séparée par des virgules de noms.
Code non testé:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Si j'ai mis une clause where et seulement de sélectionner un simple accessoire de la liste, il fonctionne très bien. Je ne pense pas qu'il va me laisser utiliser la fonction dans une sous-requête en tant que partie d'un TRUC()OriginalL'auteur Sean
Rien à voir avec votre question. Juste une remarque que l'original de votre requête peut aussi être écrite, le déplacement de la subqery à une jointure, comme:
Une sous-requête dans la
SELECT
liste peut généralement être transformé en unLEFT
rejoindre. PasINNER
rejoindre.OriginalL'auteur ypercubeᵀᴹ
Vous avez juste besoin d'utiliser le POUR XML fonctionnalité de SQL Server facilement chat chaînes:
Exemple de la lié billet de blog:
Pour analyser un domaine qui a déjà été enregistré en tant que délimité par des virgules, vous devez écrire une fonction qui analyse le terrain et retourne un tableau qui peut ensuite être utilisé avec un prédicat dans votre clause where. Regarder ici pour commencer, et ici.
Merci, je vais regarder à travers.
OriginalL'auteur Paul Sasik
Il semble être un travail pour un concaténer fonction d'agrégation.
En SQL, il peut être déployé à l'aide de CLR
http://www.mssqltips.com/tip.asp?tip=2022
OriginalL'auteur pcofre