Sql server xpath conditionnal query - sql

I have a table where one field called 'configuration' is type of XML:
<configuration>
<element value="john" />
<element value="kevin" />
<element value="lisa" />
<element value="david" />
<element value="mike" />
</configuration>
What I would like to do, is to retrieve all the table records or at least count the table records that have a field 'configuration' containing at least one 'element' attribute containing a 'value' attribute equals to 'lisa'.
What I have for the moment, is a query that can retrieve the 'value' attribute of the specified 'element' position, for example:
select Configuration.value('(/configuration/element/#value)[0]', 'nvarchar(max)') // returns me 'john'
select Configuration.value('(/configuration/element/#value)[1]', 'nvarchar(max)') // returns me 'kevin'

This is a bit of pseudo-SQL in the absence of a dataset, and a bit of guesswork; in that I (think) you simply want to return the rows(?) where there is a the node configuration/element has the value property 'lisa'. IF my guess is right, then something like this will work (you'll ened to replace object names in Braces({}):
SELECT {Columns}
FROM [{Your Table}] YT
WHERE EXISTS (SELECT 1
FROM [{Your Table}] E
CROSS APPLY E.[{Your XML Column}].nodes('configuration/element') C(E)
WHERE E.[{Your ID Column}] = YT.[{Your ID Column}]
AND C.E.value('./#value','varchar(50)') = 'lisa');
Example:
WITH VTE AS(
SELECT 1 AS ID,
CONVERT(xml,'<configuration>
<element value="john" />
<element value="kevin" />
<element value="lisa" />
<element value="david" />
<element value="mike" />
</configuration>') AS XMlCol
UNION ALL
SELECT 2 AS ID,
CONVERT(xml,'<configuration>
<element value="craig" />
<element value="donald" />
<element value="jenny" />
<element value="jayne" />
</configuration>') AS XMlCol)
SELECT *
FROM VTE YT
WHERE EXISTS (SELECT 1
FROM VTE E
CROSS APPLY E.XMlCol.nodes('configuration/element') C(E)
WHERE E.ID = YT.ID
AND C.E.value('./#value','varchar(50)') = 'lisa');
This only returns the row with an ID of 1.

Please try the below,
declare #xml as xml
set #xml='<configuration>
<element value="john" />
<element value="kevin" />
<element value="lisa" />
<element value="david" />
<element value="mike" />
</configuration>'
SELECT T.c.value('./#value','nvarchar(250)' ) As element
FROM #xml.nodes('//element') AS T(c)

Related

Counting rows with the same attributes XML/SQL

Started doing some SQL/XML resently but i have the problem of doing count functions.
Lets say i have the database
<Root>
<Element ATTTRIBUTE1 ="A" ATTRIBUTE2="1" />
<Element ATTRIBUTE1 ="A" ATTRIBUTE2="1" />
<Element ATTRIBUTE1 ="A" ATTRIBUTE2="1" />
<Element ATTRIBUTE1 ="A" ATTRIBUTE2="1" />
<Element ATTRIBUTE1 ="A" ATTRIBUTE2="1" />
<Element ATTRIBUTE1 ="A" ATTRIBUTE2="3" />
<Element ATTRIBUTE1 ="A" ATTRIBUTE2="3" />
<Element ATTRIBUTE1 ="B" ATTRIBUTE2="3" />
<Element ATTRIBUTE1 ="B" ATTRIBUTE2="3" />
<Element ATTRIBUTE1 ="B" ATTRIBUTE2="3" />
<Element ATTRIBUTE1 ="B" ATTRIBUTE2="3" />
<Element ATTRIBUTE1 ="C" ATTRIBUTE2="4" />
<Element ATTRIBUTE1 ="C" ATTRIBUTE2="4" />
</Root>
What can i write in SLQ/XML to make it count how many of each i have that have the two same attributes? So for example i have 5 elements of with attributes A and 1, 2 attributes of A and 3 and two attributes of B and 3 and so on.
I have tried to group them but i kind of just split them up outside the root then.

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 |
+----+-----------------------+---------------+----------------------+----------------+

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)');

Query xml using sql server

i am new to xml queries. i have one xml like
<fields>
<fields name = "a" active ="1" mandat ="true"/>
<fields name = "a" active ="1"/>
</fields>
Now i need to find all the field names that manadt is true. How can i query xml using sql server. please help
Your question is not quite clear, especially the tags (sql, xml, c#-4.0), but from you question's text I take, that you need to query the XML's content within SQL-Server.
You can try it like this
DECLARE #xml XML=
N'<fields>
<fields name="a" active="1" mandat="true" />
<fields name="a" active="1" />
</fields>';
SELECT fld.value(N'#name',N'nvarchar(max)') AS Field_Name
,fld.value(N'#active',N'bit') AS Field_Active
,fld.value(N'#mandat',N'bit') AS Field_Mandant
FROM #xml.nodes(N'/fields/fields') AS A(fld)
The result
Field_Name Field_Active Field_Mandant
a 1 1
a 1 NULL
UPDATE
If you want to read the value of #name of the fields-node, where #mandat is "true", do it like this:
DECLARE #xml XML=
N'<fields>
<fields name="a" active="1" mandat="true" />
<fields name="a" active="1" />
</fields>';
SELECT #xml.value(N'(/fields/fields[#mandat="true"]/#name)[1]',N'nvarchar(max)') AS Mandant_Name
UPDATE 2: More than one <fields> with #mandat="true"
Just try my first solution with a predicate in .nodes():
DECLARE #xml XML=
N'<fields>
<fields name="a" active="1" mandat="true" />
<fields name="b" active="2" />
<fields name="c" active="3" mandat="false" />
<fields name="d" active="4" mandat="true" />
</fields>';
SELECT fld.value(N'#name',N'nvarchar(max)') AS Field_Name
,fld.value(N'#active',N'bit') AS Field_Active
,fld.value(N'#mandat',N'bit') AS Field_Mandant
FROM #xml.nodes(N'/fields/fields[#mandat="true"]') AS A(fld)
This will return only the first and the last <fields> node

How to get element values from an XML column?

I have the XML below in a column. I need to get to \Report\Criterias\Criteria (where name="Advertisers")\Elements\Element(where name="ListViewAvailable"). From here I need to list all the numbers that are in the Value element.
So far I got:
SELECT xmlColumn.query('/Report/Criterias/Criteria/Elements/Element')
from tbl
but no idea how to filter.
<Report>
<Criterias>
<Criteria name="Date Range">
...
</Criteria>
<Criteria name="Advertisers">
<Elements>
<Element name="CheckBoxOne">
<Value>0</Value>
</Element>
<Element name="ListViewAvailable">
<Value>314</Value>
<Value>57</Value>
<Value>18886</Value>
<Value>7437</Value>
</Element>
</Elements>
</Criteria>
<Criteria name="Revenue Types">
...
</Criteria>
</Criterias>
</Report>
You can filter using predicate ([]) in combination with CROSS APPLY to shred the XML on Value elements level :
SELECT C.value('.', 'int') AS Value
FROM tbl t
CROSS APPLY t.xmlColumn.nodes('
/Report/Criterias/Criteria[#name="Advertisers"]
/Elements/Element[#name="ListViewAvailable"]
/Value
') T(C)