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);
Related
I tryng to read xml file in sql server:
DECLARE #XMLToParse XML
-- Load the XML data in to a variable to work with.
-- This would typically be passed as a parameter to a stored proc
SET #XMLToParse = '<Response xmlns="http://tempuri.org/">
<AuthResult xmlns:a="http://schemas.datacontract.org/2004/07/Sistema.Soap.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Result>
<a:Id_Value>500</a:Id_Value>
</a:Result>
<a:Result>
<a:Id_Value>895</a:Id_Value>
</a:Result>
</AuthResult>
</Response>'
-- Declare temp table to parse data into
DECLARE #ParsingTable TABLE
(Id_Value INT)
-- Parse the XML in to the temp table declared above
INSERT
INTO #ParsingTable
(Id_Value)
SELECT xmlData.A.value('.', 'INT') AS Id_Value
FROM #XMLToParse.nodes('Response/AuthResult/Result') xmlData(A)
-- Insert into the actual table from the temp table
SELECT Id_Value
FROM #ParsingTable
Apparently the code is correct but I can not get the values, where can I be wrong?
Use WITH XMLNAMESPACES to declare the namespaces and use the respective prefix for nodes not in the default namespace.
...
-- Parse the XML in to the temp table declared above
;WITH XMLNAMESPACES (DEFAULT 'http://tempuri.org/',
'http://schemas.datacontract.org/2004/07/Sistema.Soap.Contracts' as a,
'http://www.w3.org/2001/XMLSchema-instance' as i
)
INSERT
INTO #ParsingTable
(Id_Value)
SELECT xmlData.A.value('.', 'INT') AS Id_Value
FROM #XMLToParse.nodes('Response/AuthResult/a:Result') xmlData(A)
...
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>
I've been through various posts on the same subject but I can't seem to be able to get to the data elements in my XML file.
Here is a snippet of my XML :
<ed:Certificate xmlns="http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd" xmlns:ed="http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd"> <ed:Status Code="39">Approved</ed:Status> <ed:LastUpdatedDate>2021-03-10T14:20:55+13:00</ed:LastUpdatedDate> <ed:Identifiers>
<ed:CertificateID>NZL2021/MEABC/26913T</ed:CertificateID>
<ed:TemplateID>ED1.6</ed:TemplateID> </ed:Identifiers> <ed:Exhausted>true</ed:Exhausted> <ed:AutoApproval>false</ed:AutoApproval> <ed:DepartureDate>2021-03-10</ed:DepartureDate> <ed:Parties>
<ed:ConsignorID>MEABC</ed:ConsignorID>
<ed:ConsigneeID>FLIGHT1</ed:ConsigneeID> </ed:Parties> <ed:Transport>
<ed:Ports>
<ed:LoadingPortID>NZTRG</ed:LoadingPortID>
</ed:Ports>
<ed:FinalDestination>OAKLAND, United States</ed:FinalDestination>
<ed:TransportMode>1</ed:TransportMode>
<ed:LocalCarrier>MDH2</ed:LocalCarrier>
<ed:CarrierName> Ever Given</ed:CarrierName>
<ed:ConveyanceReference>V1234</ed:ConveyanceReference> </ed:Transport> <ed:Remarks>
<ed:Remark>
<ed:RemarkType>Unofficial Information</ed:RemarkType>
<ed:RemarkValue>Vessel ETD - 19/03/21\nTARE WEIGHT - 2880 KGS</ed:RemarkValue>
</ed:Remark> </ed:Remarks> <ed:Products>
<ed:Product>
<ed:ProductItem>1</ed:ProductItem>
<ed:Exhausted>true</ed:Exhausted>
<ed:Origin>AO</ed:Origin>
<ed:Description>BONELESS BEEF RUMP CAP</ed:Description>
<ed:CommonName>Bovine</ed:CommonName>
<ed:EligibilityCountries>
<ed:EligibilityCountryID>US</ed:EligibilityCountryID>
</ed:EligibilityCountries>
<ed:IntendedUse>consumption</ed:IntendedUse>
<ed:GrossWeight unitCode="KGM">296.4</ed:GrossWeight>
<ed:NetWeight unitCode="KGM">271.6</ed:NetWeight>
<ed:Remarks>
<ed:Remark>
<ed:RemarkType>Product Statement</ed:RemarkType>
<ed:RemarkValue>Item No. 81625\nLabel Approval 2659305 & 91060858</ed:RemarkValue>
</ed:Remark>
</ed:Remarks>
<ed:Classifications>
<ed:Classification>
<ed:ClassificationType>Temperature</ed:ClassificationType>
<ed:ClassificationValue>chilled</ed:ClassificationValue>
</ed:Classification>
<ed:Classification>
<ed:ClassificationType>New Zealand Harmonised System Code</ed:ClassificationType>
<ed:ClassificationValue>020130</ed:ClassificationValue>
</ed:Classification>
<ed:Classification>
<ed:ClassificationType>Halal Product</ed:ClassificationType>
<ed:ClassificationValue>1</ed:ClassificationValue>
</ed:Classification>
</ed:Classifications>
<ed:Containers>
<ed:Container>
<ed:ID>CGMU3099999</ed:ID>
<ed:Seals>
<ed:ID>NZMPIXXXXX</ed:ID>
</ed:Seals>
</ed:Container>
</ed:Containers>
<ed:Packaging>
<ed:Package>
<ed:Quantity>29</ed:Quantity>
<ed:Type>CT</ed:Type>
<ed:Level>1</ed:Level>
<ed:ShippingMarks>
<ed:Name>MABC\n26913</ed:Name>
</ed:ShippingMarks>
</ed:Package>
</ed:Packaging>
<ed:Processes>
<ed:Process>
<ed:ProcessTypeCode>SLT</ed:ProcessTypeCode>
<ed:StartDate>2021-03-01</ed:StartDate>
<ed:EndDate>2021-03-01</ed:EndDate>
<ed:DateOverride>false</ed:DateOverride>
<ed:Premise>
<ed:ID>MEABC</ed:ID>
</ed:Premise>
</ed:Process>
<ed:Process>
<ed:ProcessTypeCode>PRO</ed:ProcessTypeCode>
<ed:StartDate>2021-03-02</ed:StartDate>
<ed:EndDate>2021-03-02</ed:EndDate>
<ed:DateOverride>false</ed:DateOverride>
<ed:Premise>
<ed:ID>MEABC</ed:ID>
</ed:Premise>
</ed:Process>
<ed:Process>
<ed:ProcessTypeCode>CST</ed:ProcessTypeCode>
<ed:StartDate>2021-03-02</ed:StartDate>
<ed:EndDate>2021-03-10</ed:EndDate>
<ed:DateOverride>false</ed:DateOverride>
<ed:Premise>
<ed:ID>MEABC</ed:ID>
</ed:Premise>
</ed:Process>
</ed:Processes>
</ed:Product>
</ed:Products>
</ed:Certificate>
This is what I have tried so far - Figured if I can access one element, I can slowly work on the rest
if OBJECT_ID('tempdb..#XmlImportTest') is not null
drop table #XmlImportTest
CREATE TABLE #XmlImportTest(
xmlFileName VARCHAR(300) NOT NULL,
xml_data XML NOT NULL
);
DECLARE #xmlFileName VARCHAR(200) ='K:\Upload\CSNXML\WaybillXml.xml'
EXEC('INSERT INTO #XmlImportTest(xmlFileName, xml_data)
SELECT ''' + #xmlFileName + ''', xmlData
FROM(
SELECT *
FROM OPENROWSET (BULK ''' + #xmlFileName + ''', SINGLE_BLOB) AS XMLDATA
) AS FileImport (XMLDATA)
')
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #xml = (SELECT xml_data from #XmlImportTest)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #xml = (SELECT xml_data from #XmlImportTest)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
;WITH XMLNAMESPACES ('http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd' AS ed)
SELECT
p.value(N'#ProductItem',N'nvarchar(10)') AS ProductItem
FROM
#xml.nodes('/Certificate')
AS A(p)
CROSS APPLY a.p.nodes(N'Products/Product') AS B(m);
I don't get any results returned.
I get the same result using OPENROWSET as well.
Can someone please tell me how I can access this data element.
You seem to be getting confused about XML Namespaces. The example document defines two namespace URIs:
http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd, which has no prefix so is considered to be the "default" namespace of the document.
http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd, which uses the ed namespace prefix that, by eyeballing it, seems to be used on every element in the document so might as well be the default namespace.
Your simplest example is trying to extract the value of the /Certificate/Products/Product/ProductItem elements which could be done as simply as:
with xmlnamespaces (
default 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd'
)
select productItem.value(N'text()[1]', N'int') as ProductItem
from #xml.nodes('/Certificate/Products/Product/ProductItem') as p(productItem);
Expanding on this to select a few more values, you can see the # being used here to access the unitCode attribute of an element:
with xmlnamespaces (
default 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd'
)
select
product.value(N'(ProductItem/text())[1]', N'int') as ProductItem,
product.value(N'(Exhausted/text())[1]', N'bit') as Exhausted,
product.value(N'(Origin/text())[1]', N'nvarchar(2)') as Origin,
product.value(N'(GrossWeight/text())[1]', N'decimal(19,1)') as GrossWeight,
product.value(N'(GrossWeight/#unitCode)[1]', N'nvarchar(3)') as GrossWeightUnitCode
from #xml.nodes('/Certificate/Products/Product') as p(product);
It should be clear from the above two queries that the namespace prefixes used XPath query don't have to be the same as the ones used in the XML document - it's the namespace URIs themselves that matter. The prefixes in the document are used to link the elements (and sometimes attributes) to their namespace URIs, the prefixes used in XPath can be completely different so long as they reference the correct namespace URIs. e.g. this query returns the same result as the second example above, despite their being no submission prefixes in the source XML:
with xmlnamespaces (
'http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd' as multiple,
'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd' as submission
)
select
product.value(N'(submission:ProductItem/text())[1]', N'int') as ProductItem,
product.value(N'(submission:Exhausted/text())[1]', N'bit') as Exhausted,
product.value(N'(submission:Origin/text())[1]', N'nvarchar(2)') as Origin,
product.value(N'(submission:GrossWeight/text())[1]', N'decimal(19,1)') as GrossWeight,
product.value(N'(submission:GrossWeight/#unitCode)[1]', N'nvarchar(3)') as GrossWeightUnitCode,
product.value(N'(submission:Remarks/submission:Remark/submission:RemarkType/text())[1]', N'nvarchar(50)') as item_remark
from #xml.nodes('/submission:Certificate/submission:Products/submission:Product') as p(product);
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);
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;
}