Как я могу объединить CTE с предложением FOR XML? - PullRequest
4 голосов
/ 10 января 2011

Я пытаюсь сгенерировать некоторый XML с различными уровнями вложенности, и с риском чрезмерного упрощения выходной XML будет свободно иметь формат:

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

В схеме базы данных, которую я унаследовал для этого, сборы хранятся в разных таблицах, что означает, что сборы хранятся по-разному в зависимости от таблицы, откуда был сбор.

Учитывая, что вы не можете использовать UNION s с FOR XML, я сделал некоторые UNION в CTE, поэтому что-то вроде:

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, который будет рассматриваться как содержимое элемента, а не как новый элемент. Возможно ли это, или мне нужен новый подход?

Ответы [ 3 ]

1 голос
/ 10 января 2011

У вас есть запрос столбца, который возвращает несколько строк (@charge, @rate и тип XML). Я ожидаю, что запрос, который вы публикуете, выдаст ошибку:

Только одно выражение можетбыть указанным в списке выбора, когда подзапрос не введен с EXISTS.

Однако это легко исправить, переместив запрос в outer apply.Чтобы удалить двойной элемент surcharge, вы могли бы переместить имена столбцов XML как можно дальше вниз, например:

;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 = null.

1 голос
/ 10 января 2011

Похоже, что имя (поддельный) столбец как "*" будет использовать это содержимое этого столбца в качестве содержимого элемента, поэтому изменение 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 голосов
/ 10 января 2011

Я думаю, что вы можете сделать это, пропустив тип корневого узла в вашем выражении "for xml path ('surcharge')" То есть вместо этого используйте «для пути xml ('')».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...