Wie kann ich kombinieren CTEs mit einer FOR XML-Klausel?
-
09-10-2019 - |
Frage
Ich versuche, einige XML mit verschiedenen Ebenen der Verschachtelung zu erzeugen und auf die Gefahr von Über vereinfachen, wird die XML-Ausgabe lose von dem Format:
<invoice number="1">
<charge code="foo" rate="123.00">
<surcharge amount="10%" />
</charge>
<charge code="bar" />
</invoice>
Das Datenbankschema Ich habe für diesen geerbt geschieht Gebühren in unterschiedlichen Tabellen gespeichert haben, was bedeutet, dass Zuschläge unterschiedlich auf dem Tisch abgelegt basiert, von wo aus der Ladung war aus.
Da Sie nicht UNION
s mit FOR XML
verwenden können, habe ich einige UNION
ing in einem WAK getan, so etwas in der Zeilen:
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
Nun, das ist unglaublich in der Nähe, so dass (Beachten Sie die verschachtelte <surcharge>
):
<invoice number="1">
<charge code="foo" rate="123.00">
<surcharge>
<surcharge amount="10%" />
</surcharge>
</charge>
<charge code="bar" />
</invoice>
Aber ich brauche einen Weg, um die End-Abfrage finden der Wert einer XML-Spalte zu schließen, wenn der Gehalt des Elements behandelt zu werden, und nicht als ein neues Element. Ist dies möglich, oder muss ich einen neuen Ansatz nehmen?
Lösung 2
Es scheint, dass die (falsche) Spalte Benennung als „*“, dass der Inhalt dieser Spalte als Inhalt des Elements zu verwenden, so die SQL ändern, wie unten macht es Arbeit:
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
Andere Tipps
Sie haben eine Spalte Abfrage, die mulitple Zeilen zurückgibt ich die Abfrage Sie Beiträge verfassen erwarten würde, den Fehler zu geben (@charge, @rate und einen XML-Typen.):
Nur ein Ausdruck kann angegeben werden in der Auswahlliste, wenn die Unterabfrage nicht mit EXISTS eingeführt.
Allerdings, das ist festgelegt leicht durch die Abfrage zu einem outer apply
bewegen. Um die Doppel surcharge
Element zu entfernen, können Sie die XML-Spaltennamen so weit nach unten wie möglich, wie bewegen:
;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
Dies würde drucken, zum Beispiel:
<invoice number="1">
<charge code="1" rate="1" />
</invoice>
<invoice number="1">
<charge code="1" rate="1">
<surcharge amount="1" />
</charge>
</invoice>
Das erste Element kommt aus dem oberen Teil der Union, wo surcharge = null
.
Ich glaube, Sie können dies tun, indem Sie den Wurzelknotentyp in Ihrer „für XML-Pfad (‚Aufschlag‘)“ Erklärung weggelassen wird. Das heißt, die Verwendung "für XML-Pfad ( '')" statt.