如何将 CTE 与 FOR XML 子句结合起来?

Row*_*haw 5 t-sql for-xml common-table-expression sql-server-2008

我正在尝试生成一些具有不同嵌套级别的 XML,并且冒着过度简化的风险,输出 XML 将采用松散的格式:

<invoice number="1">
 <charge code="foo" rate="123.00">
  <surcharge amount="10%" />
 </charge>
 <charge code="bar" />
</invoice>
Run Code Online (Sandbox Code Playgroud)

我为此继承的数据库模式恰好将费用存储在不同的表中,这意味着附加费根据费用来源的表以不同的方式存储。

鉴于您不能将s 与 一起使用UNIONFOR 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
Run Code Online (Sandbox Code Playgroud)

现在,这非常接近,给出(注意嵌套<surcharge>):

<invoice number="1">
 <charge code="foo" rate="123.00">
  <surcharge>
   <surcharge amount="10%" />
  </surcharge>
 </charge>
 <charge code="bar" />
</invoice>
Run Code Online (Sandbox Code Playgroud)

但我需要找到一种方法,使最终查询包含 XML 列的值,并将其视为元素的内容,而不是新元素。这是可能的,还是我需要采取新的方法?

Row*_*haw 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
Run Code Online (Sandbox Code Playgroud)