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.
Related
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
I create table in oracle 12c like this
CREATE TABLE Test_xml
(
xml_data SYS.XMLTYPE
)
and insert XML data like this into column xml_data
<?xml version="1.0" encoding="UTF-8"?>
<persons xmlns="http://XXXXX.XXX/schema/1.0" name="ABC">
<person>
<name1 value="AAAA" />
<name2 value="CCCC" />
<name3 value="XXXX" />
</person>
<person>
<name1 value="11111" />
<name2 value="22222" />
<name3 value="33333" />
</person>
</persons>
but when I try to select data out from table by query
SELECT xt.*
FROM Test_xml x,
XMLTABLE('/persons/person'
PASSING x.xml_data
COLUMNS
name1 VARCHAR2(2000) PATH 'name1/#value'
) xt;
not thing out from the query,How can i select name1 from the table?
You can provide the (default, in this case) namespace as another argument to XMLTable:
SELECT xt.*
FROM Test_xml x,
XMLTABLE(
xmlnamespaces(default 'http://XXXXX.XXX/schema/1.0'),
'/persons/person'
PASSING x.xml_data
COLUMNS
name1 VARCHAR2(2000) PATH 'name1/#value'
) xt;
| NAME1 |
| :---- |
| AAAA |
| 11111 |
db<>fiddle showing your original query, #Sayan's wildcard version (which gets nulls for some reason, even though it works with a CTE), and this default namespace version.
Just replace /persons/person to /*:persons/*:person
SELECT/*+ NO_XML_QUERY_REWRITE */ xt.*
FROM Test_xml x,
XMLTABLE('/*:persons/*:person'
PASSING x.xml_data
COLUMNS
name1 VARCHAR2(2000) PATH '*:name1/#value'
) xt;
Full example:
with test_xml(xml_data) as (
select xmltype(q'[<?xml version="1.0" encoding="UTF-8"?>
<persons xmlns="http://XXXXX.XXX/schema/1.0" name="ABC">
<person>
<name1 value="AAAA" />
<name2 value="CCCC" />
<name3 value="XXXX" />
</person>
<person>
<name1 value="11111" />
<name2 value="22222" />
<name3 value="33333" />
</person>
</persons>]'
)
from dual
)
SELECT xt.*
FROM Test_xml x,
XMLTABLE('/*:persons/*:person'
PASSING x.xml_data
COLUMNS
name1 VARCHAR2(2000) PATH '*:name1/#value'
) xt;
NAME1
--------------------
AAAA
11111
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 |
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+
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
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)