SQL Server 2005 „FOR XML PATH“ Gruppieren
-
22-07-2019 - |
Frage
Ich versuche, mithilfe von "FOR XML" ein XML-Dokument aus der SQL Server 2005-Datenbank zu generieren konstruieren.
Es gibt zwei einfache Tabellen in der Datenbank mit einem Eins-zu-viele-Beziehung:
1) Zeitschriften
| Id | Number | Name |
----------------------------
| 53 | 0001 | Magazine 1 |
| 54 | 0002 | Magazine 2 |
| 55 | 0003 | Magazine 3 |
2) Artikel
| 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 |
Nehmen wir an, ich alle Zeitschriften finden, die einen Artikel mit einer Größe von mehr als 1000 haben und die folgenden XML zu erzeugen:
<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>
Ich versuche, solche XML zu erzeugen, indem eine „PATH“ Modus:
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
Es wird die folgende XML erzeugen:
<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>
Es gibt also zwei Elemente für die Magazine mit Id = „54“ (einem für jeden Artikel), und das ist das Problem.
Ich kann die Abfrage mit einer Unterabfrage wie folgt umschreiben:
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
Und diese produzieren die folgende xml:
<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>
Aber durch eine Unterabfrage kann ich nicht Zeitschriften von Artikel Säulen (ohne komplexe zusätzliche Abfragen) filtern.
Der "FOR XML AUTO" -Modus ist nicht geeignet, weil es sehr einfach ist und nicht einige "PATH" Merkmale (wie Attribute mit @, ROOT, etc ..)
unterstütztSo, Gibt es eine Möglichkeit, in "PATH" -Modus Gruppe innerer Tabellendaten wie in "AUTO" -Modus?
Danke!
Lösung
Nun können Sie einen Schritt näher kommen, indem die „Größe> 1000“ innerhalb Ihrer Unterabfrage festgelegt wird:
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
Was Sie jetzt fehlt, ist die Tatsache Sie noch Zeitschriften, die keine Artikel mit einer Größe haben bekommen> 1000. Sie können diese so etwas wie dieses beseitigen:
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
(ungetestet, ich habe nicht einen SQL-Server zur Hand jetzt haben).
Ist für Sie das? Macht es Ihnen die Zeitschriften und Artikel Sie suchen?
Marc
Andere Tipps
Verwenden Sie FOR XML explizit. Am längsten ist, Code zu schreiben, aber die Performance-Probleme provozieren von Unterabfragen zu verschwinden.