I was wary of XML when I first heard about it - mostly because I was still trying to wrap my head around other stuff that I was learning. Therefore, I didnt learn much about it at first. Then, I needed to pass multiple values to a stored procedure and looked into it. I quickly fell in love!! There are many posts about using XML within T-SQL. I am posting one so that I can search on my own blog for this when I need it - I dont seem to keep it in my head long enough to use it the next time I need it. :)
I am going to use examples from my alerter system, that is where I am using it as I am writing this article - so 2 birds with 1 stone - cant beat that! By the way, I will format the SQL code better - it looks weird being all gray!
Here is the T-SQL to set up the examples below:
-- I used a string of text for 2 reasons: -- 1) test and make sure the xml string looks right -- 2) xml can be read from a string variable or an actual xml variable declare @li_rv int ,@lv_lineBreak varchar(2) ,@lv_recipientNames varchar(max) ,@lx_names xml set @lv_lineBreak = char(13) + char(10) set @lv_recipientNames = '<Recipients>' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Alert Name="ETL_nomatchfound">' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Person FirstName="Glenda" LastName="Gable" EmailAddress="This email address is being protected from spambots. You need JavaScript enabled to view it. " />' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Person FirstName="Kermit" LastName="Frog" EmailAddress="This email address is being protected from spambots. You need JavaScript enabled to view it. " />' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Alert>' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Alert Name="job_step1completed">' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Person FirstName="Glenda" LastName="Gable" EmailAddress="This email address is being protected from spambots. You need JavaScript enabled to view it. " />' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Person FirstName="Big" LastName="Bird" EmailAddress="This email address is being protected from spambots. You need JavaScript enabled to view it. " />' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '<Person FirstName="Grover" LastName="Monster" EmailAddress="This email address is being protected from spambots. You need JavaScript enabled to view it. " />' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '</Alert>' + @lv_lineBreak set @lv_recipientNames = @lv_recipientNames + '</Recipients>'
Now that we have that out of the way.... there are multiple ways of reading that XML. I am going to show examples of using Open XML (for XML formatted string variables) and XQuery (for xml variables).
You can also use the BULK import/export for XML documents. Here is a link to describe that - I dont have a reason to use it yet, so I will let the experts explain it better :) -- http://msdn.microsoft.com/en-us/library/ms191184.aspx
OpenXML
-- ==================
-- This uses OpenXML to read XML formatted string data, parse it as XML and get the values from within the XML string
-- create an internal representation of the XML document (using the string formatted with XML tags)
exec sp_xml_preparedocument @li_rv OUTPUT, @lv_recipientNames
-- bring back results from a specific node level
select Name
FROM openxml (@li_rv, '/Recipients/Alert',1)
with (Name varchar(25))
select FirstName, LastName, EmailAddress
from openxml (@li_rv, '/Recipients/Alert/Person',1)
with (FirstName varchar(50)
,LastName varchar(50)
,EmailAddress varchar(75))
-- bring back results from multiple node levels
select AlertName, RecipFirstName, RecipLastName, EmailAddress
from openxml (@li_rv, '/Recipients/Alert/Person',2)
with (AlertName varchar(25) '../@Name'
,RecipFirstName varchar(50) '@FirstName'
,RecipLastName varchar(50) '@LastName'
,EmailAddress varchar(75) '@EmailAddress')
-- remove the document (free up the memory); "A parsed document is stored in the internal cache of SQL Server." (http://msdn.microsoft.com/en-us/library/ms190353.aspx)
exec sp_xml_removedocument @li_rv
-- For more information check out the Microsoft site:
-- http://msdn.microsoft.com/en-us/library/ms186918.aspx
XQuery
-- ==================
-- This uses XQuery to get the values from within the XML string
-- Note: the red squiggly lines appear under item.value in the select statement - that is ok, when it is run, it works
select AlertName = item.value('(../@Name)','varchar(25)')
,FirstName = item.value('(@FirstName)','varchar(50)')
,LastName = item.value('(@LastName)','varchar(50)')
,EmailAddress = item.value('(@EmailAddress)','varchar(75)')
from @lx_names.nodes('//Recipients/Alert/Person') as Recipients(item)
--where item.value('(../@Name)','varchar(25)') = 'ETL_nomatchfound'


