Querying XML data in SQL Server 2012 - sql

I have a database that has a table Parameters_XML with columns.
id, application, parameter_nr flag, value
The parameter_nr is for example 1 and the value for that parameter is the following:
<Root>
<Row>
<Item id="341" flags="1">
<Str>2</Str>
</Item>
<Item id="342" flags="1">
<Str>10</Str>
</Item>
<Item id="2196" flags="1">
<Str>7REPJ1</Str>
</Item>
</Row>
</Root>
I need to retrieve the values for all the applications where the item is 341, 342 and 2196.
Eg: for the application 1 the value for the item 341 is 2 and so on.
I have written the following query:
SELECT cast (value as XML).value('data(/Root/Row/Item[#id="431"],')
FROM Parameters_Xml x
WHERE parameter_nr = 1
I get the following error:
Msg 174, Level 15, State 1, Line 1
The value function requires 2 argument(s).
Why my query is not valid?

Try someting like this:
SELECT
CAST(x.Value AS XML).value('(/Root/Row/Item[#id="341"]/Str)[1]', 'nvarchar(100)')
FROM dbo.Parameters_Xml x
WHERE parameter_nr = 1
You're telling SQL Server to go find the <Item> node (under <Root> / <Row>) with and id=341 (that what I'm assuming - your value in the question doesn't even exist) and then get the first <Str> node under <Item> and return that value
Also: why do you need CAST(x.Value as XML) - if that column contains only XML - why isn't it defined with datatype XML to begin with? If you have this, you don't need any CAST ...

DECLARE #str XML;
SET #str = '<Root>
<Row>
<Item id="341" flags="1">
<Str>2</Str>
</Item>
<Item id="342" flags="1">
<Str>10</Str>
</Item>
<Item id="2196" flags="1">
<Str>7REPJ1</Str>
</Item>
</Row>
</Root>'
-- if you want specific values then
SELECT
xmlData.Col.value('#id','varchar(max)') Item
,xmlData.Col.value('(Str/text())[1]','varchar(max)') Value
FROM #str.nodes('//Root/Row/Item') xmlData(Col)
where xmlData.Col.value('#id','varchar(max)') = 342
--if you want all values then
SELECT
xmlData.Col.value('#id','varchar(max)') Item
,xmlData.Col.value('(Str/text())[1]','varchar(max)') Value
FROM #str.nodes('//Root/Row/Item') xmlData(Col)
--where xmlData.Col.value('#id','varchar(max)') = 342
Edit After CommentIf i query my db: select * from parameters_xml where parameter_nr = 1 i will receive over 10000 rows, each row is like the following: Id app param value 1 1 1 11 I need for all the 10000 apps to retrieve the item id and the value from the XML value - like you did for my eg.
-- declare temp table
declare #temp table
(val xml)
insert into #temp values ('<Root>
<Row>
<Item id="341" flags="1">
<Str>2</Str>
</Item>
<Item id="342" flags="1">
<Str>10</Str>
</Item>
<Item id="2196" flags="1">
<Str>7REPJ1</Str>
</Item>
</Row>
</Root>')
insert into #temp values ('<Root>
<Row>
<Item id="3411" flags="1">
<Str>21</Str>
</Item>
<Item id="3421" flags="1">
<Str>101</Str>
</Item>
<Item id="21961" flags="1">
<Str>7REPJ11</Str>
</Item>
</Row>
</Root>')
-- QUERY
SELECT
xmlData.Col.value('#id','varchar(max)') Item
,xmlData.Col.value('(Str/text())[1]','varchar(max)') Value
FROM #temp AS T
outer apply T.val.nodes('/Root/Row/Item') as xmlData(Col)

Try this:
select cast (value as
XML).value('data(/Root/Row/Item[#id="431"]','nvarchar(max)')
data type is 2nd parameter.

Related

Getting Multiple Answers out of an XML String SQL

