Monday, January 26, 2009

iteration though xml via sql

I was working on a web service (passing xml) when I decided that it would be groovy to try passing the xml to SQL Server as a variable, then selecting what I needed out of the string, without using a cursor (note: cursors in SQL Server are bad and unneeded). Here's the code of what I came up with:
declare @InputData xml (xml type limited to sql 2005 or 2008)
set @InputData = --the xml string...(blogspot doesn't like xml)

declare @widgetCount int
,@counter int
,@UserDataIndex int

set @counter = 1

--Get the user ID baby!
select @UserDataIndex = UserDataIndex from UserData where UserEmail = @InputData.value('(//UserEmail)[1]','varchar(100)')
select @widgetCount = @InputData.value('count(//widget)[1]','int')

--Get a count of our widgets using the xQuery count() function
select @InputData.value('(//widget[sql:variable("@counter")]/WidgetColumn)[1]','varchar(100)')

--start looping:
WHILE (@counter <= @widgetCount)
BEGIN
SELECT @UserDataIndex , @InputData.value('(//widget[sql:variable("@counter")]/WidgetIndex)[1]','int') as WidgetIndex , @InputData.value('(//widget[sql:variable("@counter")]/WidgetRow)[1]','int') as WidgetRow , @InputData.value('(//widget[sql:variable("@counter")]/WidgetColumn)[1]','int') as WidgetRow , @InputData.value('(//widget[sql:variable("@counter")]/WidgetTitle)[1]','varchar(200)') as WidgetTitle , @InputData.value('(//widget[sql:variable("@counter")]/WidgetCssClass)[1]','varchar(200)') as WidgetCssClass , @InputData.value('(//widget[sql:variable("@counter")]/WidgetStyle)[1]','varchar(500)') as WidgetStyle
SET @counter = @counter + 1
END

The key to iterating through the nodes is the sql:variable("@counter") notation. This passes along our counter, so that we can get the information for the node we are currently in. The thing to keep in mind about XML is that it is a data structure, which means it can be conceptually used as a table within SQL. This allows me to get the information I need from each node.

Also keep in mind that I was the one who created the schema, therefore selecting it using literal values was fairly straightforward. If we try to select without knowing what fields exist, we would find out that all we have is a bunch of nulls.

Why do this, you ask? so that we can leverage an insert into statement within T-SQL and a stored procedure, since SQL 2005 won't accept an array as a datatype (but I keep hoping)!!!

2 comments:

Sandeep said...

can u read the code u pasted ?

MecurioJ said...

I'm afraid I don't understand the comment Sandeep. I am able to read the code just fine. If you would like me to email you a copy of what I did, I can certainly do that as well. The heart of the query is to use XPath within the SQL to get the data that you need.