Convert XML to SQL Server table (cfdi document) - sql

I'm trying to convert a XML to a SQL Server table.
The XML is the following (sample):
declare #XML as XML
set #XML = '<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:nomina12="http://www.sat.gob.mx/nomina12" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Fecha="2020-02-15">
<cfdi:Emisor Rfc="12345" />
<cfdi:Conceptos>
<cfdi:Concepto ClaveProdServ="84111505" Cantidad="1" />
</cfdi:Conceptos>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/timbrefiscaldigital/TimbreFiscalDigitalv11.xsd"
Version="1.1" UUID="28C9D7DC-A9CB-4663-9606-3B7E37D922D4" FechaTimbrado="2020-04-15T18:59:18" />
<nomina12:Nomina Version="1.2" TipoNomina="O" FechaPago="2020-04-15" FechaInicialPago="2020-04-01" FechaFinalPago="2020-04-15" >
<nomina12:Emisor RegistroPatronal="Z2935172101" />
<nomina12:Receptor Curp="XYZ" />
<nomina12:Percepciones TotalSueldos="6807.63" TotalGravado="5865.48" TotalExento="942.15">
<nomina12:Percepcion TipoPercepcion="001" Clave="P001" Concepto="Sueldo Normal" ImporteGravado="4887.90" ImporteExento="0.00" />
<nomina12:Percepcion TipoPercepcion="005" Clave="P013" Concepto="Fondo Ahorro Empresa" ImporteGravado="0.00" ImporteExento="342.15" />
</nomina12:Percepciones>
<nomina12:Deducciones TotalOtrasDeducciones="1282.01" TotalImpuestosRetenidos="610.94">
<nomina12:Deduccion TipoDeduccion="001" Clave="D003" Concepto="IMSS" Importe="70.40" />
<nomina12:Deduccion TipoDeduccion="001" Clave="D034" Concepto="Cuota IMSS RCV" Importe="58.66" />
</nomina12:Deducciones>
</nomina12:Nomina>
</cfdi:Complemento>
</cfdi:Comprobante>'
My SQL code is the following:
;WITH XMLNAMESPACES(
'http://www.sat.gob.mx/cfd/3' as cfdi,
'http://www.w3.org/2001/XMLSchema-instance' as xsi,
'http://www.sat.gob.mx/TimbreFiscalDigital' as tfd,
'http://www.sat.gob.mx/TimbreFiscalDigital' as schemaLocation,
'http://www.sat.gob.mx/nomina12' as nomina12)
SELECT
xmldata.value('(#Fecha)', 'varchar(20)') AS fecha_elaboracion,
xmldata.value('(cfdi:Emisor/#Rfc)[1]', 'varchar(20)') AS rfc_emisor,
xmldata1.value('(#UUID)', 'varchar(100)') AS UUID,
xmldata1.value('(#FechaTimbrado)', 'varchar(50)') AS fecha_timbre,
xmldata2.value('(#FechaPago)', 'nvarchar(50)') AS fecha_pago,
xmldata2.value('(#FechaInicialPago)', 'nvarchar(50)') AS fecha_inicio,
xmldata2.value('(#FechaFinalPago)', 'nvarchar(50)') AS fecha_final
FROM
(SELECT #XML AS x) AS x1
CROSS APPLY
x.nodes('/cfdi:Comprobante') AS a(xmldata)
CROSS APPLY
xmldata.nodes('cfdi:Complemento/tfd:TimbreFiscalDigital') AS a1(xmldata1)
OUTER APPLY
xmldata.nodes('cfdi:Complemento/tfd:TimbreFiscalDigital/nomina12:Nomina') AS a2(xmldata2);
I'm getting information for the first nodes but when I want to get the node "nomina12:Nomina", I got a null VALUE, some idea what's wrong?
Thanks in advance for your help.

Somewhat cleaned up version.
I removed not needed namespace declarations, and adjusted proper data types.
SQL
DECLARE #xml XML =
N'<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3"
xmlns:nomina12="http://www.sat.gob.mx/nomina12"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Fecha="2020-02-15">
<cfdi:Emisor Rfc="12345"/>
<cfdi:Conceptos>
<cfdi:Concepto ClaveProdServ="84111505" Cantidad="1"/>
</cfdi:Conceptos>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/timbrefiscaldigital/TimbreFiscalDigitalv11.xsd"
Version="1.1"
UUID="28C9D7DC-A9CB-4663-9606-3B7E37D922D4"
FechaTimbrado="2020-04-15T18:59:18"/>
<nomina12:Nomina Version="1.2" TipoNomina="O" FechaPago="2020-04-15"
FechaInicialPago="2020-04-01"
FechaFinalPago="2020-04-15">
<nomina12:Emisor RegistroPatronal="Z2935172101"/>
<nomina12:Receptor Curp="XYZ"/>
<nomina12:Percepciones TotalSueldos="6807.63" TotalGravado="5865.48"
TotalExento="942.15">
<nomina12:Percepcion TipoPercepcion="001" Clave="P001"
Concepto="Sueldo Normal"
ImporteGravado="4887.90"
ImporteExento="0.00"/>
<nomina12:Percepcion TipoPercepcion="005" Clave="P013"
Concepto="Fondo Ahorro Empresa"
ImporteGravado="0.00"
ImporteExento="342.15"/>
</nomina12:Percepciones>
<nomina12:Deducciones TotalOtrasDeducciones="1282.01"
TotalImpuestosRetenidos="610.94">
<nomina12:Deduccion TipoDeduccion="001" Clave="D003"
Concepto="IMSS" Importe="70.40"/>
<nomina12:Deduccion TipoDeduccion="001" Clave="D034"
Concepto="Cuota IMSS RCV" Importe="58.66"/>
</nomina12:Deducciones>
</nomina12:Nomina>
</cfdi:Complemento>
</cfdi:Comprobante>';
;WITH XMLNAMESPACES('http://www.sat.gob.mx/cfd/3' as cfdi
, 'http://www.sat.gob.mx/TimbreFiscalDigital' as tfd
, 'http://www.sat.gob.mx/nomina12' as nomina12)
SELECT xmldata.value('#Fecha', 'DATE') AS fecha_elaboracion
, xmldata.value('(cfdi:Emisor/#Rfc)[1]', 'VARCHAR(20)') AS rfc_emisor
, xmldata1.value('#UUID', 'UNIQUEIDENTIFIER') AS UUID
, xmldata1.value('#FechaTimbrado', 'VARCHAR(50)') AS fecha_timbre
, xmldata2.value('#FechaPago', 'DATE') AS fecha_pago
, xmldata2.value('#FechaInicialPago', 'DATE') AS fecha_inicio
, xmldata2.value('#FechaFinalPago', 'DATE') AS fecha_final
FROM #xml.nodes('/cfdi:Comprobante') AS a(xmldata)
OUTER APPLY xmldata.nodes('cfdi:Complemento/tfd:TimbreFiscalDigital') AS a1(xmldata1)
OUTER APPLY xmldata.nodes('cfdi:Complemento/nomina12:Nomina') AS a2(xmldata2);
Output
+-------------------+------------+--------------------------------------+---------------------+------------+--------------+-------------+
| fecha_elaboracion | rfc_emisor | UUID | fecha_timbre | fecha_pago | fecha_inicio | fecha_final |
+-------------------+------------+--------------------------------------+---------------------+------------+--------------+-------------+
| 2020-02-15 | 12345 | 28C9D7DC-A9CB-4663-9606-3B7E37D922D4 | 2020-04-15T18:59:18 | 2020-04-15 | 2020-04-01 | 2020-04-15 |
+-------------------+------------+--------------------------------------+---------------------+------------+--------------+-------------+

You are refering to the wrong path in your outer apply statement:
xmldata.nodes('cfdi:Complemento/nomina12:Nomina') AS a2(xmldata2);
And also here is the simplified version of your query:
WITH XMLNAMESPACES ('http://www.sat.gob.mx/cfd/3' AS cfdi
, 'http://www.w3.org/2001/XMLSchema-instance' AS xsi
, 'http://www.sat.gob.mx/TimbreFiscalDigital' AS tfd
, 'http://www.sat.gob.mx/TimbreFiscalDigital' AS schemaLocation
, 'http://www.sat.gob.mx/nomina12' AS nomina12
)
SELECT
xmldata.value('(/cfdi:Comprobante/#Fecha)[1]', 'varchar(20)') AS fecha_elaboracion
, xmldata.value('(/cfdi:Comprobante/cfdi:Emisor/#Rfc)[1]', 'varchar(20)') AS rfc_emisor
, xmldata.value('(/cfdi:Comprobante/cfdi:Complemento/tfd:TimbreFiscalDigital/#UUID)[1]', 'varchar(100)') AS UUID
, xmldata.value('(/cfdi:Comprobante/cfdi:Complemento/tfd:TimbreFiscalDigital/#FechaTimbrado)[1]', 'varchar(50)') AS fecha_timbre
, xmldata.value('(/cfdi:Comprobante/cfdi:Complemento/nomina12:Nomina/#FechaPago)[1]', 'nvarchar(50)') AS fecha_pago
, xmldata.value('(/cfdi:Comprobante/cfdi:Complemento/nomina12:Nomina/#FechaInicialPago)[1]', 'nvarchar(50)') AS fecha_inicio
, xmldata.value('(/cfdi:Comprobante/cfdi:Complemento/nomina12:Nomina/#FechaFinalPago)[1]', 'nvarchar(50)') AS fecha_final
FROM
(SELECT #XML AS xmldata) AS xmldata

Related

Import xml data in SQL Server 2017

I have XML data like this:
<?xml version="1.0" ?>
<SettlementFile>
<Transaction>
<Identifier>
<StationID>049215901 </StationID>
<TransactionTimestamp>2021-04-01T10:39:32</TransactionTimestamp>
</Identifier>
<TerminalInfo>
<TerminalID>21590151</TerminalID>
<TerminalType>2</TerminalType>
</TerminalInfo>
<TransactionInfo>
<TransactionType>0</TransactionType>
<TransactionAmount>3.74</TransactionAmount>
<CurrencyCode>978</CurrencyCode>
<CustomerInput>
<Mileage>0</Mileage>
</CustomerInput>
<TicketNumber>213510037</TicketNumber>
<AuthorisationType>1</AuthorisationType>
</TransactionInfo>
</Transaction>
</SettlementFile>
My SQL Server table structure:
CREATE TABLE dbo.Import_Oase
(
StationID varchar(50) NULL,
TransactionTimestamp datetime NULL,
TicketNumber int NULL,
Mileage varchar(50) NULL
) ON PRIMARY
I'm trying to use this SELECT query:
SELECT
MY_XML.Details.query('StationID') .value('.', 'VARCHAR(50)'),
MY_XML.Details.query('TransactionTimestamp').value('.', 'Datetime'),
MY_XML.Details.query('TicketNumber') .value('.', 'Integer'),
MY_XML.Details.query('Mileage') .value('.', 'VARCHAR(50)')
FROM
(SELECT
CAST(MY_XML AS XML)
FROM
OPENROWSET(BULK '\\EO-TEST\SQL-Daten\Temp\MY_XML.xml', SINGLE_BLOB) AS T(MY_XML)
) AS T(MY_XML)
CROSS APPLY
MY_XML.nodes('SettlementFile/Transaction/Identifier, SettlementFile/Transaction/TransactionInfo, SettlementFile/Transaction/TransactionInfo/CustomerInput') AS MY_XML (Details);
I need to get the result in one line because it is all for 1 transactions. But it is in three different line in SQL.
Please try the following solution.
When you are satisfied with the outcome, just uncomment the INSERT INTO line.
SQL
WITH rs (xmlData) AS
(
SELECT TRY_CAST(BulkColumn AS XML)
FROM OPENROWSET(BULK N'e:\Temp\ daryosmitan.xml', SINGLE_BLOB) AS x
)
-- INSERT INTO dbo.Import_Oase (StationID, TransactionTimestamp, TicketNumber, Mileage)
SELECT c.value('(Identifier/StationID/text())[1]', 'VARCHAR(50)') AS StationID
, c.value('(Identifier/TransactionTimestamp/text())[1]', 'DATETIME') AS TransactionTimestamp
, c.value('(TransactionInfo/TicketNumber/text())[1]', 'VARCHAR(50)') AS TicketNumber
, c.value('(TransactionInfo/CustomerInput/Mileage/text())[1]', 'INT') AS Mileage
FROM rs
CROSS APPLY xmlData.nodes('/SettlementFile/Transaction') AS t(c);

T-SQL Parse XML Response in table format

I am struggling with parsing an XML Response I have. I need the header values to be columns and the record values to be the data inside their respective rows. Below is a sample of a return with the header values and 1 record.
Where records show xsi:nil="true" would be NULL
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:getReportResultResponse xmlns:ns2="http://service.apiendpoint.com">
<return>
<header>
<values>
<data>CUSTOMER NAME</data>
<data>DISPOSITION GROUP A</data>
<data>DISPOSITION GROUP B</data>
<data>DISPOSITION GROUP C</data>
<data>DISPOSITION PATH</data>
<data>FIRST DISPOSITION</data>
<data>LAST DISPOSITION</data>
<data>LIST NAME</data>
</values>
</header>
<records>
<values>
<data>Mark Smith</data>
<data>12</data>
<data>19</data>
<data>23</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 1</data>
</values>
</records>
</return>
</ns2:getReportResultResponse>
</env:Body>
</env:Envelope>
declare #x xml = N'
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:getReportResultResponse xmlns:ns2="http://service.apiendpoint.com">
<return>
<header>
<values>
<data>CUSTOMER NAME</data>
<data>DISPOSITION GROUP A</data>
<data>DISPOSITION GROUP B</data>
<data>DISPOSITION GROUP C</data>
<data>DISPOSITION PATH</data>
<data>FIRST DISPOSITION</data>
<data>LAST DISPOSITION</data>
<data>LIST NAME</data>
</values>
</header>
<records>
<values>
<data>Mark Smith</data>
<data>12</data>
<data>19</data>
<data>23</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 1</data>
</values>
<values>
<data>B</data>
<data>2</data>
<data>22</data>
<data>222</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/><!-- ?? -->
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 2</data>
</values>
</records>
</return>
</ns2:getReportResultResponse>
</env:Body>
</env:Envelope>
';
select #x;
declare #sql nvarchar(max) = N'';
with xmlnamespaces ('http://schemas.xmlsoap.org/soap/envelope/' as env, 'http://service.apiendpoint.com' as ns2)
select
#sql = #sql + ',r.rec.value(''data[' + cast(colid as nvarchar(10)) + '][not(#xsi:nil="true")]'', ''nvarchar(500)'') as ' + colname
from
(
select
quotename(hd.h.value('.', 'sysname')) as colname,
row_number() over(order by hd.h) as colid
from #x.nodes('/env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data') as hd(h)
) as src
order by colid;
select #sql = stuff(#sql, 1, 1, N'');
select #sql = N'with xmlnamespaces (''http://schemas.xmlsoap.org/soap/envelope/'' as env, ''http://service.apiendpoint.com'' as ns2, ''http://www.w3.org/2001/XMLSchema-instance'' as xsi)
select
' + #sql + N'
from #x.nodes(''/env:Envelope/env:Body/ns2:getReportResultResponse/return/records/values'') as r(rec)
';
exec sp_executesql #stmt = #sql, #params = N'#x xml', #x = #x;
Assuming you have your XML data in a SQL Server variable #XmlData, you could use this XQuery to get the column names ("headers"):
WITH XMLNAMESPACES ('http://schemas.xmlsoap.org/soap/envelope/' AS env, 'http://service.apiendpoint.com' AS ns2)
SELECT
XCol.value('(.)[1]', 'varchar(50)')
FROM
#XmlData.nodes('/env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data') AS XHdr(XCol);
This is fairly straightforward, since you can assume every single header is really a string (therefore you can do the .value('(.)[1]', 'varchar(50)') call and be on the safe side).
However, for the data - as #Serg already mentioned in the comment - unless you can somehow know (or find out) what the data elements' datatypes are, this is going to be trickier... Using the same approach - assuming everything is a string - would work - but then you might be losing valuable information about your data bits:
WITH XMLNAMESPACES ('http://schemas.xmlsoap.org/soap/envelope/' AS env, 'http://service.apiendpoint.com' AS ns2)
SELECT
XCol.value('(.)[1]', 'varchar(50)')
FROM
#XmlData.nodes('/env:Envelope/env:Body/ns2:getReportResultResponse/return/records/values/data') AS XData(XCol)
Here is another solution. It is very close to the #lptr's method.
It is using XQuery and FLWOR expression to construct a dynamic SELECT clause of the final SQL statement.
SQL
DECLARE #x xml = N'
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:getReportResultResponse xmlns:ns2="http://service.apiendpoint.com">
<return>
<header>
<values>
<data>CUSTOMER NAME</data>
<data>DISPOSITION GROUP A</data>
<data>DISPOSITION GROUP B</data>
<data>DISPOSITION GROUP C</data>
<data>DISPOSITION PATH</data>
<data>FIRST DISPOSITION</data>
<data>LAST DISPOSITION</data>
<data>LIST NAME</data>
</values>
</header>
<records>
<values>
<data>Mark Smith</data>
<data>12</data>
<data>19</data>
<data>23</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 1</data>
</values>
<values>
<data>B</data>
<data>2</data>
<data>22</data>
<data>222</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/><!-- ?? -->
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 2</data>
</values>
</records>
</return>
</ns2:getReportResultResponse>
</env:Body>
</env:Envelope>';
DECLARE #sql NVARCHAR(MAX) = N''
, #separator CHAR(1) = ',';
WITH XMLNAMESPACES ('http://schemas.xmlsoap.org/soap/envelope/' as env, 'http://service.apiendpoint.com' as ns2)
SELECT #sql = #x.query('
for $r in /env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data
let $pos := count(env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data[. << $r]) + 1
let $line := concat("c.value(''(data[", string($pos), "]/text())[1]'', ''VARCHAR(50)'') AS [", string(($r/text())[1]),"]")
return if ($r is (/env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data[last()])[1]) then string($line)
else concat($line, sql:variable("#separator"))
').value('.', 'NVARCHAR(MAX)');
SET #sql = N';WITH XMLNAMESPACES (''http://schemas.xmlsoap.org/soap/envelope/'' as env, ''http://service.apiendpoint.com'' as ns2)
SELECT ' + #sql + N'
FROM #x.nodes(''/env:Envelope/env:Body/ns2:getReportResultResponse/return/records/values'') AS t(c)
';
EXEC sp_executesql #stmt = #sql, #params = N'#x xml', #x = #x;
Output
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+
| CUSTOMER NAME | DISPOSITION GROUP A | DISPOSITION GROUP B | DISPOSITION GROUP C | DISPOSITION PATH | FIRST DISPOSITION | LAST DISPOSITION | LIST NAME |
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+
| Mark Smith | 12 | 19 | 23 | NULL | NULL | NULL | Tier 1 |
| B | 2 | 22 | 222 | NULL | NULL | NULL | Tier 2 |
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+

Query for extract string from xml in sql

In SQL Server 2012, I have a table DEFINITIONS and a column in it that value of it is XML and name of column is "XML". I want to extract string "[CDATA[xxxx]]" from XML column (in parameter tag). how can I do that?
XML Example value:
<CatalogItem subType="0" type="82">
<id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
<name>Test White</name>
<description />
<attributes>0</attributes>
<parameters><conditions><condition grouping="or"><prop-key>usb_device_serial_number</prop-key><op-key>equals</op-key><value><![CDATA[gdefgd||]]></value></condition></conditions></parameters>
<customParameterNames />
<enforceProducts>
<Product type="WIN" />
</enforceProducts>
</CatalogItem>
Update 1
This Query solve my problem:
if object_id('dbo.cdata') is not null drop table dbo.cdata;
create table dbo.cdata(
x xml
);
insert into dbo.cdata(x)
SELECT XML FROM [HQ-MC-SRV-01].[dbo].[DEFINITIONS]
select
xv.v.value('.', 'nvarchar(max)') as cdata
from dbo.cdata
cross apply
cdata.x.nodes(
'//parameters'
) as pp(p)
cross apply (
values(
cast(pp.p.value(
'.', 'nvarchar(max)'
) as xml)
)
) as xp(p)
cross apply
xp.p.nodes('//value') as xv(v)
;
Thanks a Lot, Andrei Odegov
Update 2
i have to extract "serialNumber" and "endUser" from this XML with previous query too.
<CatalogItem subType="0" type="93">
<id>9d6825e6-fa89-44e1-8e0f-61768016624c</id>
<name>tteesstt</name>
<description />
<attributes>0</attributes>
<entries>
<entry>
<serialNumber>zsxxdx</serialNumber>
<userType>user</userType>
<endUser>farhad#drf.local</endUser>
<description />
</entry>
</entries>
</CatalogItem>
Update 3
<CatalogItem subType="0" type="12">
<id>169d6139-bdb6-4fff-88e6-09f00dd2f155</id>
<name>za</name>
<description />
<attributes>0</attributes>
<SIDMode>true</SIDMode>
<nameIdentificationType>1</nameIdentificationType>
<entries>
<entry>
<name>farhad</name>
<path>CN=farhad,CN=Users,DC=DCVLAB,DC=LOCAL</path>
<uid>F7A84834EAC8984AA7FBEAD7A5539432</uid>
<serverName>192.168.7.2</serverName>
<sid>S-1-5-21-907365782-933549064-1582919620-1103</sid>
<type>user</type>
<entry>
<name>IT-MNG</name>
<path>CN=IT,CN=Users,DC=sglab,DC=local</path>
<uid>BEDC7DDF93A8D54DAC7A5CEE7307BF4F</uid>
<serverName>192.168.7.201</serverName>
<sid>S-1-5-21-3362085216-3357124804-2073486349-1107</sid>
<type>user</type>
</entry>
</entries>
</CatalogItem>
Taking into account your test data, you can try to adapt the following code:
declare #x xml = '
<CatalogItem subType="0" type="82">
<id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
<name>Test White</name>
<description />
<attributes>0</attributes>
<parameters><conditions><condition grouping="or"><prop-key>usb_device_serial_number</prop-key><op-key>equals</op-key><value><![CDATA[gdefgd||]]></value></condition></conditions></parameters>
<customParameterNames />
<enforceProducts>
<Product type="WIN" />
</enforceProducts>
</CatalogItem>
';
select cast(#x.value('(//parameters)[1]', 'nvarchar(max)') as xml).query('//value/text()') as cdata;
Output
+----------+
| cdata |
+----------+
| gdefgd|| |
+----------+
Update:
if object_id('dbo.cdata') is not null drop table dbo.cdata;
create table dbo.cdata(
x xml
);
insert into dbo.cdata(x)
values ('
<CatalogItem subType="0" type="82">
<id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
<name>Test White</name>
<description />
<attributes>0</attributes>
<parameters><conditions><condition grouping="or"><prop-key>usb_device_serial_number</prop-key><op-key>equals</op-key><value><![CDATA[gdefgd||]]></value><value><![CDATA[foo]]></value></condition></conditions></parameters>
<parameters><conditions><condition grouping="or"><prop-key>usb_device_serial_number</prop-key><op-key>equals</op-key><value><![CDATA[gdefgd||170]]></value><value><![CDATA[foo170]]></value></condition></conditions></parameters>
<customParameterNames />
<enforceProducts>
<Product type="WIN" />
</enforceProducts>
</CatalogItem>
'), ('
<CatalogItem subType="0" type="82">
<id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
<name>Test White</name>
<description />
<attributes>0</attributes>
<parameters><conditions><condition grouping="or"><prop-key>usb_device_serial_number</prop-key><op-key>equals</op-key><value><![CDATA[gdefgd||42]]></value><value><![CDATA[foo42]]></value></condition></conditions></parameters>
<customParameterNames />
<enforceProducts>
<Product type="WIN" />
</enforceProducts>
</CatalogItem>
');
select
xv.v.value('.', 'nvarchar(max)') as cdata
from dbo.cdata
cross apply
cdata.x.nodes(
'//parameters'
) as pp(p)
cross apply (
values(
cast(pp.p.value(
'.', 'nvarchar(max)'
) as xml)
)
) as xp(p)
cross apply
xp.p.nodes('//value') as xv(v);
Update #2:
You can get more detail information about working in Sql Server with XML data in the "XQuery Language Reference (SQL Server)".There are two articles on the CROSS and OUTER APPLY operators with examples of their application to XML data.
select
replace(xv.v.value('.', 'nvarchar(max)'), '|', '') as cdata,
xci.ci.value('(//serialNumber)[1]', 'nvarchar(15)') as sn,
xci.ci.value('(entries/entry/endUser)[1]', 'nvarchar(50)') as eu,
xci.ci.value('(entries/entry/name)[1]', 'nvarchar(50)') as name
from dbo.cdata
cross apply
cdata.x.nodes('/CatalogItem') as xci(ci)
outer apply
xci.ci.nodes('parameters') as pp(p)
outer apply (
values(
cast(pp.p.value(
'.', 'nvarchar(max)'
) as xml)
)
) as xp(p)
outer apply
xp.p.nodes('//value') as xv(v);
Output:
+-----------+--------+------------------+--------+
| cdata | sn | eu | name |
+-----------+--------+------------------+--------+
| gdefgd | zsxxdx | farhad#drf.local | NULL |
| foo | zsxxdx | farhad#drf.local | NULL |
| gdefgd170 | zsxxdx | farhad#drf.local | NULL |
| foo170 | zsxxdx | farhad#drf.local | NULL |
| NULL | foobar | user#mail.net | NULL |
| NULL | NULL | NULL | farhad |
+-----------+--------+------------------+--------+
Test it online with Rextester.

SQL xml merge first row values with rest of the rows

I would like to know in SQL Server how do I take the following XML and represent the following table.
<Family>
<Main Surname="Smith" />
<Person Name="Fred" />
<Person Name="Jane" />
</Family>
Row Name Surname
1 Fred Smith
2 Jane Smith
Please note I cannot change the XML schema.
Here is my current SQL query.
declare #Input XML
set #Input = '<Family> <Main Surname="Smith" /> <Person Name="Fred" /> <Person Name="Jane" /> </Family>'
SELECT
Test.value('(#Name)[1]', 'varchar(20)') as Name,
Test.value('(#Surname)[1]', 'varchar(20)') as Surname
FROM #Input.nodes('/Family/*') AS Tbl(Test)
OPTION ( OPTIMIZE FOR ( #Input = NULL ) )
DECLARE #xml XML = '
<Family>
<Main Surname="Smith" />
<Person Name="Fred" />
<Person Name="Jane" />
</Family>'
SELECT
RowNum = ROW_NUMBER() OVER (ORDER BY 1/0)
, t.c.value('#Name', 'VARCHAR(20)')
, t2.c2.value('#Surname', 'VARCHAR(20)')
FROM #xml.nodes('Family/Person') t(c)
CROSS APPLY t.c.nodes('../Main') t2(c2)
results -
-------------------- -------------------- --------------------
1 Fred Smith
2 Jane Smith

Transform XML to Table data using XQuery in SQL Server

Is it possible to achieve the following table from of output using XQuery in SQL Server
Edit: A change in my requirement, Consider i have a table which stores the below xml and also UserID
DECLARE #XML xml
set #XML = '<Security>
<FiscalYear Name="2012">
<Country Id="204">
<State Id="1">
<City Id="10"></City>
</State>
<State Id="2">
<City Id="20"></City>
<City Id="30"></City>
</State>
<State Id ="3"></State>
</Country >
</FiscalYear>
</Security>'
CREATE TABLE #tmp_user
(UserID INT,SecurityXML XML)
INSERT INTO #tmp_user
( UserID, SecurityXML )
VALUES ( 1,
#XML
)
Now how can i get a o/p like
Output:
UserID StateID CityID
1 1 10
1 2 20
1 2 30
1 3 0
Is it possible to achieve?
I modified your XML a bit because it was invalid. Change the end tag </Subsidiary> to </Country>.
declare #XML xml
set #XML =
'<Security>
<FiscalYear Name="2012">
<Country Id="204">
<State Id="1">
<City Id="10"></City>
</State>
<State Id="2">
<City Id="20"></City>
<City Id="30"></City>
</State>
<State Id ="3"></State>
</Country>
</FiscalYear>
</Security>'
select S.N.value('#Id', 'int') as StateID,
coalesce(C.N.value('#Id', 'int'), 0) as CityID
from #XML.nodes('/Security/FiscalYear/Country/State') as S(N)
outer apply S.N.nodes('City') as C(N)
A version using a table instead of XML variable
select T.UserID,
S.N.value('#Id', 'int') as StateID,
coalesce(C.N.value('#Id', 'int'), 0) as CityID
from #tmp_user as T
cross apply T.SecurityXML.nodes('/Security/FiscalYear/Country/State') as S(N)
outer apply S.N.nodes('City') as C(N)