Comment puis-je combiner avec une clause CTEs XML FOR?
-
09-10-2019 - |
Question
Je suis en train de générer des XML avec différents niveaux d'imbrication, et au risque de trop simplifier, le XML de sortie sera lâchement du format:
<invoice number="1">
<charge code="foo" rate="123.00">
<surcharge amount="10%" />
</charge>
<charge code="bar" />
</invoice>
Le schéma de base de données que j'ai hérité de ce qui arrive à avoir des charges stockées dans des tables différentes, ce qui signifie que les suppléments sont stockés différemment selon la table où la charge était.
Étant donné que vous ne pouvez pas utiliser UNION
s avec FOR XML
, je l'ai fait quelques UNION
ing dans un CTE, donc quelque chose le long de la lignes de:
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
, qui est très à proximité, ce qui donne (Notez le <surcharge>
imbriquée):
<invoice number="1">
<charge code="foo" rate="123.00">
<surcharge>
<surcharge amount="10%" />
</surcharge>
</charge>
<charge code="bar" />
</invoice>
Mais je dois trouver un moyen d'obtenir la requête de fin d'inclure la valeur d'une colonne XML à traiter comme le contenu de l'élément, plutôt que comme un nouvel élément. Est-ce possible, ou dois-je prendre une nouvelle approche?
La solution 2
Il semble que nommer le (faux) colonne comme « * » utilisera que le contenu de cette colonne que le contenu de l'élément, en changeant ainsi le SQL comme ci-dessous fait fonctionner:
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
Autres conseils
Vous avez une requête de colonne qui renvoie des lignes mulitple j'attendre la requête que vous postez pour donner l'erreur (@charge, @rate, et un type XML.):
Une seule expression peut être spécifiée dans la liste de sélection lorsque la sous-requête n'est pas introduite par exists.
Cependant, qui est facilement corrigé en déplaçant la requête à un outer apply
. Pour supprimer la double élément surcharge
, vous pouvez déplacer les noms de colonnes XML jusqu'à au fond que possible, comme:
;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
imprimerait, par exemple:
<invoice number="1">
<charge code="1" rate="1" />
</invoice>
<invoice number="1">
<charge code="1" rate="1">
<surcharge amount="1" />
</charge>
</invoice>
Le premier élément provient de la partie supérieure de l'Union, où surcharge = null
.
Je pense que vous pouvez le faire en supprimant le type de nœud racine dans votre déclaration « pour le chemin xml ( 'en supplément) ». Autrement dit, l'utilisation "pour le chemin xml ( '')" à la place.