2011-01-10 11 views
4

私は、ネストのさまざまなレベルでいくつかのXMLを生成しようとしている、とオーバー簡素化の危険にさらされて、出力XML形式で緩くなります。CTEとFOR XML句を組み合わせるにはどうすればよいですか?

<invoice number="1"> 
<charge code="foo" rate="123.00"> 
    <surcharge amount="10%" /> 
</charge> 
<charge code="bar" /> 
</invoice> 

私はこのために継承しているデータベーススキーマ別のテーブルに課金されていることがあります。つまり課金元のテーブルに基づいて課金される課金額が異なります。

はあなたcannot use UNIONs with FOR XMLが、私はいくつかのUNIONはCTEにINGのやったことを考えると、それほどの線に沿って何か:今

WITH Charges ([@code], [@rate], surcharge, InvoiceId) AS (
    SELECT code AS [@Code], amount AS [@rate], NULL as surcharge, InvoiceId 
    FROM item.charges 
UNION ALL 
    SELECT 
     code AS [@Code], 
     amount AS [@rate], 
     (
      SELECT amount AS [@amount] 
      FROM order.surcharges os 
      WHERE oc.ChargeId = os.ChargeId 
      FOR XML PATH('surcharge'), TYPE 
     ), 
     InvoiceId 
    FROM order.charges oc 
) 
SELECT 
    Number AS [@number], 
    (
     SELECT 
      [@code], 
      [@rate], 
      surcharge 
     FROM Charges 
     WHERE Charges.InvoiceId = i.InvoiceId 
    ) 
FROM Invoices i 
FOR XML PATH('invoice'), TYPE 

は、それは(ネストされた<surcharge>注)与え、信じられないほど近いです:

<invoice number="1"> 
<charge code="foo" rate="123.00"> 
    <surcharge> 
    <surcharge amount="10%" /> 
    </surcharge> 
</charge> 
<charge code="bar" /> 
</invoice> 

しかし、私は、要素の内容としてではなく、新しい要素として扱われるXML列の値が含まれるように、エンドクエリを取得する方法を見つける必要があります。これは可能ですか、新しいアプローチをとる必要がありますか?

答えて

1

「*」要素の内容として、その列の内容は、ように、以下のSQLを変更すると、それが仕事になることを利用すると(偽の)列に名前を付けることが表示されます:

WITH Charges ([@code], [@rate], surcharge, InvoiceId) AS (
    SELECT code AS [@Code], amount AS [@rate], NULL as surcharge, InvoiceId 
    FROM item.charges 
UNION ALL 
    SELECT 
     code AS [@Code], 
     amount AS [@rate], 
     (
      SELECT amount AS [@amount] 
      FROM order.surcharges os 
      WHERE oc.ChargeId = os.ChargeId 
      FOR XML PATH('surcharge'), TYPE 
     ), 
     InvoiceId 
    FROM order.charges oc 
) 
SELECT 
    Number AS [@number], 
    (
     SELECT 
      [@code], 
      [@rate], 
      surcharge AS [*] -- Thsi will embed the contents of the previously generated XML in here. 
     FROM Charges 
     WHERE Charges.InvoiceId = i.InvoiceId 
    ) 
FROM Invoices i 
FOR XML PATH('invoice'), TYPE 
+0

サブクエリがEXISTSとともに導入されていない場合、選択リストで指定できる式は1つだけです。 – user3752281

+0

@ user3752281その解決策は私のために働いたので、私はあなたのコメントを理解していないのですか? –

0

私はあなたの "for XML Path( 'surcharge')"ステートメントでルートノードタイプを省略することでこれを行うことができると思います。つまり、代わりに "for XML Path( '')"を使用します。

+0

が得られることエラー:「行タグの省略(空の行タグ名)は、属性中心のXMLシリアル化では使用できません。」 –

+0

+1ユニオンの上部に追加料金が暗示的に追加料金として追加されているので、パス( 'surgicalcharge')が重複して見える – Andomar

+0

そのエラーで混乱します。私が提案したように、 "for xml"句であなた自身のユニオンで2番目の選択を実行するとどうなりますか? –

1

あなたはmulitple行を返す列クエリ持っている私はあなたがエラーを与えるためにPostクエリ期待(@charge、@rate、およびXMLタイプを。):

Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

をしかし、それは簡単に固定されますクエリをouter applyに移動します。これは、例えば、印刷し

;WITH Charges (code, rate, surcharge, InvoiceId) AS 
    (
    SELECT code, amount, NULL, InvoiceId 
    FROM @charges 
    UNION ALL 
    SELECT code 
    ,  amount 
    ,  (
      SELECT amount AS [@amount] 
      FROM @surcharges os 
      WHERE oc.ChargeId = os.ChargeId 
      FOR XML PATH('surcharge'), TYPE 
      ) 
    ,  InvoiceId 
    FROM @charges oc 
) 
SELECT Number AS [@number] 
,  c.code as [charge/@code] 
,  c.rate as [charge/@rate] 
,  c.surcharge as [charge] 
FROM @Invoices i 
outer apply 
     (
     SELECT code 
     ,  rate 
     ,  surcharge 
     FROM Charges 
     WHERE Charges.InvoiceId = i.InvoiceId 
     ) c 
WHERE i.InvoiceID = 1 
FOR XML PATH('invoice'), TYPE 

<invoice number="1"> 
    <charge code="1" rate="1" /> 
</invoice> 
<invoice number="1"> 
    <charge code="1" rate="1"> 
    <surcharge amount="1" /> 
    </charge> 
</invoice> 

最初の要素がから来て、二重surcharge要素を削除するには、次のように、できるだけ下に限りXMLの列名を移動することができます組合の上部は、surcharge = nullです。

関連する問題