XML output in SQL help needed - sql-server

Hi I have the following code in SQL that outputs xml between 2 tables. The output is 90% correct but if possible add to the output and then also remove some of the output text.
I am not sure if SQL has the ability to code a type of a element in the output. Please see the code below with the output. Currently if possible I would like to make 2 changes to my current output. The changes are list at the end of the port
DECLARE #ID_Rechnung int = 1978,
#XMLData xml;
WITH XMLNAMESPACES ('?xml version="1.0" encoding="UTF-8"?' as ext)
SELECT
#XMLData = xmldat.xmldataCol
FROM
(
SELECT (
SELECT
-- HIER XML Daten generieren
[InvoiceHeader].[InvoiceDate] AS 'invoice-date',
([InvoiceHeader].[InvoiceNumber]) AS 'invoice-number',
cast(replace([InvoiceHeader].[GrossValue],' ','') as decimal(18,2)) AS 'gross-total',
cast(replace([InvoiceHeader].[NetValue],' ','') as decimal(18,2)) AS 'amount-due',
[InvoiceHeader].[VatRate] AS 'tax-rate',
cast(replace([InvoiceHeader].[VatValue],' ','') as decimal(18,2)) AS 'tax-amount',
[ImagePath] AS 'image-scan-url',
[InvoiceType] AS 'document-type',
[LegalEntityVATNo] AS 'account-type/id',
[LegalEntityName] AS 'account-type/name',
[SupplierCode] as 'supplier/number',
[Currency] as 'currency/code',
(
SELECT rtrim([InvoiceLines].[LineNumber]) AS [order-line-num]
, [PONumber] as [po-number],
CAST([InvoiceLines].[UnitPrice] AS decimal(18,2)) AS Price ,
[Quantity] as quantity,
[TaxAmount] as [tax-amount],
[LineTotal] as [total],
[Decsription] as description
FROM [InvoiceLines] WHERE [InvoiceLines].[DOCID] = #id_Rechnung
FOR XML PATH('Invoice-line'), ROOT('invoice-lines'), TYPE
)
FROM [InvoiceHeader]
WHERE [InvoiceHeader].[DOCID] = #ID_Rechnung
FOR XML PATH(''), TYPE, ROOT('invoice-header')
) AS xmldataCol
) AS xmldat;
SELECT #XMLData
.query('<invoice-header>
{
for $x in /invoice-header/*[local-name()!="root"]
return $x,
for $x in /invoice-header/root/r
return <invoice-lines>/<invoice-line>{$x/*}</invoice-line></invoice-lines>
}
</invoice-header>');
Output:
<invoice-header>
<invoice-date>20180509</invoice-date>
<invoice-number>1075440</invoice-number>
<gross-total>1376.67</gross-total>
<amount-due>1197.10</amount-due>
<tax-rate>15.00%</tax-rate>
<tax-amount>179.57</tax-amount>
<image-scan-url>\\INTEL-SQL01\Attachment\2018-06-20\7e0dd165-81d6-445a-95d1-8aac686d44ed\f9a1179c-2a54-480e-b97a-ce6ac7327ae0.000</image-scan-url>
<account-type>
<id>4010112052</id>
<name>CONSOLIDATEDPOWERPROJECTS</name>
</account-type>
<supplier>
<number>12345</number>
</supplier>
<currency>
<code>ZAR</code>
</currency>
<invoice-lines xmlns:ext="?xml version="1.0" encoding="UTF-8"?">
<Invoice-line>
<order-line-num>4</order-line-num>
<po-number>120934861</po-number>
<Price>50.00</Price>
<quantity>1.000000</quantity>
<tax-amount>7.500000</tax-amount>
<total>50.00</total>
<description>Test1</description>
</Invoice-line>
<Invoice-line>
<order-line-num>2</order-line-num>
<po-number>120934861</po-number>
<Price>10.00</Price>
<quantity>2.000000</quantity>
<tax-amount>4.500000</tax-amount>
<total>20.00</total>
<description>Test2</description>
</Invoice-line>
</invoice-lines>
</invoice-header>
1.How do I get rid of the following xmlns:ext="?xml version="1.0" encoding="UTF-8&in the line: "<invoice-lines xmlns:ext="?xml version="1.0" encoding="UTF-8"?">"
How would I code "<tax-amount>7.500000</tax-amount> to get the output": "<tax-amount type="decimal">7.500000</tax-amount>"

Without a minimal reproducible example it is not possible to give you a full working answer.
(1) As #JeroenMostert already pointed out, the
'?xml version="1.0" encoding="UTF-8"?'
is an XML prolog declaration. Just delete the following line:
WITH XMLNAMESPACES ('?xml version="1.0" encoding="UTF-8"?' as ext)
(2) Here is a conceptual example how to add an attribute to an XML element. What is important here is a sequential order of adding, i.e. attribute shall be first, element itself is 2nd.
SQL
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, [tax-amount] VARCHAR(20));
INSERT INTO #tbl ([tax-amount]) VALUES
(N'7.500000'),
(N'18.000000');
SELECT
'decimal' AS [tax-amount/#type]
, [tax-amount]
FROM #tbl
FOR XML PATH('r'), TYPE, ROOT('root');
Output
<root>
<r>
<tax-amount type="decimal">7.500000</tax-amount>
</r>
<r>
<tax-amount type="decimal">18.000000</tax-amount>
</r>
</root>

Related

SQL Output as XML stop repeating the namespace

I'm using SSIS\SQL Server 2014 and am using the below SQL statement to output to XML.
In summary, 1 property can have many schedules. I only want the name space to appear once before the 'Job' XML path, however, if there are multiple schedules, then the namespace is also appearing in the xml output for each schedule - how do I stop this?
My code:
DECLARE #XMLOutput XML
DECLARE #XMLOutputChar nvarchar(max)
;WITH XMLNAMESPACES('http://www.example.com' as ns)
SELECT #XMLOutput =
(
SELECT
ISNULL(T1.[PropertyID],'') as PropertyId,
ISNULL(T1.[Desc],'') as JobDescription,
(
SELECT
ScheduleId as ScheduleId,
LocationID as LocationId,
FROM [JobSchedules]
WHERE T1.JobIdentity = JobIdentity
FOR XML PATH('JobSchedules'), TYPE
)
FROM [JobFile] T1
FOR XML PATH('Job'),TYPE,ROOT('JobLoader')
)
SET #XMLOutputChar = '<?xml version="1.0" encoding="UTF-8"?>' + CONVERT(nvarchar(max),#XMLOutput)
SELECT #XMLOutputChar AS XMLOutput
This is the desired output:
<?xml version="1.0" encoding="utf-8"?>
<JobLoader xmlns="http://www.example.com/" >
<Job>
<PropertyId>PROPERTYID</PropertyId>
<JobDescription>JOBDESCRIPTION</JobDescription>
<JobSchedules>
<JobSchedule>
<ScheduleId>SCHEDULEID</ScheduleId>
<LocationId>LOCATIONID</LocationId>
</JobSchedule>
</JobSchedules>
</Job>
</JobLoader>
What am I missing?
If anyone is interested I was able to resolve this by adding the below line to replace the value just after the encoding line:
SET #XMLOutputChar = REPLACE(#XMLOutputChar,'<JobSchedules xmlns:ns="http://www.example.com/"','<JobSchedules ')

SQL Server FOR XML with nested sub-select

The following sql code
SELECT
b.GivenName [Individual/Name/FirstName] ,
b.FamilyName [Individual/Name/LastName] ,
b.Address_Country [Individual/Address/CountryCode] ,
b.AddressFree [Individual/Address/AddressFree]
FROM dbo.stage_Clients_Merge b
WHERE b.DWHClientNo = #dwhclientNo
FOR XML PATH('Owner'), TYPE
will generate an xml fragment
<Owner>
<Individual>
<Name>
<FirstName>Bob</FirstName>
<LastName>Smith</LastName>
</Name>
<Address>
<CountryCode>US</CountryCode>
<AddressFree>123,Utah</AddressFree>
</Address>
</Individual>
</Owner>
If I extend this query to include a sub-query to return, for example, all the orders associated with a individual using the following:
(SELECT
c.OrderIdentificationNumber [Individual/OrderNumber]
FROM
dbo.stage_Customer_Orders c
WHERE
c.CustomerNo = b.masterClient
FOR
XML PATH(''), TYPE)
I will get the individual section twice. How can I combine the two to return the following?
<Owner>
<Individual>
<OrderNo>12345</OrderNo>
<OrderNo>23456</OrderNo>
<Name>
<FirstName>Bob</FirstName>
<LastName>Smith</LastName>
</Name>
<Address>
<CountryCode>US</CountryCode>
<AddressFree>123,Utah</AddressFree>
</Address>
</Individual>
</Owner>
Try it like this
I set up a mock-up scenario for stand-alone solutions. Next time you have a question, you might try this on your own. This makes it much easier to understand your issue and create a fully working and testable solution for it.
DECLARE #stage_Clients_Merge TABLE(ID INT,FirstName VARCHAR(100),LastName VARCHAR(100),CountryCode VARCHAR(100),AdressFree VARCHAR(100));
INSERT INTO #stage_Clients_Merge VALUES
(1,'Bob','Smith','US','123/Utah')
,(2,'Jim','Doh','US','123/Maryland');
DECLARE #orders TABLE(CustomerID INT, OrderNo INT)
INSERT INTO #orders VALUES
(1,11111),(1,12222)
,(2,21111),(2,22222);
SELECT (SELECT OrderNo FROM #orders WHERE CustomerID=b.ID FOR XML PATH(''),TYPE) AS Individual
,FirstName AS [Individual/Name/FirstName]
,LastName AS [Individual/Name/LastName]
,CountryCode AS [Individual/Address/CountryCode]
,AdressFree AS [Individual/Address/AdressFree]
FROM #stage_Clients_Merge AS b
FOR XML PATH('Owner');
You can use a subquery and [data()] to just get the column values with no additional nesting - then use path as before:
SELECT
(SELECT c.OrderIdentificationNumber as [data()]
FROM dbo.stage_Customer_Orders c
WHERE c.CustomerNo = b.masterClient
For XML Path('OrderNo'), type) as [Individual],
b.GivenName [Individual/Name/FirstName] ,
b.FamilyName [Individual/Name/LastName] ,
b.Address_Country [Individual/Address/CountryCode] ,
b.AddressFree [Individual/Address/AddressFree]
FROM dbo.stage_Clients_Merge b
WHERE b.DWHClientNo = #dwhclientNo
FOR XML PATH('Owner'), TYPE

SQL Server insert from a XML file

I'm trying to insert info from a XML file to a temporal table in SQL Server, but I can't get it.
First I declare a table variable, then I make an insert into this table, and the values come from an XML file, at the end I select data from the table variable that should have the info inserted before, but the select just returns an empty result without errors.
Any ideas?
This is the XML
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante Moneda="MXN" NumCtaPago="3746" LugarExpedicion="something" metodoDePago="03" tipoDeComprobante="ingreso" total="434.30" descuento="0.00" subTotal="402.14"
noCertificado="00001000000403736552" formaDePago="pago en una sola exhibición" sello="something" fecha="something" folio="something" serie="something" version="3.2" xsi:schemaLocation="http://something http://something" xmlns:xsi="http://something" xmlns:cfdi="http://something">
<cfdi:Addenda xsi:schemaLocation="https://something" xmlns:xsi="http://something" xmlns="https://something">
<ADDENDABENAVIDES>
<HEADERFACTURA INTNOTAENTRADA="something" STRREMISIONID="something" STRCLAVEFACTREM= "something" FLTIEPSFACTURA="something" FLTIVADESCUENTO="something" FLTDESCUENTOFACTURA="something" FLTBRUTOFACTURA="something" FLTIVAFACTURA="something" FLTNETOFACTURA="something" STRALMACENID="something" STRCENTROLOGISTICOID="something" DTMFECHAFACTURA="something" INTNOREGISTRO="something" STRFOLIO="something" STRSERIE="something" INTBODEGAID="something" INTMAYORISTAID="something" STRNUMEROPROVEEDOR="something"/>
<DETALLEFACTURA>
<DETALLEPRODUCTO />
</DETALLEFACTURA>
</ADDENDABENAVIDES>
</cfdi:Addenda>
</cfdi:Comprobante>
And this is from SQL
DECLARE #HEADERFACTURA TABLE
(
Id int IDENTITY(1,1),
[INTNOTAENTRADA] int,
[STRREMISIONID] NVARCHAR(max),
[STRCLAVEFACTREM] NVARCHAR(max),
[FLTIEPSFACTURA] decimal(10,2),
[FLTIVADESCUENTO] decimal(10,2),
[FLTDESCUENTOFACTURA] decimal(10,2),
[FLTBRUTOFACTURA] decimal(10,2),
[FLTIVAFACTURA] decimal(10,2),
[FLTNETOFACTURA] decimal(10,2),
[STRALMACENID] int,
[STRCENTROLOGISTICOID] NVARCHAR(max),
[DTMFECHAFACTURA] NVARCHAR(max),
[INTNOREGISTRO] int,
[STRFOLIO] int,
[STRSERIE] NVARCHAR(max),
[INTBODEGAID] int,
[INTMAYORISTAID] int,
[STRNUMEROPROVEEDOR] NVARCHAR(max)
)
;with xmlnamespaces('http://something' as cfdi)
INSERT INTO #HEADERFACTURA ([INTNOTAENTRADA], [STRREMISIONID],
[STRCLAVEFACTREM], [FLTIEPSFACTURA],
[FLTIVADESCUENTO], [FLTDESCUENTOFACTURA],
[FLTBRUTOFACTURA], [FLTIVAFACTURA],
[FLTNETOFACTURA], [STRALMACENID],
[STRCENTROLOGISTICOID], [DTMFECHAFACTURA],
[INTNOREGISTRO], [STRFOLIO],
[STRSERIE], [INTBODEGAID],
[INTMAYORISTAID], [STRNUMEROPROVEEDOR])
SELECT
X.Solicitud.query('INTNOTAENTRADA').value('.', 'int'),
X.Solicitud.query('STRREMISIONID').value('.', 'nvarchar(50)'),
X.Solicitud.query('STRCLAVEFACTREM').value('.', 'nvarchar(50)'),
X.Solicitud.query('FLTIEPSFACTURA').value('.', 'decimal(10,2)'),
X.Solicitud.query('FLTIVADESCUENTO').value('.', 'decimal(10,2)'),
X.Solicitud.query('FLTDESCUENTOFACTURA').value('.', 'decimal(10,2)'),
X.Solicitud.query('FLTBRUTOFACTURA').value('.', 'decimal(10,2)'),
X.Solicitud.query('FLTIVAFACTURA').value('.', 'decimal(10,2)'),
X.Solicitud.query('FLTNETOFACTURA').value('.', 'decimal(10,2)'),
X.Solicitud.query('STRALMACENID').value('.', 'int'),
X.Solicitud.query('STRCENTROLOGISTICOID').value('.', 'nvarchar(50)'),
X.Solicitud.query('DTMFECHAFACTURA').value('.', 'nvarchar(50)'),
X.Solicitud.query('INTNOREGISTRO').value('.', 'int'),
X.Solicitud.query('STRFOLIO').value('.', 'int'),
X.Solicitud.query('STRSERIE').value('.', 'nvarchar(50)'),
X.Solicitud.query('INTBODEGAID').value('.', 'int'),
X.Solicitud.query('INTMAYORISTAID').value('.', 'int'),
X.Solicitud.query('STRNUMEROPROVEEDOR').value('.', 'nvarchar(50)')
FROM
(SELECT
CAST (X AS XML)
FROM
OPENROWSET (BULK 'C:\aa.xml', SINGLE_BLOB) AS T(X)
) AS T(X)
CROSS APPLY
x.nodes('/cfdi:Comprobante/cfdi:Addenda/ADDENDABENAVIDES/HEADERFACTURA') AS X(Solicitud);
SELECT *
FROM #HEADERFACTURA
Thanks in advance.
You have a specific namespace and default namespace in your input xml. Fix the following line and you will get results:
CROSS APPLY
x.nodes('//cfdi:Comprobante/cfdi:Addenda/*:ADDENDABENAVIDES/*:HEADERFACTURA') AS X(Solicitud);
Take note that your query will still fail from your example because all of the attributes you are querying are strings and your query is casting them into types.
Also note, you can simplify each of your attribute statements as per this example:
X.Solicitud.query('STRNUMEROPROVEEDOR').value('.', 'nvarchar(50)') becomes
X.Solicitud.value('#STRNUMEROPROVEEDOR', 'nvarchar(50)')
Lastly, notice your xml is <?xml version="1.0" encoding="UTF-8"?>; I believe it should be <?xml version="1.0" encoding="UTF-16"?> since you are using accented characters. Your XML file may fail to parse.
In your attempt to provide an XML with cleaned data you went much to far...
Values, which should be numeric (e.g. int) show up as "Something", actually everything shows up as "something"...
Another problem is, that your namespaces are all set to the same URL.
Look at this (highly condensed) sample of your XML (the default namespace is in the second level!):
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://something" Moneda="MXN">
<cfdi:Addenda xmlns="https://Default">
<ADDENDABENAVIDES>
<HEADERFACTURA INTNOTAENTRADA="123" STRREMISIONID="something" />
<DETALLEFACTURA>
<DETALLEPRODUCTO />
</DETALLEFACTURA>
</ADDENDABENAVIDES>
</cfdi:Addenda>
</cfdi:Comprobante>
One more problem is, that your XML-file starts with a declaration with encoding="utf-8", but your content includes special characters. This declaration will be ommitted by SQL Server in any case, but you cannot read UTF-8 via NVARCHAR into XML. Therefore I read this into NVARCHAR(MAX), call REPLACE to introduce utf-16 and cast this to XML.
The next point is, that you want to read attributes, but you try to find them as elements.
You would query this like here:
;WITH XMLNAMESPACES(DEFAULT 'https://Default'
,'http://something' AS cfdi)
SELECT
--An attribute from <cfdi:Comprobante>
T.X.value('(/cfdi:Comprobante/#Moneda)[1]','nvarchar(max)') AS Moneda,
--Many attributes in <HEADERFACTURA>
X.Solicitud.value('#INTNOTAENTRADA', 'int') AS INTNOTAENTRADA,
X.Solicitud.value('#STRREMISIONID', 'nvarchar(50)') AS STRREMISIONID
FROM
(SELECT
CAST(REPLACE(CAST (X AS NVARCHAR(MAX)),'utf-8','utf-16') AS XML)
FROM
OPENROWSET (BULK 'C:\aa.xml', SINGLE_CLOB) AS T(X)
) AS T(X)
CROSS APPLY
x.nodes('/cfdi:Comprobante/cfdi:Addenda/ADDENDABENAVIDES/HEADERFACTURA') AS X(Solicitud);

Casting a field to XML, querying it returns NULL records

I've a field on my table that is nvarchar(max) and contains XML document. Don't ask why it is nvarchar(max) instead of XML because I don't know it.
By the way, here is an extraction of a sample XML:
<?xml version="1.0" encoding="utf-16"?>
<ItemType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AutoPay xmlns="urn:ebay:apis:eBLBaseComponents">true</AutoPay>
<Country xmlns="urn:ebay:apis:eBLBaseComponents">IT</Country>
<Currency xmlns="urn:ebay:apis:eBLBaseComponents">EUR</Currency>
<HitCounter xmlns="urn:ebay:apis:eBLBaseComponents">BasicStyle</HitCounter>
<ListingDuration xmlns="urn:ebay:apis:eBLBaseComponents">GTC</ListingDuration>
<ListingType xmlns="urn:ebay:apis:eBLBaseComponents">FixedPriceItem</ListingType>
<Location xmlns="urn:ebay:apis:eBLBaseComponents">Italy</Location>
<PaymentMethods xmlns="urn:ebay:apis:eBLBaseComponents">PayPal</PaymentMethods>
<PayPalEmailAddress xmlns="urn:ebay:apis:eBLBaseComponents">email#paypal.com</PayPalEmailAddress>
<PrimaryCategory xmlns="urn:ebay:apis:eBLBaseComponents">
<CategoryID>137084</CategoryID>
</PrimaryCategory>
<ShippingDetails xmlns="urn:ebay:apis:eBLBaseComponents">
<ShippingServiceOptions>
<ShippingService>StandardShippingFromOutsideUS</ShippingService>
<ShippingServiceCost currencyID="EUR">0</ShippingServiceCost>
<ShippingServiceAdditionalCost currencyID="EUR">0</ShippingServiceAdditionalCost>
<FreeShipping>true</FreeShipping>
</ShippingServiceOptions>
<InternationalShippingServiceOption>
<ShippingService>StandardInternational</ShippingService>
<ShippingServiceCost currencyID="EUR">0</ShippingServiceCost>
<ShippingServiceAdditionalCost currencyID="EUR">0</ShippingServiceAdditionalCost>
<ShippingServicePriority>1</ShippingServicePriority>
<ShipToLocation>Americas</ShipToLocation>
<ShipToLocation>Europe</ShipToLocation>
</InternationalShippingServiceOption>
<ShippingType>Flat</ShippingType>
<InsuranceDetails>
<InsuranceFee currencyID="EUR">0</InsuranceFee>
<InsuranceOption>NotOffered</InsuranceOption>
</InsuranceDetails>
<InternationalInsuranceDetails>
<InsuranceFee currencyID="EUR">0</InsuranceFee>
<InsuranceOption>NotOffered</InsuranceOption>
</InternationalInsuranceDetails>
</ShippingDetails>
<Site xmlns="urn:ebay:apis:eBLBaseComponents">US</Site>
<Storefront xmlns="urn:ebay:apis:eBLBaseComponents">
<StoreCategoryID>2947535016</StoreCategoryID>
<StoreCategory2ID>0</StoreCategory2ID>
</Storefront>
<DispatchTimeMax xmlns="urn:ebay:apis:eBLBaseComponents">4</DispatchTimeMax>
<ReturnPolicy xmlns="urn:ebay:apis:eBLBaseComponents">
<ReturnsAcceptedOption>ReturnsAccepted</ReturnsAcceptedOption>
<Description>Accepted</Description>
<ShippingCostPaidByOption>Buyer</ShippingCostPaidByOption>
</ReturnPolicy>
<ConditionID xmlns="urn:ebay:apis:eBLBaseComponents">1000</ConditionID>
</ItemType>
I would love to query the table on that field, for example to extract CategoryID field.
I tried everything I knew, like casting to ntext, removing utf-16, replacing it with utf-8, adding namespaces and stuff like that, but the result is always a NULL record.
Here is one of the queries I tried:
;WITH XMLNAMESPACES('urn:ebay:apis:eBLBaseComponents' AS ns,
'http://www.w3.org/2001/XMLSchema-instance' as xsi,
'http://www.w3.org/2001/XMLSchema' as xsd)
select CategoryVal = CONVERT(xml, [Template]).value('(/ItemType/PrimaryCategory/CategoryID)[1]', 'nvarchar(max)') FROM Templates where ID = 1
Thanks, Marco
with xmlnamespaces('urn:ebay:apis:eBLBaseComponents' as n)
select cast(Template as xml).value('(/ItemType/n:PrimaryCategory/n:CategoryID)[1]', 'nvarchar(max)')
from Templates
where ID = 1
You need to prefix the elements in your xpath expression.
I've done that once, but without the use of namespaces.
I had my input as varchar(max) (nvarchar should work too)
#Text AS varchar(MAX)
Then i used an XML type variable and the conversion was as simple as this:
DECLARE #XML XML
SELECT #XML = #Text
To query your CategoryID value you would use:
SELECT itemtype.item.value('(/ItemType/PrimaryCategory/CategoryID)[1]', 'nvarchar(max)')
FROM #XML.nodes('/ItemType') AS itemtype(item);

Concatenate XML without type casting to string

I have the following XML generated from various tables in my SQL SERVER database
<XMLData>
...
<Type>1</Type>
...
</XMLData>
AND
<XMLData>
...
<Type>2</Type>
...
</XMLData>
AND
<XMLData>
...
<Type>3</Type>
...
</XMLData>
The final output I need is single combined as follows:
<AllMyData>
<XMLData>
...
<Type>1</Type>
...
</XMLData>
<XMLData>
...
<Type>2</Type>
...
</XMLData>
<XMLData>
...
<Type>3</Type>
...
</XMLData>
<AllMyData>
NOTE - all the independent elements that I am combining have the same tag name.
Thanks in advance for looking this up.
I have the following XML generated from various tables in my SQL
SERVER database
Depends on how you have it but if it is in a XML variable you can do like this.
declare #XML1 xml
declare #XML2 xml
declare #XML3 xml
set #XML1 = '<XMLData><Type>1</Type></XMLData>'
set #XML2 = '<XMLData><Type>2</Type></XMLData>'
set #XML3 = '<XMLData><Type>3</Type></XMLData>'
select #XML1, #XML2, #XML3
for xml path('AllMyData')
I can't comment but can answer so even though I think a comment is more appropriate, I'll expand on what rainabba answered above to add a bit more control. My .Net code needs to know the column name returned so I can't rely on auto-generated names but needed the very tip rainabba provided above otherwise.
This way, the xml can effectively be concatenated into a single row and the resulting column named. You could use this same approach to assign the results to an XML variable and return that from a PROC also.
SELECT (
SELECT XmlData as [*]
FROM
(
SELECT
xmlResult AS [*]
FROM
#XmlRes
WHERE
xmlResult IS NOT NULL
FOR XML PATH(''), TYPE
) as DATA(XmlData)
FOR XML PATH('')
) as [someColumnName]
If you use for xml type, you can combine the XML columns without casting them. For example:
select *
from (
select (
select 1 as Type
for xml path(''), type
)
union all
select (
select 2 as Type
for xml path(''), type
)
union all
select (
select 3 as Type
for xml path(''), type
)
) as Data(XmlData)
for xml path(''), root('AllMyData'), type
This prints:
<AllMyData>
<XmlData>
<Type>1</Type>
</XmlData>
<XmlData>
<Type>2</Type>
</XmlData>
<XmlData>
<Type>3</Type>
</XmlData>
</AllMyData>
As an addendum to Mikael Eriksson's answer - If you have a process where you need to continually add nodes and then want to group that under a single node, this is one way to do it:
declare #XML1 XML
declare #XML2 XML
declare #XML3 XML
declare #XMLSummary XML
set #XML1 = '<XMLData><Type>1</Type></XMLData>'
set #XMLSummary = (SELECT #XMLSummary, #XML1 FOR XML PATH(''))
set #XML2 = '<XMLData><Type>2</Type></XMLData>'
set #XMLSummary = (SELECT #XMLSummary, #XML2 FOR XML PATH(''))
set #XML3 = '<XMLData><Type>3</Type></XMLData>'
set #XMLSummary = (SELECT #XMLSummary, #XML3 FOR XML PATH(''))
SELECT #XMLSummary FOR XML PATH('AllMyData')
I needed to do the same but without knowing how many rows/variables were concerned and without extra schema added so here was my solution. Following this pattern, I can generate as many snippets as I want, combine them, pass them between PROCS or even return them from procs and at any point, wrap them up in containers all without modifying the data or being forced to add XML structure into my data. I use this approach with HTTP end points to provide XML Web services and with another trick that converts XML into JSON, to provide JSON WebServices.
-- SETUP A type (or use this design for a Table Variable) to temporarily store snippets into. The pattern can be repeated to pass/store snippets to build
-- larger elements and those can be further combined following the pattern.
CREATE TYPE [dbo].[XMLRes] AS TABLE(
[xmlResult] [xml] NULL
)
GO
-- Call the following as much as you like to build up all the elements you want included in the larger element
INSERT INTO #XMLRes ( xmlResult )
SELECT
(
SELECT
'foo' '#bar'
FOR XML
PATH('SomeTopLevelElement')
)
-- This is the key to "concatenating" many snippets into a larger element. At the end of this, add " ,ROOT('DocumentRoot') " to wrapp them up in another element even
-- The outer select is a time from user2503764 that controls the output column name
SELECT (
SELECT XmlData as [*]
FROM
(
SELECT
xmlResult AS [*]
FROM
#XmlRes
WHERE
xmlResult IS NOT NULL
FOR XML PATH(''), TYPE
) as DATA(XmlData)
FOR XML PATH('')
) as [someColumnName]
ALTER PROCEDURE usp_fillHDDT #Code int
AS
DECLARE #HD XML,#DT XML;
SET NOCOUNT ON;
select invhdcode, invInvoiceNO,invDate,invCusCode,InvAmount into #HD
from dbo.trnInvoiceHD where invhdcode=#Code
select invdtSlNo No,invdtitemcode ItemCode,invdtitemcode ItemName,
invDtRate Rate,invDtQty Qty,invDtAmount Amount ,'Kg' Unit into #DT from
dbo.trnInvoiceDt where invDtTrncode=#Code
set #HD = (select * from #HD HD FOR XML AUTO,ELEMENTS XSINIL);
set #DT = (select* from #DT DT FOR XML AUTO,ELEMENTS XSINIL);
SELECT CAST ('<OUTPUT>'+ CAST (ISNULL(#HD,'') AS VARCHAR(MAX))+ CAST ( ISNULL(#DT,'') AS VARCHAR(MAX))+ '</OUTPUT>' AS XML)
public String ReplaceSpecialChar(String inStr)
{
inStr = inStr.Replace("&", "&");
inStr = inStr.Replace("<", "<");
inStr = inStr.Replace(">", ">");
inStr = inStr.Replace("'", "'");
inStr = inStr.Replace("\"", """);
return inStr;
}

Resources