SQL Server 2005「FOR XML PATH」グループ化
-
22-07-2019 - |
質問
「FOR XML」を使用して、SQL Server 2005データベースからXMLドキュメントを生成しようとしています。構成します。
データベースには、1対多の関係を持つ2つの単純なテーブルがあります。
1)雑誌
| Id | Number | Name |
----------------------------
| 53 | 0001 | Magazine 1 |
| 54 | 0002 | Magazine 2 |
| 55 | 0003 | Magazine 3 |
2)記事
| 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 |
サイズが1000を超える記事を持つすべての雑誌を検索する必要があると仮定しましょう そして、次のxmlを生成します。
<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>
&quot; PATH&quot;を使用してこのようなxmlを生成しようとしています。モード:
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
次のxmlが生成されます。
<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>
したがって、Id =&quot; 54&quot;の雑誌には2つの要素があります。 (各記事に1つ)、これが問題です。
次のようなサブクエリを使用してクエリを書き換えることができます。
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
そして、これにより次の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>
ただし、サブクエリを使用すると、記事の列で雑誌をフィルタリングできません(複雑な追加クエリなし)。
&quot; FOR XML AUTO&quot;モードは非常に単純で、一部の&quot; PATH&quot;をサポートしないため、適切ではありません。機能(@、ROOTなどを使用した属性など)
では、&quot; PATH&quot;に可能性はありますか? &quot; AUTO&quot;のような内部テーブルデータをグループ化するモードモード?
ありがとう!
解決
さて、&quot;サイズ&gt; 1000&quot;サブクエリ内:
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
今欠けているのは、サイズのある記事のない雑誌を引き続き入手できるということです&gt; 1000.次のようなものを削除できます:
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
(テストされていませんが、現在SQLサーバーは手元にありません)
それはあなたのために働きますか?お探しの雑誌や記事はありますか?
マーク
他のヒント
明示的なFOR XMLを使用します。記述するのに最も長いコードですが、サブクエリによって引き起こされるパフォーマンスの問題はなくなります。