SQL Server 2005 & # 8220; FOR XML PATH & # 8221; Regroupement
-
22-07-2019 - |
Question
J'essaie de générer un document XML à partir de la base de données SQL Server 2005 à l'aide de "FOR XML". construire.
Il y a deux tables simples dans la base de données avec une relation un à plusieurs:
1) Magazines
| Id | Number | Name |
----------------------------
| 53 | 0001 | Magazine 1 |
| 54 | 0002 | Magazine 2 |
| 55 | 0003 | Magazine 3 |
2) Articles
| Id | Title | MagazineId | Size |
--------------------------------------
| 1 | Article 1 | 53 | 1205 |
| 2 | Article 2 | 53 | 817 |
| 3 | Article 3 | 54 | 1570 |
| 4 | Article 4 | 54 | 2510 |
| 5 | Article 5 | 55 | 910 |
Supposons que je dois trouver tous les magazines qui ont un article dont la taille est supérieure à 1000. et pour produire le XML suivant:
<Magazines>
<Magazine Id="53">
<Number>0001</Number>
<Articles>
<Article Id="1">
<Title>Article 1</Title>
<Size>1205</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="3">
<Title>Article 3</Title>
<Size>1570</Size>
</Article>
<Article Id="4">
<Title>Article 4</Title>
<Size>2510</Size>
</Article>
</Articles>
</Magazine>
</Magazines>
J'essaie de produire un tel fichier XML en utilisant un "PATH". mode:
SELECT Magazines.Id AS "@Id",
Magazines.Number AS "Number",
Articles.Id AS "Articles/Article/@Id",
Articles.Title AS "Articles/Article/Title",
Articles.Size AS "Articles/Article/Size"
FROM Magazines INNER JOIN Articles ON Magazines.Id = Articles.MagazineId
WHERE Articles.Size > 1000
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
Il produira le code XML suivant:
<Magazines>
<Magazine Id="53">
<Number>0001</Number>
<Articles>
<Article Id="1">
<Title>Article 1</Title>
<Size>1205</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="3">
<Title>Article 3</Title>
<Size>1570</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="4">
<Title>Article 4</Title>
<Size>2510</Size>
</Article>
</Articles>
</Magazine>
</Magazines>
Il y a donc deux éléments pour le magazine avec Id = "54" (un pour chaque article) et c’est le problème.
Je peux réécrire la requête en utilisant une sous-requête comme celle-ci:
SELECT M.Id AS "@Id",
M.Number AS "Number",
(SELECT Articles.Id AS "@Id",
Articles.Title AS "Title",
Articles.Size AS "Size"
FROM Articles
WHERE Articles.MagazineId = M.Id
FOR XML PATH('Article'), ROOT('Articles'), TYPE
)
FROM Magazines AS M
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
Et cela produit le XML suivant:
<Magazines>
<Magazine Id="53">
<Number>0001</Number>
<Articles>
<Article Id="1">
<Title>Article 1</Title>
<Size>1205</Size>
</Article>
<Article Id="2">
<Title>Article 2</Title>
<Size>817</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="3">
<Title>Article 3</Title>
<Size>1570</Size>
</Article>
<Article Id="4">
<Title>Article 4</Title>
<Size>2510</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="55">
<Number>0003</Number>
<Articles>
<Article Id="5">
<Title>Article 5</Title>
<Size>910</Size>
</Article>
</Articles>
</Magazine>
</Magazines>
Mais en utilisant une sous-requête, je ne peux pas filtrer les magazines par colonnes d'articles (sans requêtes supplémentaires complexes).
Le fichier "FOR XML AUTO" Le mode n’est pas adapté, car il est très simple et ne prend pas en charge certains " PATH " fonctionnalités (comme les attributs utilisant @, ROOT, etc.)
Dans ce cas, existe-t-il une possibilité dans "PATH"? mode pour regrouper les données de la table interne comme dans "AUTO". mode?
Merci!
La solution
Eh bien, vous pouvez faire un pas de plus en spécifiant la " taille > 1000 " dans votre sous-requête:
SELECT M.Id AS "@Id",
M.Number AS "Number",
(SELECT Articles.Id AS "@Id",
Articles.Title AS "Title",
Articles.Size AS "Size"
FROM Articles
WHERE Articles.MagazineId = M.Id
AND Articles.Size > 1000
FOR XML PATH('Article'), ROOT('Articles'), TYPE
)
FROM Magazines AS M
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
Ce qui vous manque maintenant, c’est que vous aurez toujours des magazines sans articles de taille > 1000. Vous pouvez éliminer ceux qui ressemblent à ceci:
SELECT M.Id AS "@Id",
M.Number AS "Number",
(SELECT Articles.Id AS "@Id",
Articles.Title AS "Title",
Articles.Size AS "Size"
FROM Articles
WHERE Articles.MagazineId = M.Id
AND Articles.Size > 1000
FOR XML PATH('Article'), ROOT('Articles'), TYPE
)
FROM Magazines AS M
WHERE EXISTS(SELECT * FROM Articles
WHERE Articles.MagazineId = M.Id
AND Articles.Size > 1000)
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
(non testé, je n'ai pas de serveur SQL sous la main pour le moment).
Est-ce que cela fonctionne pour vous? Est-ce que cela vous donne les magazines et les articles que vous cherchez?
Marc
Autres conseils
Utilisez FOR XML explicitement. C’est le code le plus long à écrire mais à résoudre les problèmes de performances provoqués par les sous-requêtes.