There are 3 attributes I am trying to return when reading this xml file. 2 of the 3 are returning expected values. I can not figure out why I can't get the id to return the value. It always returns NULL. How can I get the proper value of rid1 and rid2
DECLARE #xml xml
SELECT #xml = BulkColumn
FROM OPENROWSET(BULK 'C:\data\workbook.xml', SINGLE_BLOB) x;
WITH XMLNAMESPACES (default
'http://schemas.openxmlformats.org/spreadsheetml/2006/main' ,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships' as a,
'http://schemas.openxmlformats.org/markup-compatibility/2006' as b,
'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main' as c,
'http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac' as d)
SELECT
doc.col.value('#name', 'nvarchar(10)') sheet
,doc.col.value('#id', 'nvarchar(max)') rid
,doc.col.value('#sheetId', 'int') id
FROM #xml.nodes('*:workbook/sheets/sheet') doc(col)
Here is the XML File
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" mc:Ignorable="x15">
<fileVersion appName="xl" lastEdited="7" lowestEdited="7" rupBuild="18431" />
<workbookPr defaultThemeVersion="166925" />
<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<mc:Choice Requires="x15">
<x15ac:absPath xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac" url="C:\data\" />
</mc:Choice>
</mc:AlternateContent>
<bookViews>
<workbookView xWindow="0" yWindow="0" windowWidth="21576" windowHeight="7968" />
</bookViews>
<sheets>
<sheet name="Sheet1" sheetId="1" r:id="rId1" />
<sheet name="Sheet2" sheetId="2" r:id="rId2" />
</sheets>
<calcPr calcId="171027" />
<fileRecoveryPr repairLoad="1" />
<extLst>
<ext xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" uri="{140A7094-0E35-4892-8432-C4D2E57EDEB5}">
<x15:workbookPr chartTrackingRefBase="1" />
</ext>
</extLst>
</workbook>
You need to prefix the attribute with the namespace like so:
SELECT
doc.col.value('#name', 'nvarchar(10)') sheet
,doc.col.value('#a:id', 'nvarchar(max)') rid
,doc.col.value('#sheetId', 'int') id
FROM #xml.nodes('*:workbook/sheets/sheet') doc(col)
Give your namespaces the same aliases in your T-SQL as they have in your XML and use the namespace alias in your reference:
WITH XMLNAMESPACES (DEFAULT 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
'http://schemas.openxmlformats.org/officeDocument/2006/relationships' AS r,
'http://schemas.openxmlformats.org/markup-compatibility/2006' AS mc,
'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main' AS x15,
'http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac' AS x15ac)
SELECT doc.col.value('#name', 'nvarchar(10)') sheet,
doc.col.value('#r:id', 'nvarchar(max)') rid,
doc.col.value('#sheetId', 'int') id
FROM #xml.nodes('*:workbook/sheets/sheet') doc(col);
Related
This query returns the attribute value "storedId1"
SET #xml = N'<Data>
<Ref ID="1" sf="storedId1">
this is the value I want
</Ref>
</Data>'
SELECT
T.C.value('#sf', 'nvarchar(MAX)') AS result
FROM
#xml.nodes('Data/Ref') T(C)
WHERE
T.C.value('#sf', 'nvarchar(MAX)') = 'storedId1'
How can I return the node value instead .i.e. return "this is the value i want"
I guess I need to change the SELECT to something like
SELECT T.C.value('Data/Ref', 'nvarchar(MAX)') AS result
But it fails with
XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
Try this:
SELECT
T.C.value('(./text())[1]', 'nvarchar(MAX)') AS result
FROM
#xml.nodes('Data/Ref[#sf="storedId1"]') T(C)
DECLARE #xml xml
SET #xml = N'<Data>
<Ref ID="1" sf="storedId1">
this is the value I want
</Ref>
</Data>'
SELECT
T.C.value('.', 'nvarchar(MAX)') AS result
FROM
#xml.nodes('Data/Ref') T(C)
WHERE
T.C.value('#sf', 'nvarchar(MAX)') = 'storedId1'
Demo: http://sqlfiddle.com/#!18/a7540/28512
I'm working with XML data and want to return the values of two child nodes. I can get this work with a single node but not return two seperate columns. How do I write the xPath and xQuery to return two columns?
DECLARE #x XML
Set #x = '
<MT_BoxTextCtrl>
<DataSpec>ShipID_3_1_1</DataSpec>
<Label>Mode</Label>
<Size>230,30</Size>
<Units />
<UserLoValue />
</MT_BoxTextCtrl>
<MT_BoxTextCtrl>
<DataSpec>ShipID_3_1_2</DataSpec>
<Label>Sub Mode</Label>
<Size>230,30</Size>
<Units />
<UserLoValue />
</MT_BoxTextCtrl>
<MT_AlarmCtrl>
<AlarmRngIsReversed>False</AlarmRngIsReversed>
<CustomQuery />
<DataSpec>ShipID_9_1_1</DataSpec>
<HiValue>1</HiValue>
<Label />
</MT_AlarmCtrl>
<MT_AlarmCtrl>
<AlarmRngIsReversed>False</AlarmRngIsReversed>
<CustomQuery />
<DataSpec>ShipID_9_1_5</DataSpec>
<HiValue>1</HiValue>
<Label>In 500M DP Zone</Label>
</MT_AlarmCtrl>'
Select T.c.value('.', 'varchar(30)') as 'DataSpec'
from #x.nodes('//DataSpec') T(c)
Select T.c.value('.', 'varchar(30)') as Label
from #x.nodes('//Label') T(c)
thanks
Try this:
SELECT
NodeType = XC.value('local-name(.)', 'varchar(25)'),
DataSpec = XC.value('(DataSpec)[1]', 'varchar(30)'),
Label = XC.value('(Label)[1]', 'varchar(30)')
FROM
#x.nodes('/*') XT(XC)
This basically takes every top-level node and returns a "virtual" table of those XML fragments. From those XML fragments, I grab the node name (the "type" of the XML node in question), the DataSpec and the Label subelements (their textual values).
I get an output like this:
What am I not getting here? I can't get any return except NULL...
DECLARE #xml xml
SELECT #xml = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<webregdataResponse>
<result>0</result>
<regData />
<errorFlag>99</errorFlag>
<errorResult>Not Processed</errorResult>
</webregdataResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'
DECLARE #nodeVal int
SELECT #nodeVal = #xml.value('(errorFlag)[1]', 'int')
SELECT #nodeVal
Here is the solution:
DECLARE #xml xml
SELECT #xml = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<webregdataResponse>
<result>0</result>
<regData />
<errorFlag>99</errorFlag>
<errorResult>Not Processed</errorResult>
</webregdataResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'
declare #table table (data xml);
insert into #table values (#xml);
WITH xmlnamespaces (
'http://schemas.xmlsoap.org/soap/envelope/' as [soap])
SELECT Data.value('(/soap:Envelope/soap:Body/webregdataResponse/errorFlag)[1]','int') AS ErrorFlag
FROM #Table ;
Running the above SQL will return 99.
Snapshot of the result is given below,
That's because errorFlag is not the root element of your XML document. You can either specify full path from root element to errorFlag, for example* :
SELECT #nodeVal = #xml.value('(/*/*/*/errorFlag)[1]', 'int')
or you can use descendant-or-self axis (//) to get element by name regardless of it's location in the XML document, for example :
SELECT #nodeVal = #xml.value('(//errorFlag)[1]', 'int')
*: I'm using * instead of actual element name just to simplify the expression. You can also use actual element names along with the namespaces, like demonstrated in the other answer.
I'm retrieving xml formatted text from ntext fields (sample format of a row below):
<root>
<DocInfo>
<CompanyName>Some Company</CompanyName>
<WebsiteUrl>http://www.someurl.com</WebsiteUrl>
<PrimaryServices>Benefits Administration</PrimaryServices>
<PrimaryServices>Payroll Processing</PrimaryServices>
<SecondaryServices>Background Checking</SecondaryServices>
<SecondaryServices>HR Outsourcing</SecondaryServices>
<SecondaryServices>Comp & Benefits</SecondaryServices>
<SecondaryServices>Administration</SecondaryServices>
</DocInfo>
</root>
Using this sql I am retrieving the single node values:
select #xmlString = COALESCE(#xmlString + '', '') + cast(content_html as nvarchar(max)) FROM content where folder_id = 18
set #xmlString = replace(#xmlString,'<?xml version="1.0" encoding="UTF-16" standalone="yes"?>','')
set #XML = cast(#xmlString as xml)
Select
T.N.value('CompanyName[1]', 'varchar(250)') as CompanyName,
T.N.value('WebsiteUrl[1]', 'varchar(250)') as WebsiteUrl,
T.N.value('PrimaryServices[1]', 'varchar(250)') as PrimaryServices,
T.N.value('SecondaryServices[1]', 'varchar(250)') as SecondaryServices,
T.N.value('Description[1]', 'varchar(max)') as Description
from #XML.nodes('/root/DocInfo') as T(N)
This works fine for the single node values (CompanyName, WebsiteUrl). However, it isn't inserting the nodes with multiple values properly (like PrimaryServices and SecondaryServices - each of which may have zero to 16 nodes). How do I get these variable length multiple node values into these columns?
Thanks for any help
To get the multiple nodes as a comma separated value you can use a variant of the for xml path('') trick. Use the shredded XML (T.N) as a source in the sub-query to get the nodes you are interested in. The xQuery ... substring(text()[1]) ... part is just there to remove the extra comma and to get the comma separated value out of the XML that is created by for xml.
select
T.N.value('(CompanyName/text())[1]', 'varchar(250)') as CompanyName,
T.N.value('(WebsiteUrl/text())[1]', 'varchar(250)') as WebsiteUrl,
(
select ', '+P.N.value('text()[1]', 'varchar(max)')
from T.N.nodes('PrimaryServices') as P(N)
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as PrimaryServices,
(
select ', '+S.N.value('text()[1]', 'varchar(max)')
from T.N.nodes('SecondaryServices') as S(N)
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as SecondaryServices,
T.N.value('(Description/text())[1]', 'varchar(max)') as Description
from #XML.nodes('/root/DocInfo') as T(N)
If you want all the services in one column you can use a different xPath in the nodes part in the sub-query.
select
T.N.value('(CompanyName/text())[1]', 'varchar(250)') as CompanyName,
T.N.value('(WebsiteUrl/text())[1]', 'varchar(250)') as WebsiteUrl,
(
select ', '+P.N.value('text()[1]', 'varchar(max)')
from T.N.nodes('PrimaryServices,SecondaryServices') as P(N)
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as Services,
T.N.value('(Description/text())[1]', 'varchar(max)') as Description
from #XML.nodes('/root/DocInfo') as T(N)
Please consider this simple example. I can't get the text of the state element 'red' or 'blue' Please help!!!!! this is driving me batty
DECLARE #xml XML;
SET #xml = '<capitals>
<state name="Alabama"
abbreviation="AL"
capital="Montgomery" >red</state>
<state name="Alaska"
abbreviation="AK"
capital="Juneau" >blue</state>
<state name="Arizona"
abbreviation="AZ"
capital="Phoenix" >green</state>
</capitals>';
SELECT Node.value('#name', 'varchar(100)') AS Name,
Node.value('#abbreviation', 'varchar(2)') AS Abbreviation,
Node.value('#capital', 'varchar(100)') AS Capital
FROM #xml.nodes('/capitals/state') TempXML (Node);
You just have to use the . to get the inner text of the element. You can also use text()[1] There is a really good tutorial and examples on xPath in here.
DECLARE #xml XML;
SET #xml = '<capitals>
<state name="Alabama"
abbreviation="AL"
capital="Montgomery" >red</state>
<state name="Alaska"
abbreviation="AK"
capital="Juneau" >blue</state>
<state name="Arizona"
abbreviation="AZ"
capital="Phoenix" >green</state>
</capitals>';
SELECT Node.value('#name', 'varchar(100)') AS Name,
Node.value('#abbreviation', 'varchar(2)') AS Abbreviation,
Node.value('#capital', 'varchar(100)') AS Capital,
Node.value('.', 'varchar(100)') AS Color
FROM #xml.nodes('/capitals/state') TempXML (Node);
I guess I am silly:
Node.value('.','varchar(100)') AS PoliticalDisposition