Как я могу объединить CTE с A для XML-предложений?
-
09-10-2019 - |
Вопрос
Я пытаюсь сгенерировать некоторые XML с различными уровнями вложения, а на риск превышения упрощения выходной сигнал XML будет свободно от формата:
<invoice number="1">
<charge code="foo" rate="123.00">
<surcharge amount="10%" />
</charge>
<charge code="bar" />
</invoice>
Схема базы данных, которую я унаследовал для этого, произошло, имеющие сборы, хранящиеся в разных таблицах, что означает, что доплаты хранятся по-разному на основе таблицы, откуда заряд.
Учитывая, что вы не можете использовать UNION
с 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, которая будет рассматриваться как содержание элемента, а не как новый элемент. Это возможно, или мне нужно сделать новый подход?
Решение 2
Похоже, что называя (подделка) столбца как «*» будет использовать то, что содержимое этого столбца в качестве содержания элемента, поэтому изменение 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
Другие советы
У вас есть столбец, который возвращает MULITPLE ROAWS (@ @ @ @ @RATE и тип XML.) Я ожидал, что вы опубликовал запрос, чтобы дать ошибку:
Только одно выражение может быть указано в списке выбора, когда подзапрос не вводится с существующими.
Тем не менее, это легко исправлено, перемещая запрос на 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
.
Я думаю, что вы можете сделать это, пропустив тип корневого узла в своем операторе «для XML Path ('Surch')». То есть используйте «для XML Path ('')» вместо этого.