SQL Server xquery sum cast error when schema data type is string - sql

Trying to run this in SQL Server 2014 in order to sum all Values in "UserData" xml:
IF EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'SC')
DROP XML SCHEMA COLLECTION SC
go
CREATE XML SCHEMA COLLECTION SC AS N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="UserData"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Item" minOccurs="0" maxOccurs="unbounded"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Value" type="xsd:string" /><xsd:any minOccurs="0" /></xsd:sequence><xsd:attribute name="Key" type="xsd:string" /><xsd:attribute name="Type" type="xsd:string" /></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:sequence></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:schema>'
go
Declare #xml xml(SC)
set #xml= '<UserData>
<Item Key="CONVERTED_PAGES_1" Type="CONVERTED_PAGES">
<Value>2</Value>
</Item>
<Item Key="CONVERTED_PAGES_2" Type="CONVERTED_PAGES">
<Value>4</Value>
</Item>
</UserData>'
Select #xml.value('sum(/UserData/Item[#Type="CONVERTED_PAGES"]/Value)','int') as Sum
and getting the following error:
Msg 9308, Level 16, State 1, Line 16
XQuery [value()]: The argument of 'sum()' must be of a single numeric primitive type or 'http://www.w3.org/2004/07/xpath-datatypes#untypedAtomic'. Found argument of type 'xs:string *'.
I tried changing the select to the following:
Select #xml.value('sum(/UserData/Item[#Type="CONVERTED_PAGES"]/Value cast as xs:int?)','int') as Sum
But then I get this:
Msg 2365, Level 16, State 1, Line 16 XQuery [value()]: Cannot
explicitly convert from 'xs:string *' to 'xs:int ?'
I am not able to change the xml schema in this case, but figured I could cast in order to perform this operation (since I know that in my case all of the Values will be int). Any suggestions would be appreciated!

