Reputation: 1738
I have a problem where I must return data in a SQL query that is contained in an XML column. I have some tentative results, but am having a difficult time making quick headway. So far I have this:
XML (example for one row):
<root>
<property>
<Name>Boolean</Name>
<Value>True</Value>
</property>
<property>
<Name>Integer</Name>
<Value>0</Value>
</property>
</root>
SQL:
select ItemID,
boolean = CASE WHEN CF.exist('/root/property/Name[text() = "Boolean"]') = 1
THEN CF.value('(/root/property/Value)[1]', 'varchar(32)') END,
[integer] = CASE WHEN CF.exist('/root/property/Name[text() = "Integer"]') = 1
THEN CF.value('(/root/property/Value)[2]', 'varchar(32)') END
from
[TTS].[dbo].[tblInItem]
And the resulting data is this:
You can see that row 4 is populating a boolean where there should be an integer. This is because the XML for that line is:
<root>
<property>
<Name>Boolean</Name>
<Value>True</Value>
</property>
<property>
<Name>Another Boolean</Name>
<Value>True</Value>
</property>
<property>
<Name>Integer</Name>
<Value>0</Value>
</property>
</root>
So, how can I replace the singleton [2]
in CF.value('(/root/property/Value)[2]', 'varchar(32)')
with something that returns the node position?
I also recognize that there are likely a number of more elegant solutions, and am open to any of those as well.
Upvotes: 1
Views: 50
Reputation: 138990
Skip the case statement and put the predicate on property name in the xPath expression where you get the value.
MS SQL Server 2008 Schema Setup:
create table T(ItemID int identity primary key, CF xml);
insert into T(CF) values('<root>
<property>
<Name>Boolean</Name>
<Value>True</Value>
</property>
<property>
<Name>Integer</Name>
<Value>0</Value>
</property>
</root>');
insert into T(CF) values('<root>
<property>
<Name>Boolean</Name>
<Value>True</Value>
</property>
<property>
<Name>Another Boolean</Name>
<Value>True</Value>
</property>
<property>
<Name>Integer</Name>
<Value>0</Value>
</property>
</root>');
Query 1:
select T.ItemID,
T.CF.value('(/root/property[Name/text() = "Boolean"]/Value/text())[1]', 'varchar(32)') as Boolean,
T.CF.value('(/root/property[Name/text() = "Integer"]/Value/text())[1]', 'varchar(32)') as Integer
from T
| ItemID | Boolean | Integer |
|--------|---------|---------|
| 1 | True | 0 |
| 2 | True | 0 |
Upvotes: 1