Upsert on SQL Server table from XML
.net, c#, sql-server-2008, t-sql, xml
Solution
You can use `merge` with `output` to a table variable and then query the table variable to build the log XML.
Put it in a stored procedure where you have the item XML as an in parameter and the log XML as an out parameter.
create procedure AddItemXML
@ItemsXML xml,
@ItemsLogXML xml out
as
declare @Changes table
(
Item_Id int,
Name nvarchar(20),
Price money,
Action nvarchar(10)
);
merge Items as T
using
(
select T.N.value('Id[1]', 'int') as Item_Id,
T.N.value('Name[1]', 'varchar(20)') as Name,
T.N.value('Price[1]', 'money') as Price
from @ItemsXML.nodes('/Item') T(N)
) as S
on T.Item_Id = S.Item_Id
when matched then
update set Name = S.Name, Price = S.Price
when not matched then
insert (Item_Id, Name, Price) values (S.Item_Id, S.Name, S.Price)
output inserted.Item_Id,
inserted.Name,
inserted.Price,
$action
into @Changes;
set @ItemsLogXML =
(
select Item_Id as ID,
Name,
Price
from @Changes
where Action = 'INSERT'
for xml path('Item'), type
);
Working sample on SE-Data
Problem
I'm attempting to create a small console app in C# to perform inserts on a table of Products (ITEMS) in SQL Server 2008 according to the contents of an XML file in the FASTEST way possible. I already have an .XSD file that contains the proper mappings to the SQL table (which may not be necessary with the approach outlined below). Here's a high-level of my approach: - Read the XML, using it to create a table. - Perform a MERGE against the ITEMS table using the table created from the XML file. 2a. If the item exists, update it. 2b. If the item does not exist, insert it. - Create a log of only the records inserted in XML. Consider the following ITEMS table and XML file: ITEMS ``` Item_Id Name Price 1 Coke 5.00 2 Pepsi 3.00 3 Sprite 2.00 ``` ITEMS.XML ``` <?xml version="1.0" encoding="ISO-8859-1"?> <Item> <Id>5</Id> <Name>Mountain Dew</Name> <Price>4.50</Price> </Item> <Item> <Id>3</Id> <Name>Sprite Zero</Name> <Price>1.75</Price> </Item> ``` After the import, the ITEMS table should look like: ITEMS ``` Item_Id Name Price 1 Coke 5.00 2 Pepsi 3.00 3 Sprite Zero 1.75 5 Mountain Dew 4.50 ``` Once that's done, I also need to generate an XML formatted log file that contains the "new" record that was inserted into the table (ITEMS_LOG.XML): ITEMS_LOG.XML ``` <?xml version="1.0" encoding="ISO-8859-1"?> <Item> <Id>5</Id> <Name>Mountain Dew</Name> <Price>4.50</Price> </Item> ``` I have tried implementing this using SQLXMLBulkLoad, but unfortunately it does not provide the logging that I need, nor does it permit me to access any of the messages returned from SQL Server (i.e. what's been inserted/updated). Although I have an intermediate level of SQL expertise, I am fairly new to working with XML, especially in this context. Any help/guidance would be greatly appreciated!