My rule of thumb is that if I hit "one table", I push directly into that table.
If I hit 2 or more, I shred the xml into a #temp (or @variable) table, and then do Insert/Update/Upsert(Merge) from that #temp table.
If I have more than 1 destination table, then I do my shredding outside of the BEGIN TRAN/COMMIT TRAN. Then do the Upsert stuff inside the TRAN.
Here is a "typical" setup for me.
Also note the "where not exists" if you are inserting (only). (an option, not necessarily your scenario)
/*
EXEC dbo.uspMyEntityUpsertByXml
'
'
*/
IF EXISTS
(
SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspMyEntityUpsertByXml'
)
BEGIN
DROP PROCEDURE [dbo].[uspMyEntityUpsertByXml]
END
GO
CREATE Procedure dbo.uspMyEntityUpsertByXml (
@parametersXML XML
)
AS
BEGIN
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
CREATE TABLE #Holder
(
SurrogateKeyIDENTITY int not null IDENTITY (1,1) ,
NameOf NVARCHAR(100) ,
Number int ,
CustomerId int
)
/* Start XML usage */
/* Only incur the penalty of XML parsing, if XML was specified */
if (@parametersXML IS NOT NULL) AND (Datalength(@parametersXML) > 10 )
/* Only process the xml If the xml exists, and it has at least 10 chars. 10 is just a somewhat */
/* arbritrary number, saying, that an xml doc with <10 chars doesn't have a whole lot going for it */ /* || DataLength is used for Text datatype */
BEGIN
INSERT INTO #Holder ( NameOf , Number , CustomerId )
SELECT x.item.value('@Name[1]', 'NVARCHAR(100)') AS Name,
x.item.value('@Number[1]', 'INT') AS Number,
x.item.value('@CustomerId[1]', 'INT') AS CustomerId
FROM @parametersXML.nodes('//rows/row') AS x(item)
END
/* End XML usage */
/*
INSERT INTO dbo.CustomerNumbers (Name, Number, CustomerId)
*/
Select NameOf , Number, CustomerId from #Holder h
/*
Where not exists ( select null from dbo.CustomerNumbers innerRealTable
where innerRealTable.Name = h.NameOf
and innerRealTable.Number = h.Number
and innerRealTable.CustomerId = h.CustomerId
)
*/
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
END