I have an XML document saved in a Column as varchar(max). The text I want is surrounded by <Text> Words I Want</Text>but these Text tags repeat sometimes 4 or 5 times.
How do I loop through the same document x number of times dependent on the number of text tags?
Currently I'm using this to pull out the first bit of text
DECLARE #first_char nvarchar(10)
DECLARE #second_char nvarchar(10)
SET #first_char = 'xt>';
SET #second_char = '</text>';
SELECT[TestId]
,[SectionId],
SUBSTRING
(
-- column
settings
-- start position
,CHARINDEX(#first_char, Settings , 1) + 3
-- length
,CASE
WHEN (CHARINDEX(#second_char, Settings , 0) - CHARINDEX(#first_char, Settings, 0)) > 0
THEN CHARINDEX(#second_char, Settings, 0) - CHARINDEX(#first_char, Settings, 0) - 3
ELSE 0
END
) AS Response
FROM [B2IK-TestBuilder].[dbo].[Questions]
group by [TestId]
,[SectionId], settings
and I know how many times the Text tag appears.
This is an example of the xml document saved a varchar(max):
<Settings>
<ShowNotes>true</ShowNotes>
<ShowComment>false</ShowComment>
<TextBefore>From the six safety essentials, a </TextBefore>
<TextAfter>is essential before any work is carried out?</TextAfter>
<Items>
<Item>
<Text>Answer 1</Text>
</Item>
<Item>
<Text>Answer 2</Text>
</Item>
<Item>
<Text>Answer 3</Text>
</Item>
<Item>
<Text>Answer 4</Text>
</Item>
<Item>
<Text>Answer 5</Text>
</Item>
<Item>
<Text>Answer 6</Text>
</Item>
Thank you in advance.
OK since SQL 2005 you can use XPath to query the data. I would recommend using the XML column type for the Settings column. Then you can use CROSS APPLY to get the Item nodes.
SELECT q.TestId,q.SectionId,x.XmlCol.value('(Text)[1]','VARCHAR(MAX)')
FROM Questions q
CROSS APPLY q.settings.nodes('/Settings/Items/Item') x(XmlCol);
If you for some reason cannot change the type of you settings column you could cast it in your statement.
SELECT q.TestId,q.SectionId,x.XmlCol.value('(Text)[1]','VARCHAR(MAX)')
FROM (SELECT TestId,SectionId, cast([settings] as xml) as Data FROM Questions) q
CROSS APPLY q.settings.nodes('/Settings/Items/Item') x(XmlCol);

Processing XML Hierarchy with MS SQL

How would I specify the following XML Hierarchy into readable columns in Microsoft SQL?
<transaction id=1>
<item id=1>
<price>1</price>
</item>
<item id=2>
<price>1</price>
</item>
</transaction>
<transaction>
<item id=1>
<price>1</price>
</item>
</transaction>
for instance
select
x.i.value('(????)','Varchar(max)') [TransId]
x.i.value('(????)','Varchar(max)') [ItemId]
x.i.value('(????)','Varchar(max)') [PriceId]
from #xml.nodes('/transaction') x(i)
Thanks in advance.
Attribute values must always appear in quotation marks in XML.
Not sure about the desired output. An example would be:
declare #xml xml
Select #xml=
'<transaction id="1">
<item id="1">
<price>1</price>
</item>
<item id="2">
<price>2</price>
</item>
</transaction>
<transaction>
<item id="1">
<price>3</price>
</item>
</transaction>'
SELECT
y.value('../#id','int') as TransactionID,
y.value('#id','int') as ItemID,
y.value('(./price/text())[1]', 'Varchar(max)') as Price
FROM #xml.nodes('/transaction/item') as x(y)
order by TransactionID,ItemID
with the output:
NULL 1 3
1 1 1
1 2 2
Actually usually it's faster to shred XML from parent to child using apply, like this:
select
t.c.value('#id','int') as TransId,
i.c.value('#id','int') as ItemId,
i.c.value('(price/text())[1]', 'int') as PriceId
from #xml.nodes('transaction') as t(c)
outer apply t.c.nodes('item') as i(c)
order by TransId, ItemID
sql fiddle demo

Pull out Attributes from TSQL XML

I have the following XML:
<help>
<item field="field1" help="helptext" />
<item field="field2" help="helptext" />
<item field="field3" help="helptext" />
</help>
I have this stored in an XML DataType in SQL server and would like to pull out the fields and help text seperately. I.e a results set similar to:
| field1 | helptext |
| field2 | helptext |
| field3 | helptext |
Does anybody know how to achieve this?
Kindest Regards,
Adam
DECLARE #xml AS XML = '<help>
<item field="field1" help="helptext" />
<item field="field2" help="helptext" />
<item field="field3" help="helptext" />
</help>'
select c.value('#field', 'varchar(max)') field, c.value('#help', 'varchar(max)') help
from #xml.nodes('/help/item') T(c);
To achieve the same when xml data is in a table field use:
SELECT c.value('#field', 'varchar(max)') field, c.value('#help', 'varchar(max)') help
FROM MyTable A CROSS APPLY A.MyXmlField.nodes('/help/item') T(c)
Where MyTable is the table with field MyXmlField containing xml data.
See if following helps:
DECLARE #processedXmlDoc int
DECLARE #inputDoc varchar(1000)
EXEC sp_xml_preparedocument #processedXmlDoc OUTPUT, #inputDoc
SELECT *
FROM OPENXML (#processedXmlDoc , '/help/item',1)
WITH (field varchar(20) 'field',
help varchar(20) 'helpText')
EXECUTE sp_xml_removedocument #idoc
Hope that helps.
Try something like this:
DECLARE #input XML = '<help>
<item field="field1" help="helptext" />
<item field="field2" help="helptext" />
<item field="field3" help="helptext" />
</help>'
SELECT
Field = Item.value('#field', 'varchar(25)'),
HELP = Item.value('#help', 'varchar(50)')
FROM
#input.nodes('/help/item') AS XTbl(Item)

SQL Query which deletes an attribute in XML

I have column of XML type.There's a xml like this
<items>
<item type="xxx"><items>
<item type="xxx"><items>
</items>
I need to delete all type attributes. I know oracle has some functions for xml manipulation, but I don't get how to delete attributes.
How would such query look like ?
Here is an example using the Oracle supplied SQL function deletexml
Acknowledgement to Jonas Lincoln as I am using his XPATH expression
SELECT deleteXML(xmltype.CREATEXML('<items>
<item type="xxx">a</item>
<item type="xxx">b</item>
</items>'),
'/items/item[#type="xxx"]/#type')
FROM dual
<items>
<item>a</item>
<item>b</item>
</items>
declare #xml as xml
set #xml = '
<items>
<item type="xxx">3</item>
<item type="xxx">4</item>
</items>'
SET #xml.modify('delete (/items/item[#type="xxx"]/#type)')
select cast(#xml as nvarchar(100))
<items>
<item>3</item>
<item>4</item>
</items>

Query #xml variable to get a rowset

I have an xml data that looks like below.
DECLARE #XmlContent XML
SET #XmlContent =
'<Entities>
<Entity type = "5">
<item id ="1"/>
<item id ="2"/>
<item id ="2"/>
</Entity>
<Entity type = "6">
<item id ="3"/>
<item id ="4"/>
<item id ="5"/>
</Entity>
</Entities>'
I want to select data from this and insert into a table in the following format -
------------
Type Id
------------
5 1
5 2
5 2
6 3
6 4
6 5
Can some one help me to write query for this in sql server?
select
ent.value('#type', 'int') as Type,
row.value('#id', 'int') as ID
from
#XmlContent.nodes('/Entities/Entity') foo(ent)
cross apply ent.nodes('item') bar(row)