Click here to Skip to main content
15,888,454 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
How to get the second or third element DYNAMICALLY of a XML document on XQuery with SQL Server, specifically using the .value method.

By dynamically I mean that I can use a SQL SERVER variable like
DECLARE @Index int
with some sort of syntax within the first parameter of the .value method , because if you just use a VARCHAR variable, for example, you get an error like :

The argument 1 of the XML data type method "value" must be a string literal

This is in Sql server 2008.

I havent found answer to this on internet, or maybe I dont know how to question, but there's only samples to access the first element or the second and so on but hardcoding.

I've seen a similar syntax like the following but with the .exists method.
(and this is what I would like to do)

-- This is clearly an example of MSDN

DECLARE @Index int
DECLARE @myDoc xml

SET @Index = 3
SET @myDoc = '<Root>
                <ProductDescription ProductID="9865" ProductName="Road Bike"> 
                        .....'

SELECT  @myDoc.value('(/Root/ProductDescription/@ProductID)[ =sql:variable("@Index") ]', 'int' )


Unfortunately this produces the error : XQuery [value()]: Syntax error near '='

Context :
I have a process that needs to execute actions based on the values of the second or third element.
There is no possibility to change the field in database or the way the XML is structured.
Posted
Comments
j snooze 22-May-14 17:57pm    
This link may help your situation.
http://stackoverflow.com/questions/8959754/getting-nth-element-from-last-in-a-xml-in-sql-server
fvalerin 23-May-14 11:50am    
Thanx J Snooze, God bless you. It seems your answer is the correct, but I have some problems :

First I didnt explain all the context the right way, I am really using a column field on a table instead of a XML variable, besides the field is a VARCHAR(max), instead of a XML (this is the way it was designed, I didnt, and cannot be changed).
Second I have the requirement to process the records in DLM sentences, not processing records one by one on a loop.
Third the process is a trigger, so what I need is to make a INSERT INTO ANOTHERTABLE SELECT ... FROM INSERTED , so it will be a massive INSERT.
Finally, I will do make a loop for the INDEX of the XML element on the pseudo XML field.

So I learnt that I can use CROSS APPLY like this :

...
FROM TABLEWITHXML
CROSS APPLY CAST(PSEUDOXMLFIELD AS XML).nodes('Root/ProductDescription[ position() = sql:variable("@index") ]') as Table2(ProductDescription)


But generates the error : Incorrect syntax near the keyword 'AS'.

I dont know how to proceed or how to do it another way fulfilling the previous requirements.
j snooze 23-May-14 12:34pm    
You may have to put the data in a table variable or temp table first. The error is trying to use the CAST().nodes, It's not liking that syntax. Something like this perhaps. #test was just me mimicking your TABLEWITHXML that is actually a varchar(max) field. I put the corresponding data in a table variable @ConvertedData, then selected off of that. Hope it helps.

create table #test(row int identity(1,1),pseudoxmlfield varchar(max))

--drop table #test
insert into #test (pseudoxmlfield)
values('<root>
<ProductDescription ProductID="9865" ProductName="Road Bike"/>
<ProductDescription ProductID="9866" ProductName="Test Bike"/>
<ProductDescription ProductID="9867" ProductName="Dirt Bike"/>
')

insert into #test (pseudoxmlfield)
values('<root>
<ProductDescription ProductID="9868" ProductName="Big Bike"/>
<ProductDescription ProductID="9869" ProductName="Little Bike"/>
<ProductDescription ProductID="9870" ProductName="Rodeo Bike"/>
')


Declare @ConvertedData Table(row int,
pseudoxmlfield xml)

Insert Into @ConvertedData(row,pseudoxmlfield)
Select row,Cast(pseudoxmlfield as XML)
From #test

DECLARE @Index int

SET @Index = 2

Select t2.prod.query('.')
From @ConvertedData
Cross Apply PSEUDOXMLFIELD.nodes('Root/ProductDescription[ position() = sql:variable("@index") ]') as t2(prod)
j snooze 23-May-14 12:35pm    
There should be "root" tags around my test code...apparently the posting mechanism on codeproject removed those.

1 solution

Ok, thank you again J Snooze, I'm sorry I couldnt follow up on this timely. Your last response it seems to put us on the right track, but fortunately there was a simpler answer for what I need and it was a matter of syntax, at the beginning I tried several syntax but I couldnt find it, that's why I made the question.

I was able to use this effectively on a pseudo XML field of a table and with CAST to XML, similar to this :
SQL
-- Suppose you have several ProductDescription items

DECLARE @Index int
DECLARE @myDoc VARCHAR(max)
 
SET @Index = 2
SET @myDoc = '<root>
                <productdescription productid="9865" productname="Road Bike"> 
                     <country>China</country>
                        .....'
-- Extracts the subelement "Country" from the second element (above @Index = 2)
SELECT  CAST(@myDoc AS XML).value('(/Root/ProductDescription)[sql:variable("@Index")]/Country[1]', 'VARCHAR(20)' )
 
-- Extracts the atribute "ProductId" of the second element (above @Index = 2)
SELECT  CAST(@myDoc AS XML).value('(/Root/ProductDescription/@ProductID)[sql:variable("@Index")][1]', 'int' )

</productdescription></root>
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900