Related
Is it possible to pivot the following xml into the following result set, or get the structure as close to it as possible? It can obviously have more than 1 item with similar data, I have just trimmed it down so only item sku 987654 is in the file.
DECLARE #XML AS XML = '<data xsi:schemaLocation="http://www.intershop.com/xml/ns/enfinity/7.0/xcs/impex catalog.xsd http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt dt.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.intershop.com/xml/ns/enfinity/7.0/xcs/impex" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt" major="6" minor="1" family="enfinity" branch="enterprise" build="2.6.6-R-1.1.59.2-20210714.2">
<item sku="987654">
<sku>987654</sku>
<category-links>
<category-link name="abc" domain="WhiteStuff-DE-WebCategories" default = "0" hotdeal = "0"/>
<category-link name="def" domain="WhiteStuff-DE-WebCategories" default = "1" hotdeal = "0"/>
<category-link name="ghi" domain="WhiteStuff-DE-WebCategories" default = "0" hotdeal = "0"/>
</category-links>
<images>
<primary-view image-view="FF" />
<image-ref image-view="FD" image-type="w150" image-base-name="FD.jpg" domain="WhiteStuff" />
<image-ref image-view="FF" image-type="ORI" image-base-name="FF.jpg" domain="WhiteStuff" />
</images>
<variations>
<variation-attributes>
<variation-attribute name = "size">
<presentation-option>default</presentation-option>
<custom-attributes>
<custom-attribute name="displayName" dt:dt="string" xml:lang="en-US">Size</custom-attribute>
<custom-attribute name="productDetailUrl" xml:lang="de-DE" dt:dt="string">123.co.uk</custom-attribute>
</custom-attributes>
</variation-attribute>
<variation-attribute name = "colour">
<presentation-option>colorCode</presentation-option>
<presentation-product-attribute-name>rgbColour</presentation-product-attribute-name>
<custom-attributes>
<custom-attribute name="displayName" dt:dt="string" xml:lang="en-US">Colour</custom-attribute>
<custom-attribute name="productDetailUrl" xml:lang="de-DE" dt:dt="string">456.co.uk</custom-attribute>
</custom-attributes>
</variation-attribute>
</variation-attributes>
</variations>
</item>
</data>
'
This is my starting block:
;WITH XMLNAMESPACES
(
DEFAULT 'http://www.intershop.com/xml/ns/enfinity/7.0/xcs/impex',
'http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt' as dt
)
SELECT n.value('#sku', 'nvarchar(max)') as [sku]
--[category-link],
--[FD image],
--[FF image],
--[productDetailUrl DE],
--[productDetailUrl EN]
FROM #XML.nodes('/data/item') as x(n);
It is not so clear how to distinguish between languages:
[productDetailUrl DE]
[productDetailUrl EN]
Other than that, please try the following solution. It will get you started.
SQL
DECLARE #XML AS XML =
N'<?xml version="1.0"?>
<data xsi:schemaLocation="http://www.intershop.com/xml/ns/enfinity/7.0/xcs/impex catalog.xsd http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt dt.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.intershop.com/xml/ns/enfinity/7.0/xcs/impex"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt"
major="6" minor="1" family="enfinity" branch="enterprise"
build="2.6.6-R-1.1.59.2-20210714.2">
<item sku="987654">
<sku>987654</sku>
<category-links>
<category-link name="abc" domain="WhiteStuff-DE-WebCategories"
default="0" hotdeal="0"/>
<category-link name="def" domain="WhiteStuff-DE-WebCategories"
default="1" hotdeal="0"/>
<category-link name="ghi" domain="WhiteStuff-DE-WebCategories"
default="0" hotdeal="0"/>
</category-links>
<images>
<primary-view image-view="FF"/>
<image-ref image-view="FD" image-type="w150"
image-base-name="FD.jpg" domain="WhiteStuff"/>
<image-ref image-view="FF" image-type="ORI" image-base-name="FF.jpg"
domain="WhiteStuff"/>
</images>
<variations>
<variation-attributes>
<variation-attribute name="size">
<presentation-option>default</presentation-option>
<custom-attributes>
<custom-attribute name="displayName" dt:dt="string"
xml:lang="en-US">Size</custom-attribute>
<custom-attribute name="productDetailUrl"
xml:lang="de-DE" dt:dt="string">123.co.uk</custom-attribute>
</custom-attributes>
</variation-attribute>
<variation-attribute name="colour">
<presentation-option>colorCode</presentation-option>
<presentation-product-attribute-name>rgbColour</presentation-product-attribute-name>
<custom-attributes>
<custom-attribute name="displayName" dt:dt="string"
xml:lang="en-US">Colour</custom-attribute>
<custom-attribute name="productDetailUrl"
xml:lang="de-DE" dt:dt="string">456.co.uk</custom-attribute>
</custom-attributes>
</variation-attribute>
</variation-attributes>
</variations>
</item>
</data>';
;WITH XMLNAMESPACES
(
DEFAULT 'http://www.intershop.com/xml/ns/enfinity/7.0/xcs/impex',
'http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt' as dt
)
SELECT c.value('#sku', 'nvarchar(max)') as [sku]
, n.value('#name','VARCHAR(20)') AS [category-link]
, c.value('(images/image-ref[#image-view="FD"]/#image-base-name)[1]','VARCHAR(20)') AS [FD image]
, c.value('(images/image-ref[#image-view="FF"]/#image-base-name)[1]','VARCHAR(20)') AS [FF image]
, c.value('(variations/variation-attributes/variation-attribute/custom-attributes/custom-attribute[#xml:lang="de-DE"]/text())[1]','VARCHAR(20)') AS [productDetailUrl DE]
, c.value('(variations/variation-attributes/variation-attribute[#name="colour"]/custom-attributes/custom-attribute[#xml:lang="de-DE"]/text())[1]','VARCHAR(20)') AS [productDetailUrl EN]
FROM #XML.nodes('/data/item') as t(c)
CROSS APPLY t.c.nodes('category-links/category-link') AS t2(n);
Output
+--------+---------------+----------+----------+---------------------+---------------------+
| sku | category-link | FD image | FF image | productDetailUrl DE | productDetailUrl EN |
+--------+---------------+----------+----------+---------------------+---------------------+
| 987654 | abc | FD.jpg | FF.jpg | 123.co.uk | 456.co.uk |
| 987654 | def | FD.jpg | FF.jpg | 123.co.uk | 456.co.uk |
| 987654 | ghi | FD.jpg | FF.jpg | 123.co.uk | 456.co.uk |
+--------+---------------+----------+----------+---------------------+---------------------+
I create my xml file in this way (I do not show all output fields because there are very many fields):
DECLARE #ID_Rechnung int = 8;
WITH XMLNAMESPACES (
'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext,
'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc,
'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac,
'http://uri.etsi.org/01903/v1.3.2#' as xades,
'http://www.w3.org/2001/XMLSchema-instance' as xsi,
'http://www.w3.org/2000/09/xmldsig#' as ds
)
SELECT
#XMLData = xmldat.xmldataCol
FROM
(
SELECT
(
SELECT
-- HIER XML Daten generieren
'' AS 'ext:UBLExtensions',
'' AS 'ext:UBLExtensions/ext:UBLExtension',
'' AS 'ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent',
'2.1' AS 'cbc:UBLVersionID',
'TR1.2' AS 'cbc:CustomizationID',
'' AS 'cbc:ProfileID',
Rechnungen.Nummer AS 'cbc:ID',
'false' AS 'cbc:CopyIndicator',
'' AS 'cbc:UUID',
CAST(Rechnungen.Datum AS Date) AS 'cbc:IssueDate'
FROM
rechnungen
WHERE
rechnungen.id = #ID_Rechnung
FOR XML PATH(''), ROOT('Invoice')
) AS xmldataCol
This works fine - i get the following XML:
<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent />
</ext:UBLExtension>
</ext:UBLExtensions>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>TR1.2</cbc:CustomizationID>
<cbc:ProfileID />
<cbc:ID>R200001</cbc:ID>
<cbc:CopyIndicator>false</cbc:CopyIndicator>
<cbc:UUID />
<cbc:IssueDate>2020-06-29</cbc:IssueDate>
</Invoice>
But now i need the invoice positions in the same file.
This SQL should be included in the first one and the date should be as invoice line in the xml file:
SELECT
Rechnungpos.ID AS 'cac:InvoiceLine/cbc:ID',
Rechnungpos.Anzahl AS 'cac:InvoiceLine/cbc:InvoicedQuantity'
FROM
RechnungPos
WHERE
RechnungPos.id_Rechnung = #ID_Rechnung
The output should be this:
<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent />
</ext:UBLExtension>
</ext:UBLExtensions>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>TR1.2</cbc:CustomizationID>
<cbc:ProfileID />
<cbc:ID>R200001</cbc:ID>
<cbc:CopyIndicator>false</cbc:CopyIndicator>
<cbc:UUID />
<cbc:IssueDate>2020-06-29</cbc:IssueDate>
<cac:InvoiceLine>
<cbc:ID>1<(cbc:>
<cbc:InvoicedQuantity>3</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>5<(cbc:>
<cbc:InvoicedQuantity>1</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>9<(cbc:>
<cbc:InvoicedQuantity>2</cbc:InvoicedQuantity>
</cac:InvoiceLine>
</Invoice>
Here is the Code to generate Test Data:
CREATE TABLE [dbo].[Rechnungen](
[id] [int] NOT NULL,
[Nummer] [nvarchar](20) NOT NULL,
[Datum] [datetime] NOT NULL
)
INSERT INTO Rechnungen (id, Nummer, Datum) VALUES (8, 'R200001', '29.06.2020')
CREATE TABLE [dbo].Rechnungpos(
[id] [int] NOT NULL,
[id_Rechnung] [int] NOT NULL,
[Anzahl] [float] NOT NULL
)
INSERT INTO RechnungPos (id, id_Rechnung, Anzahl) VALUES (1, 8, 3)
INSERT INTO RechnungPos (id, id_Rechnung, Anzahl) VALUES (5, 8, 1)
INSERT INTO RechnungPos (id, id_Rechnung, Anzahl) VALUES (9, 8, 2)
it has to run on different versions - my version is SQL Server 2019
How can i do that?
Thanks for help, Thomas.
Here is how to do it.
The only complexity is how to handle a child table and specially namespaces in the output XML. That's why XQuery and its FLWOR expression are in use.
SQL
-- DDL and sample data population, start
DECLARE #Rechnungen TABLE (id int , Nummer nvarchar(20), Datum datetime);
INSERT INTO #Rechnungen (id, Nummer, Datum) VALUES
(8, 'R200001', '2020-06-29');
DECLARE #Rechnungpos TABLE (id int, id_Rechnung int, Anzahl float);
INSERT INTO #RechnungPos (id, id_Rechnung, Anzahl) VALUES
(1, 8, 3),
(5, 8, 1),
(9, 8, 2);
-- DDL and sample data population, end
DECLARE #ID_Rechnung int = 8;
;WITH XMLNAMESPACES ('urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
, 'http://uri.etsi.org/01903/v1.3.2#' as xades
, 'http://www.w3.org/2001/XMLSchema-instance' as xsi
, 'http://www.w3.org/2000/09/xmldsig#' as ds)
SELECT (
SELECT '2.1' AS [cbc:UBLVersionID],
'TR1.2' AS [cbc:CustomizationID],
'' AS [cbc:ProfileID],
p.Nummer AS [cbc:ID],
'false' AS [cbc:CopyIndicator],
'' AS [cbc:UUID],
CAST(p.Datum AS Date) AS [cbc:IssueDate],
(
SELECT c.id AS [cbc:ID]
, CAST(c.Anzahl AS INT) AS [cbc:InvoicedQuantity]
FROM #Rechnungpos AS c INNER JOIN
#Rechnungen AS p ON p.id = c.id_Rechnung
FOR XML PATH('r'), TYPE, ROOT('root')
)
FROM #Rechnungen AS p
WHERE p.id = #ID_Rechnung
FOR XML PATH(''), TYPE, ROOT('Invoice')
).query('<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent/>
</ext:UBLExtension>
</ext:UBLExtensions>
{
for $x in /Invoice/*[local-name()!="root"]
return $x,
for $x in /Invoice/root/r
return <cac:InvoiceLine>{$x/*}</cac:InvoiceLine>
}
</Invoice>');
Output
<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent />
</ext:UBLExtension>
</ext:UBLExtensions>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>TR1.2</cbc:CustomizationID>
<cbc:ProfileID />
<cbc:ID>R200001</cbc:ID>
<cbc:CopyIndicator>false</cbc:CopyIndicator>
<cbc:UUID />
<cbc:IssueDate>2020-06-29</cbc:IssueDate>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity>3</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>5</cbc:ID>
<cbc:InvoicedQuantity>1</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>9</cbc:ID>
<cbc:InvoicedQuantity>2</cbc:InvoicedQuantity>
</cac:InvoiceLine>
</Invoice>
Thanks, Yitzhak Khabinsky for help - heres the complete solution:
DECLARE #ID_Rechnung int = 8,
#XMLData xml;
WITH XMLNAMESPACES ('urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
, 'http://uri.etsi.org/01903/v1.3.2#' as xades
, 'http://www.w3.org/2001/XMLSchema-instance' as xsi
, 'http://www.w3.org/2000/09/xmldsig#' as ds)
SELECT
#XMLData = xmldat.xmldataCol
FROM
(
SELECT (
SELECT
-- HIER XML Daten generieren
'' AS 'ext:UBLExtensions',
'' AS 'ext:UBLExtensions/ext:UBLExtension',
'' AS 'ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent',
'2.1' AS 'cbc:UBLVersionID',
'TR1.2' AS 'cbc:CustomizationID',
'' AS 'cbc:ProfileID',
Rechnungen.Nummer AS 'cbc:ID',
'false' AS 'cbc:CopyIndicator',
'' AS 'cbc:UUID',
CAST(Rechnungen.Datum AS Date) AS 'cbc:IssueDate',
'' AS 'cbc:InvoiceTypeCode',
Rechnungen.Bemerkung1 AS 'cbc:Note',
#Waehrung AS 'cbc:DocumentCurrencyCode',
#Waehrung AS 'cbc:TaxCurrencyCode',
Rechnungen.Auftrag AS 'cac:OrderReference/cbc:ID',
-- Verkaüfer
'' AS 'cac:AccountingSupplierParty/cac:Party/cbc:EndpointID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyIdentification/cbc:ID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:StreetName',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:CityName',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:PostalZone',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cac:Country/cbc:IdentificationCode',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyId',
'VAT' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyLegalForm',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:Name',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:Telephone',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail',
-- Käufer
'' AS 'cac:AccountingCustomerParty/cac:Party/cbc:EndpointID',
Rechnungen.DebKreNr AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID',
Rechnungen.DebBez01 + ' ' + DebBez02 AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name',
Rechnungen.DebStrasse AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cbc:StreetName',
Rechnungen.DebOrt AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cbc:CityName',
Rechnungen.DebPLZ AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cbc:PostalZone',
Rechnungen.DebLandKFZ AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cac:Country/cbc:IdentificationCode',
Rechnungen.DebUMSTID AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
'VAT' AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
Rechnungen.DebBez01 + ' ' + DebBez02 AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName',
'' AS 'cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:Name',
'' AS 'cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:Telephone',
'' AS 'cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail',
-- Kontoverbindung Verkäufer
'' AS 'cac:PaymentMeans/cbc:PaymentMeansCode',
'' AS 'cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:ID',
'' AS 'cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:Name',
'' AS 'cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:ID',
--'' AS 'cac:PaymentTerms/cbc:Note',
-- Steuern
#Waehrung AS 'cac:TaxTotal/cbc_TaxAmount/#currencyID',
CAST(Rechnungen.BetragMWST AS nvarchar(15)) AS 'cac:TaxTotal/cbc_TaxAmount',
#Waehrung AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxableAmount/#currencyID',
CAST(Rechnungen.BetragNetto AS nvarchar(15))AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxableAmount',
#Waehrung AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxAmount/#currencyID',
CAST(Rechnungen.BetragMWST AS nvarchar(15))AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxAmount',
'' AS 'cac:TaxTotal/cac:Taxubtotal/cac:TaxCategory/cbc:ID',
CAST(Rechnungen.MWST AS nvarchar(2)) AS 'cac:TaxTotal/cac:Taxubtotal/cac:TaxCategory/cbc:Percent',
'VAT' AS 'cac:TaxTotal/cac:Taxubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:LineExtensionAmount/#currencyID',
CAST(Rechnungen.BetragNetto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:LineExtensionAmount',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount/#currencyID',
CAST(Rechnungen.BetragNetto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount/#currencyID',
CAST(Rechnungen.BetragBrutto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:PayableAmount/#currencyID',
CAST(Rechnungen.BetragBrutto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:PayableAmount',
(
SELECT Rechnungpos.id AS [cbc:ID]
, CAST(Rechnungpos.Anzahl AS INT) AS [cbc:InvoicedQuantity]
FROM Rechnungpos WHERE RechnungPos.id_Rechnung = #id_Rechnung
FOR XML PATH('r'), TYPE, ROOT('root')
)
FROM Rechnungen
WHERE Rechnungen.id = #ID_Rechnung
FOR XML PATH(''), TYPE, ROOT('Invoice')
) AS xmldataCol
) AS xmldat;
SELECT #XMLData
.query('<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
{
for $x in /Invoice/*[local-name()!="root"]
return $x,
for $x in /Invoice/root/r
return <cac:InvoiceLine>{$x/*}</cac:InvoiceLine>
}
</Invoice>');
I have a XML Data like:
<EmployeeDetails>
<BusinessEntityID>3</BusinessEntityID>
<NationalIDNumber>509647174</NationalIDNumber>
<JobTitle>Engineering Manager</JobTitle>
<BirthDate>1974-11-12</BirthDate>
<MaritalStatus>M</MaritalStatus>
<Gender>M</Gender>
<StoreDetail>
<Store>
<AnnualSales>800000</AnnualSales>
<AnnualRevenue>80000</AnnualRevenue>
<BankName>Guardian Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1987</YearOpened>
<Specialty>Touring</Specialty>
<SquareFeet>21000</SquareFeet>
</Store>
<Store>
<AnnualSales>300000</AnnualSales>
<AnnualRevenue>30000</AnnualRevenue>
<BankName>International Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1982</YearOpened>
<Specialty>Road</Specialty>
<SquareFeet>9000</SquareFeet>
</Store>
</StoreDetail>
</EmployeeDetails>
as an example I want to filter as follows 'SquareFeet>10000' and the result I want to get
<EmployeeDetails>
<BusinessEntityID>3</BusinessEntityID>
<NationalIDNumber>509647174</NationalIDNumber>
<JobTitle>Engineering Manager</JobTitle>
<BirthDate>1974-11-12</BirthDate>
<MaritalStatus>M</MaritalStatus>
<Gender>M</Gender>
<StoreDetail>
<Store>
<AnnualSales>800000</AnnualSales>
<AnnualRevenue>80000</AnnualRevenue>
<BankName>Guardian Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1987</YearOpened>
<Specialty>Touring</Specialty>
<SquareFeet>21000</SquareFeet>
</Store>
</StoreDetail>
</EmployeeDetails>
can I do this with SQL server? The result I want to get is still an XML data.
SQL Server XQuery and its FLWOR expression allow to achieve what you need with ease.
T-SQL
DECLARE #xml XML =
N'<EmployeeDetails>
<BusinessEntityID>3</BusinessEntityID>
<NationalIDNumber>509647174</NationalIDNumber>
<JobTitle>Engineering Manager</JobTitle>
<BirthDate>1974-11-12</BirthDate>
<MaritalStatus>M</MaritalStatus>
<Gender>M</Gender>
<StoreDetail>
<Store>
<AnnualSales>800000</AnnualSales>
<AnnualRevenue>80000</AnnualRevenue>
<BankName>Guardian Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1987</YearOpened>
<Specialty>Touring</Specialty>
<SquareFeet>21000</SquareFeet>
</Store>
<Store>
<AnnualSales>300000</AnnualSales>
<AnnualRevenue>30000</AnnualRevenue>
<BankName>International Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1982</YearOpened>
<Specialty>Road</Specialty>
<SquareFeet>9000</SquareFeet>
</Store>
</StoreDetail>
</EmployeeDetails>';
SELECT #xml.query('<EmployeeDetails>
{
for $x in /EmployeeDetails/*
return if (local-name($x) ne "StoreDetail") then $x
else
<StoreDetail>
{
for $y in $x/Store
where $y/SquareFeet/text() > 10000
return $y
}
</StoreDetail>
}
</EmployeeDetails>');
Output
<EmployeeDetails>
<BusinessEntityID>3</BusinessEntityID>
<NationalIDNumber>509647174</NationalIDNumber>
<JobTitle>Engineering Manager</JobTitle>
<BirthDate>1974-11-12</BirthDate>
<MaritalStatus>M</MaritalStatus>
<Gender>M</Gender>
<StoreDetail>
<Store>
<AnnualSales>800000</AnnualSales>
<AnnualRevenue>80000</AnnualRevenue>
<BankName>Guardian Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1987</YearOpened>
<Specialty>Touring</Specialty>
<SquareFeet>21000</SquareFeet>
</Store>
</StoreDetail>
</EmployeeDetails>
This can be done as follows
select * into #tmp from YourTable
update #tmp
set xmldata.modify('
delete (/EmployeeDetails/StoreDetail/Store[SquareFeet <= 10000])[1]
')
select * from #tmp
drop table #tmp
My xml has 4 elements called Sheet, Group, Lineitem and BM
1) there could be multiple Sheet elements but sheet elements will not be nested.
2) Group will be child element of sheet element and Group can be nested means a group can have another child group or many nested child group.
3) Lineitem will be child element of Group element and Lineitem will not be nested.
2) BM will be child element of Lineitem element but BM element will not be nested.
i have a nested xml which i try to parse by xquery to insert data into table one by one. i store the nested element as Parent Child relationship in xml.
here is table structure
CREATE TABLE [dbo].[tblCSM_Details](
[CSM_ID] [int] NOT NULL,
[ID] [int] IDENTITY(1,1) NOT NULL,
[ParentID] [int] NULL,
[Type] [varchar](30) NULL,
[DisplayInCSM] [varchar](200) NULL,
[FontName] [varchar](max) NULL,
[FontStyle] [varchar](max) NULL,
[FontSize] [varchar](max) NULL,
[UnderLine] [varchar](max) NULL,
[BGColor] [varchar](max) NULL,
[LineItemID] [int] NULL,
[BMID] [int] NULL,
[ColOrder] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Parent-child relation is maintained in table by the fields called ID and ParentID
My full code to parse nested element in xml.
DECLARE #XMLData XML=N'<Nodes>
<Sheet FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Model1">
<Group FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Consensus Model">
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1225" NodeText="Net Revenue" />
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1226" NodeText="Cost of Revenue">
<BM FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" BMID="01" NodeText="As % of Net Revenue" />
<BM FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" BMID="02" NodeText="Year over Year Growth" />
</LineItem>
</Group>
<Group FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Segment Details">
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1227" NodeText="Cost of Revenue-GAAP" />
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1228" NodeText="Gross Profit" />
</Group>
</Sheet>
<Sheet FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Model2">
<Group FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Key Financials">
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1235" NodeText="Total Operating Expenses-GAAP" />
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1236" NodeText="EBITDA" />
</Group>
</Sheet>
</Nodes>'
DECLARE #BMID INT,#ColLineItemID INT
DECLARE #SheetID INT,#GroupID INT,#LineItemID INT
DECLARE #SheetOrderID INT,#GroupOrderID INT,#LineItemOrderID INT,#BMOrderID INT
DECLARE #SheetStartIndex INT ,#SheetCount INT = #XMLData.value('count(/Nodes/Sheet)', 'INT');
DECLARE #GroupStartIndex INT ,#GroupCount INT = #XMLData.value('count(/Nodes/Sheet/Group)', 'INT');
DECLARE #LineitemStartIndex INT ,#LineitemCount INT = #XMLData.value('count(/Nodes/Sheet/Group/LineItem)', 'INT');
DECLARE #BMStartIndex INT ,#BMCount INT = #XMLData.value('count(/Nodes/Sheet/Group/LineItem/BM)', 'INT');
SET #SheetStartIndex = 1
SET #GroupStartIndex = 1
SET #LineitemStartIndex = 1
SET #BMStartIndex = 1
SET #SheetOrderID = 1
SET #GroupOrderID = 1
SET #LineItemOrderID = 1
SET #BMOrderID = 1
DECLARE #DisplayInCSM VARCHAR(MAX),
#FontName VARCHAR(MAX),
#FontStyle VARCHAR(MAX),
#FontSize VARCHAR(MAX),
#UnderLine VARCHAR(MAX),
#BGColor VARCHAR(MAX)
SET #DisplayInCSM = ''
SET #FontName = ''
SET #FontStyle = ''
SET #FontSize = ''
SET #UnderLine = ''
SET #BGColor = ''
WHILE #SheetStartIndex <= #SheetCount
BEGIN --Inserting sheet data
--PRINT 'Sheet'
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)')
FROM #XMLData.nodes('/Nodes/Sheet[position() = sql:variable("#SheetStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,0,'SHEET',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,0,0,#SheetOrderID)
SELECT #SheetID = SCOPE_IDENTITY()
BEGIN --Inserting Group data
SET #GroupOrderID = 1
SET #GroupStartIndex = 1
WHILE #GroupStartIndex <= #GroupCount
BEGIN --Inserting Group data
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)')
FROM #XMLData.nodes('/Nodes/Sheet/Group[position() = sql:variable("#GroupStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,#SheetID,'GROUP',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,0,0,#GroupOrderID)
SELECT #GroupID = SCOPE_IDENTITY()
BEGIN --Inserting LineItem data
SET #LineItemOrderID = 1
SET #LineitemStartIndex = 1
WHILE #LineitemStartIndex <= #LineitemCount
BEGIN
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)'),
#ColLineItemID = CAST(tab.col.value('#LineItemID[1]', 'VARCHAR(MAX)') AS INT)
FROM #XMLData.nodes('/Nodes/Sheet/Group/LineItem[position() = sql:variable("#LineitemStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,#GroupID,'LINEITEM',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,#ColLineItemID,0,#LineItemOrderID)
SELECT #LineItemID = SCOPE_IDENTITY()
BEGIN --Inserting BM data
SET #BMOrderID = 1
SET #BMStartIndex = 1
WHILE #BMStartIndex <= #BMCount
BEGIN --Inserting sheet data
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)'),
#BMID = CAST(tab.col.value('#BMID[1]', 'VARCHAR(MAX)') AS INT)
FROM #XMLData.nodes('/Nodes/Sheet/Group/LineItem/BM[position() = sql:variable("#BMStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,#LineItemID,'BM',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,0,#BMID,#BMOrderID)
SET #BMOrderID = #BMOrderID + 1
SET #BMStartIndex = #BMStartIndex + 1
END
END
SET #LineItemOrderID = #LineItemOrderID + 1
SET #LineitemStartIndex = #LineitemStartIndex + 1
END
END
SET #GroupOrderID = #GroupOrderID + 1
SET #GroupStartIndex = #GroupStartIndex + 1;
END
END
SET #SheetOrderID = #SheetOrderID + 1
SET #SheetStartIndex = #SheetStartIndex + 1;
END
1) When run the above code then i saw 6 Group has been inserted into table. whereas i have 3 group in xml
2) BM element has been added under wrong lineitem.
i insert data into loop because i have parent child relation in table. so when i insert parent data then i store parent's inserted id into variable which i also insert during child data insertion.
i am not being able to understand where i made the mistake in code. anyone can help me. thanks
I have this table in DB:
ID | Timestamp | Score
------|---------------------|-------------------
1 | 2013-01-01 12:00:00 | 15
1 | 2013-01-02 11:00:00 | 1
1 | 2013-01-03 16:00:00 | 4
2 | 2013-01-08 04:00:00 | 7
2 | 2013-01-09 08:00:00 | 9
2 | 2013-01-10 11:00:00 | 6
3 | 2013-01-03 12:00:00 | 14
3 | 2013-01-01 10:00:00 | 15
3 | 2013-01-02 00:00:00 | 17
What I need is a last Score for each ID.
In other words, for each ID, I need to pick the row with highest Timestamp and then get the Score from that row.
I managed to do that in SQL server like this (which may not be optimal)
SELECT ID, Timestamp, Score FROM Data cd
LEFT OUTER JOIN
(SELECT ID as SubId, MAX(Timestamp) AS TS
FROM Data GROUP BY ID) AS SUB
ON cd.ID = SUB.SubId
WHERE Timestamp = TS
I need a LINQ to Entities (v4) solution to this situation, but I am unsure how to approach subqueries and grouping in this situation.
#Edit (in reply to comments):
I've tried something like the following, but I don't know how to get the Score from that grouped item, or how to integrate the subquery into this.
from d in Datas
group d by d.ID into group
select new { ID = group.Key, TS = group.Max(i => i.Timestamp) }
Is this scenario possible? Is there any better solution (performance-wise)?
This should achieve what you are wanting:
from d in Datas
group d by d.ID into g
let maxDate = g.Max(d => d.Timestamp)
select new
{
ID = g.Key,
Score = g.First(item => item.Timestamp == maxDate).Score
};
Here's a copy of the complete code listing that I used in LINQPad:
void Main()
{
var testData = GenerateTestData();
var result =
from d in testData
group d by d.ID into g
let maxDate = g.Max(d => d.Timestamp)
select new
{
ID = g.Key,
Score = g.First(item => item.Timestamp == maxDate).Score
};
foreach (var item in result)
{
Console.WriteLine("ID={0}; Score={1}", item.ID, item.Score);
}
}
List<Item> GenerateTestData()
{
List<Item> list = new List<Item>();
list.Add(new Item(1, "2013-01-01 12:00:00", 15));
list.Add(new Item(1, "2013-01-02 11:00:00", 1));
list.Add(new Item(1, "2013-01-03 16:00:00", 4));
list.Add(new Item(2, "2013-01-08 04:00:00", 7));
list.Add(new Item(2, "2013-01-09 08:00:00", 9));
list.Add(new Item(2, "2013-01-10 11:00:00", 6));
list.Add(new Item(3, "2013-01-03 12:00:00", 14));
list.Add(new Item(3, "2013-01-01 10:00:00", 15));
list.Add(new Item(3, "2013-01-02 00:00:00", 17));
return list;
}
class Item
{
public Item(int id, string timestamp, int score)
{
ID = id;
Timestamp = DateTime.Parse(timestamp);
Score = score;
}
public int ID;
public DateTime Timestamp;
public int Score;
}
Which produced the output:
ID=1; Score=4
ID=2; Score=6
ID=3; Score=14