The xquery sum aggregate requires the input to be a number. Currently it is defined as string in your XSD. To get this to work, you have three options:
Option 1:
You change the schema to force "value" to be an int. Instead of the first line below, use the second. (The difference is highlighted in between the two statements with "|||||||".)
Query 1:
CREATE XML SCHEMA COLLECTION SC AS N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="UserData"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Item" minOccurs="0" maxOccurs="unbounded"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Value" type="xsd:string" /><xsd:any minOccurs="0" /></xsd:sequence><xsd:attribute name="Key" type="xsd:string" /><xsd:attribute name="Type" type="xsd:string" /></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:sequence></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:schema>'
|||||||
CREATE XML SCHEMA COLLECTION SC AS N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="UserData"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Item" minOccurs="0" maxOccurs="unbounded"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Value" type="xsd:integer" /><xsd:any minOccurs="0" /></xsd:sequence><xsd:attribute name="Key" type="xsd:string" /><xsd:attribute name="Type" type="xsd:string" /></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:sequence></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:schema>'
Option 2:
If changing the XSD is not an option, you can also use the T-SQL SUM aggregate instead of the xquery one, like this:
Query 2:
IF EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'SC')
DROP XML SCHEMA COLLECTION SC
go
CREATE XML SCHEMA COLLECTION SC AS N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="UserData"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Item" minOccurs="0" maxOccurs="unbounded"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Value" type="xsd:string" /><xsd:any minOccurs="0" /></xsd:sequence><xsd:attribute name="Key" type="xsd:string" /><xsd:attribute name="Type" type="xsd:string" /></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:sequence></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:schema>'
go
Declare #xml xml(SC)
set #xml= '<UserData>
<Item Key="CONVERTED_PAGES_1" Type="CONVERTED_PAGES">
<Value>2</Value>
</Item>
<Item Key="CONVERTED_PAGES_2" Type="CONVERTED_PAGES">
<Value>4</Value>
</Item>
</UserData>'
SELECT SUM(N.value('.','INT')) AS [Sum]
FROM #xml.nodes('/UserData/Item[#Type="CONVERTED_PAGES"]/Value') AS X(N);
Option 3:
As you noticed, SQL Server does not allow us to convert an XSD-typed value to another data type. To get around that, you could instruct SQL Server to forget about the schema:
Query 3:
IF EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'SC')
DROP XML SCHEMA COLLECTION SC;
GO
CREATE XML SCHEMA COLLECTION SC AS N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="UserData"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Item" minOccurs="0" maxOccurs="unbounded"><xsd:complexType><xsd:complexContent><xsd:restriction base="xsd:anyType"><xsd:sequence><xsd:element name="Value" type="xsd:string" /><xsd:any minOccurs="0" /></xsd:sequence><xsd:attribute name="Key" type="xsd:string" /><xsd:attribute name="Type" type="xsd:string" /></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:sequence></xsd:restriction></xsd:complexContent></xsd:complexType></xsd:element></xsd:schema>';
GO
DECLARE #xml XML(SC);
SET #xml= '<UserData>
<Item Key="CONVERTED_PAGES_1" Type="CONVERTED_PAGES">
<Value>2</Value>
</Item>
<Item Key="CONVERTED_PAGES_2" Type="CONVERTED_PAGES">
<Value>4</Value>
</Item>
</UserData>';
SELECT CAST(#xml AS XML).value('sum((/UserData/Item[#Type="CONVERTED_PAGES"]/Value ))','int') AS Sum;
Note: Without the schema, you still cannot cast (not sure why), but the sum now works without casting.
Update:
I did a little more digging. The original error message you got after attempting to cast is this one:
Msg 2365, Level 16, State 1, Line 16 XQuery [value()]: Cannot
explicitly convert from 'xs:string *' to 'xs:int ?'
It tells us that you can't convert a sequence of strings into a single integer.
The * as well as the ? are Occurrence Indicators. So the error message reads: zero-to-many strings can't be converted to zero-to-one integer.
Your xquery /UserData/Item[#Type="CONVERTED_PAGES"]/Value returns more than one value, and to sum them up we need to convert each one individually.
xquery offers multiple ways to accomplish that, but not all of them work in SQL Server. The one that works uses a for-each construct:
.value('sum(for $val in /UserData/Item[#Type="CONVERTED_PAGES"]/Value return $val cast as xs:int?)','INT');
Thanks to #MikaelEriksson for helping me out with this.

Related

Q. How to select named element values from XSD string field

Within SQL Server I'm trying to select values from what I think is a XSD string.
e.g. Given the following SQL Server table
CREATE TABLE dbo.TextXML (
ID INT PRIMARY KEY,
Data NVARCHAR(max))
INSERT INTO dbo.TextXML ( ID, Data )
SELECT 1,
('<element name="Rownum" value="Row23" />
<element name="CONNECTIONTYPESECTION" value="True" />
<element name="CustomFields" />
<element name="EchoData">
<element name="0000" value="8220000000000000" />
<element name="0001" value="0400000100000000" />
<element name="0007" value="0805193143" />
<element name="MessageType" value="1234" />
</element>
<element name="ENABLESSL" value="false" />' )
INSERT INTO dbo.TextXML ( ID, Data )
SELECT 2,
('<element name="Rownum" value="Row24" />
<element name="CONNECTIONTYPESECTION" value="True" />
<element name="CustomFields" />
<element name="EchoData">
<element name="0000" value="8220000000000000" />
<element name="0001" value="0400000100000000" />
<element name="0007" value="0805193143" />
<element name="MessageType" value="5678" />
</element>
<element name="ENABLESSL" value="true" />' );
I want to be able to select the values for given element names. Something like ...
SELECT ID, Data.CONNECTIONTYPESECTION, Data.EchoData.0007, Data.EchoData.MessageType, Data.ENABLESSL
FROM TextXML
WHERE Data.Rownum = "Row23" AND Data.EchoData.MessageType = "1234".
ID Data.CONNECTIONTYPESECTION Data.EchoData.0007 Data.EchoData.MessageType Data.ENABLESSL
1 True 0805193143 1234 true
I can use CHARINDEX and SUBSTRING but have to hardcode the length of the "name" value and this asumes the "value" is always the same length. I'm hoping there is a better and more efficient way do do this.
I have experimented with CROSS APPPLY and XML VALUE functions but this only returns the first element in the Data field. I also could not find out how to search for a particular element "name" to get its value
Please try the following T-SQL.
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, Data NVARCHAR(max));
INSERT INTO #tbl (Data) VALUES
(N'<element name="Rownum" value="Row23"/>
<element name="CONNECTIONTYPESECTION" value="True"/>
<element name="CustomFields"/>
<element name="EchoData">
<element name="0000" value="8220000000000000"/>
<element name="0001" value="0400000100000000"/>
<element name="0007" value="0805193143"/>
<element name="MessageType" value="1234"/>
</element>
<element name="ENABLESSL" value="false"/>'),
(N'<element name="Rownum" value="Row24"/>
<element name="CONNECTIONTYPESECTION" value="True"/>
<element name="CustomFields"/>
<element name="EchoData">
<element name="0000" value="8220000000000000"/>
<element name="0001" value="0400000100000000"/>
<element name="0007" value="0805193143"/>
<element name="MessageType" value="5678"/>
</element>
<element name="ENABLESSL" value="true"/>');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT *
, TRY_CAST(data AS XML) AS xmldata
FROM #tbl
)
SELECT rs.ID
, xmldata.value('(element[#name="CONNECTIONTYPESECTION"]/#value)[1]','VARCHAR(10)') AS CONNECTIONTYPESECTION
, xmldata.value('(element[#name="EchoData"]/element[#name="0007"]/#value)[1]','VARCHAR(10)') AS [EchoData.0007]
, xmldata.value('(element[#name="EchoData"]/element[#name="MessageType"]/#value)[1]','VARCHAR(10)') AS [EchoData.MessageType]
, xmldata.value('(element[#name="ENABLESSL"]/#value)[1]','VARCHAR(10)') AS [Data.ENABLESSL]
FROM rs
WHERE xmldata.value('(element[#name="Rownum"]/#value)[1]','VARCHAR(30)') = 'Row23'
AND xmldata.value('(element[#name="EchoData"]/element[#name="MessageType"]/#value)[1]','VARCHAR(10)') = '1234';
Output
+----+-----------------------+---------------+----------------------+----------------+
| ID | CONNECTIONTYPESECTION | EchoData.0007 | EchoData.MessageType | Data.ENABLESSL |
+----+-----------------------+---------------+----------------------+----------------+
| 1 | True | 0805193143 | 1234 | false |
+----+-----------------------+---------------+----------------------+----------------+

Convert XML column to Table Data in SQL Query

I have this XML file which is a returned data table from web service:
DECLARE #MyXML XML =
'<?xml version="1.0" encoding="utf-8"?>
<DataTable xmlns="http://tempuri.org/">
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Blah" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Blah">
<xs:complexType>
<xs:sequence>
<xs:element name="Col1" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<DocumentElement xmlns="">
<Blah diffgr:id="Blah1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<Col1>testing1</Col1>
</Blah>
</DocumentElement>
</diffgr:diffgram>
</DataTable>'
I want an output like this:
Select Col1
Col1
testing1
Then, I would be able to insert the data into a table in sql.
Is this XML under your control?
I'm especially irritated by this
<DocumentElement xmlns="">
This line is redefining the default namespace.
The XML you show consists of a schema portion and a data portion
DECLARE #MyXML XML =
'<?xml version="1.0" encoding="utf-8"?>
<DataTable xmlns="http://tempuri.org/">
<!-- This schema is describing your data''s structure -->
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Blah" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Blah">
<xs:complexType>
<xs:sequence>
<xs:element name="Col1" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<!-- End of schema -->
<!-- Begin of data -->
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<DocumentElement xmlns="">
<Blah diffgr:id="Blah1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<Col1>testing1</Col1>
</Blah>
</DocumentElement>
</diffgr:diffgram>
<!-- End of data -->
</DataTable>';
Your statement
Then, I would be able to insert the data into a table in sql.
... let's me think, that the real-world use case will consist of more than one column. In this case you do not show enough.
This query would read just the <Col1> content in a lazy approach:
SELECT #MyXML.value('(//*:Col1/text())[1]','nvarchar(max)');
In general it is good to be as specific as possible, but the actual issue looks, as if you might be better off with a namespace wildcard and a deep search (//) down to <DocumentElement>:
SELECT de.query('.')
FROM #MyXml.nodes('//DocumentElement') A(de)
This query will return various content of this area:
SELECT de.value('(Blah/#*:id)[1]','nvarchar(max)') DiffGr_ID
,de.value('(Blah/#*:rowOrder)[1]','int') MsData_RowOrder
,de.value('(Blah/#*:hasChanges)[1]','nvarchar(max)') diffgr_HasChanges
,de.value('(Blah/Col1/text())[1]','nvarchar(max)') Col1_Text
FROM #MyXml.nodes('//DocumentElement') A(de);
The result
DiffGr_ID MsData_RowOrder diffgr_HasChanges Col1_Text
-----------------------------------------------------------
Blah1 0 inserted testing1
INSERT INTO sampletable
(
col1,
col2
)
SELECT
t.value('(col1/text())[1]', 'nvarchar(10)') ---colum name of the xml
t.value('(col2/text())[1]', 'nvarchar(10)') ---colum name of the xml
FROM #xmlData.nodes('/NewDataSet/MYTABLE') AS TempTable(t)
take not ,when the type of the column in the xml is float you need to change the 'narchar(10)' to 'float', or if date use 'date', etc..
You need to set the XML Namespace before using the XQuery:
;WITH XMLNAMESPACES('http://tempuri.org/' AS ns, 'urn:schemas-microsoft-com:xml-diffgram-v1' AS dg)
SELECT
Col1 = XC.value('(Col1)[1]', 'varchar(50)')
FROM
#MyXML.nodes('/ns:DataTable/dg:diffgram/DocumentElement/Blah') AS XT(XC)

Stripping data from xml in SQL Server

One of my tables with xml datatype has the following xml information:
<RequestMetaData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MetaData Type="DocImport">
<Keywords>
<Key Name="Zone" Value="MIO" />
<Key Name="ClassificationStrategy" Value="NeedClassification" />
<Key Name="Folder" Value="0456e6ca" />
</Keywords>
</MetaData>
<MetaData Type="SourceResponse">
<Keywords>
<Key Name="NotificationResponse_20180427-150426" Value="Received successful response from Source" />
</Keywords>
</MetaData>
</RequestMetaData>
I need to write an SQL query to fetch the value of Classification strategy based on key name.
I have added the xml in a variable #xml and used the following code. It is returning NULL.
select A.b.value('ClassificationStrategy[1]', 'VARCHAR(30)') AS CS
FROM #xml.nodes('/RequestMetaData/MetaData/Keywords') AS A(b)
Can someone please help me with this.
You can read your XML in various ways. Use a simple .value() with an XPath/XQuery expression to retrieve a single value, use .query to retrieve a part of the XML or use .nodes() to return repeated elements as derived table:
DECLARE #xml XML=
N'<RequestMetaData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MetaData Type="DocImport">
<Keywords>
<Key Name="Zone" Value="MIO" />
<Key Name="ClassificationStrategy" Value="NeedClassification" />
<Key Name="Folder" Value="0456e6ca" />
</Keywords>
</MetaData>
<MetaData Type="SourceResponse">
<Keywords>
<Key Name="NotificationResponse_20180427-150426" Value="Received successful response from Source" />
</Keywords>
</MetaData>
</RequestMetaData>';
--Read the whole lot
SELECT md.value('#Type','nvarchar(max)') AS MetaDataType
,k.value('#Name','nvarchar(max)') AS KeyName
,k.value('#Value','nvarchar(max)') AS KeyValue
FROM #xml.nodes('/RequestMetaData/MetaData') A(md)
OUTER APPLY md.nodes('Keywords/Key') B(k);
--Get one key's value by name (anywhere in the doc)
DECLARE #keyName VARCHAR(100)='ClassificationStrategy';
SELECT #xml.value('(//Key[#Name=sql:variable("#keyName")]/#Value)[1]','nvarchar(max)');
--Use the meta data type as additional filter (if key names are not unique per doc)
DECLARE #kName VARCHAR(100)='ClassificationStrategy';
DECLARE #mdType VARCHAR(100)='DocImport';
SELECT #xml.value('(/RequestMetaData
/MetaData[#Type=sql:variable("#mdType")]
/Keywords
/Key[#Name=sql:variable("#kName")]
/#Value)[1]','nvarchar(max)');

How to read formated xml file in SQL Server

I have XML file that need to read some data from it by SQL Server 2008.
Please guide me to to solve this problem.
My XML file like that:
<?xml version="1.0" encoding="utf-8"?>
<DataSet xmlns="http://tempuri.org/">
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Table">
<xs:complexType>
<xs:sequence>
<xs:element name="CI_CODE" type="xs:decimal" minOccurs="0" />
<xs:element name="CI_NAME" type="xs:string" minOccurs="0" />
<xs:element name="CI_PISH_CODE" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet xmlns="">
<Table diffgr:id="Table1" msdata:rowOrder="0">
<CI_CODE>1</CI_CODE>
<CI_NAME>Kerman</CI_NAME>
<CI_PISH_CODE>34</CI_PISH_CODE>
</Table>
<Table diffgr:id="Table2" msdata:rowOrder="1">
<CI_CODE>2</CI_CODE>
<CI_NAME>Anar</CI_NAME>
<CI_PISH_CODE>34</CI_PISH_CODE>
</Table>
<Table diffgr:id="Table3" msdata:rowOrder="2">
<CI_CODE>3</CI_CODE>
<CI_NAME>Baft</CI_NAME>
<CI_PISH_CODE>34</CI_PISH_CODE>
</Table>
</NewDataSet>
</diffgr:diffgram>
</DataSet>
I need to help to read this XML in SQL Server 2008.
I need tags <CI_CODE> and <CI_NAME> and <CI_PISH_CODE> data.
Please guide me
Assuming your XML is stored in a variable called #Data XML, you can use this XQuery go get your data.
The XPath expression "navigates" down the tree of nodes to give you a "virtual" table of XML fragments - one for each <Table> XML element. From that XML element, you can then fetch the individual data items using the .value() XQuery expression.
You need to be especially vigilant about using the correct XML namespaces for each element.
;WITH XMLNAMESPACES('http://tempuri.org/' AS ns,
'urn:schemas-microsoft-com:xml-diffgram-v1' AS dg)
SELECT
CI_CODE = XC.value('(CI_CODE)[1]', 'int'),
CI_NAME = XC.value('(CI_NAME)[1]', 'varchar(50)'),
CI_PISH_CODE = XC.value('(CI_PISH_CODE)[1]', 'int')
FROM
#Data.nodes('/ns:DataSet/dg:diffgram/NewDataSet/Table') AS XT(XC)
This produces this output on my PC:
In general I'd advise you to be as specific as possible. In this case you have unclean namespaces (empty default namespace at schema level), which makes it difficult to query this correctly.
Try it wild wildcarded namespace (*:):
EDIT: simplified
--Your XML in a variable
DECLARE #xml XML=
'Copy your XML here';
--The query
SELECT dgt.value('(#*:id)[1]','nvarchar(max)') AS DiffgramTable
,dgt.value('(*:CI_CODE)[1]','int') AS Diffgram_CI_CODE
,dgt.value('(*:CI_NAME)[1]','nvarchar(max)') AS Diffgram_CI_NAME
,dgt.value('(*:CI_PISH_CODE)[1]','int') AS Diffgram_CI_CODE
FROM #xml.nodes('/*:DataSet') AS A(ds)
OUTER APPLY ds.nodes('*:diffgram') AS C(dg)
OUTER APPLY dg.nodes('*:NewDataSet/*:Table') AS D(dgt)
First we pick the "DataSet" and call it "ds". Below this we pick "diffgram" ("dg"). Below "dg" we pick all "Table" ("dgt")
The select will read all information out of the nearest node
The result
+---------------+------------------+------------------+------------------+
| DiffgramTable | Diffgram_CI_CODE | Diffgram_CI_NAME | Diffgram_CI_CODE |
+---------------+------------------+------------------+------------------+
| Table1 | 1 | Kerman | 34 |
+---------------+------------------+------------------+------------------+
| Table2 | 2 | Anar | 34 |
+---------------+------------------+------------------+------------------+
| Table3 | 3 | Baft | 34 |
+---------------+------------------+------------------+------------------+

XML Schema Collection breaks xquery

The script below can be used to show an example of the problem I have. The script will return an error "There is no element named 'this'".
If I change the declaration of the #XML variable so it is untyped XML (replace the line DECLARE #XML XML(Test) with DECLARE #XML XML), I do not get the error, but get the expected result instead.
Why do I get the error when using the Schema collection and how can I avoid it - I want to fill a table column with properly typed xml, but I'm having trouble getting my data back out of the column.
IF EXISTS (SELECT name FROM sys.xml_schema_collections WHERE name = 'test') DROP XML SCHEMA COLLECTION Test
CREATE XML SCHEMA COLLECTION Test AS
'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://tempuri.org/this.xsd"
targetNamespace="http://tempuri.org/this.xsd"
elementFormDefault="qualified">
<xsd:element name ="this">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="What" minOccurs="1" maxOccurs="1" >
<xsd:simpleType>
<xsd:restriction base ="xsd:string">
<xsd:enumeration value ="01."/>
<xsd:enumeration value ="02."/>
<xsd:enumeration value ="03."/>
<xsd:enumeration value ="04."/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="When" minOccurs="1" maxOccurs="1" >
<xsd:simpleType>
<xsd:restriction base ="xsd:string">
<xsd:enumeration value ="01."/>
<xsd:enumeration value ="02."/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Outcome" minOccurs="1" maxOccurs="1" >
<xsd:simpleType>
<xsd:restriction base ="xsd:string">
<xsd:enumeration value ="one"/>
<xsd:enumeration value ="two"/>
<xsd:enumeration value ="whatever"/>
<xsd:enumeration value =""/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>'
GO
DECLARE #XML XML(Test)
SET #XML =
'<this xmlns="http://tempuri.org/this.xsd">
<What>02.</What>
<When>01.</When>
<Outcome></Outcome>
</this>'
SELECT #XML
SELECT
Field.value('What[1]','VARCHAR(100)')
FROM #Xml.nodes('/this') AS this(Field)
The problem is your namespace declaration: <this xmlns="http://tempuri.org/this.xsd">. Everything in that XML snippet belongs to the namespace http://tempuri.org/this.xsd. Your query used the unqualified name for this and What. Use this instead:
;WITH XMLNAMESPACES (
'http://tempuri.org/this.xsd' as t
)
SELECT
Field.value('t:What[1]','VARCHAR(100)')
FROM #Xml.nodes('/t:this') AS this(Field)