SQL Server: Stored Proc input table variable workaround
I'm trying to find a good work around to not being able to use a table variable as an input to a stored procedure. I want to insert a single record into a base table and multiple records into a pivot table. My initial thought process led me to wanting a stored proc with separate inputs for the base table, and a single list input for the pivot table records, i.e.:
create proc insertNewTask (@taskDesc varchar(100), @sTime datetime, @eTime datetime, @items table(itemID int))
as
begin
declare @newTask table(newID int)
insert into tasks(description, sTimeUTC, eTimeUTC)
output inserted.ID into @newTask
values(@taskDesc, @sTime, @eTime)
insert into taskItems(taskID, itemID)
select newID, itemID
from @newTask cross join @items
end
As already stated, the above code won't work because of the table variable input, @items
(I believe primarily due to variable scope issues). So, are there any good workarounds to this?
Original Question
I have three tables:CREATE TABLE items
(
ID int PRIMARY KEY,
name varchar(20),
description varchar(100)
)
CREATE TABLE tasks
(
ID int identity(1,1) PRIMARY KEY,
description varchar(100),
sTimeUTC datetime,
eTimeUTC datetime
)
CREATE TABLE taskItems
(
taskID int,
itemID int,
CONSTRAINT fk_taskItems_taskID FOREIGN KEY (taskID) on tasks(ID),
CONSTRAINT fk_taskItems_itemID FOREIGN KEY (itemID) on items(ID)
)
With some initial item data:
insert into items (ID, name, description)
select 1, 'nails', 'Short piece of metal, with one flat side and one pointed side' union
select 2, 'hammer', 'Can be used to hit things, like nails' union
select 3, 'screws', 'I''m already tired of writing descriptions for simple tools' union
select 4, 'screwdriver', 'If you can''t tell already, this is all fake data' union
select 5, 'AHHHHHH', 'just for good measure'
And I have some code for creating a new task:
declare @taskDes varchar(100), @sTime datetime, @eTime datetime
select @taskDes = 'Assemble a bird house',
@sTime = '2011-01-05 12:00', @eTime = '2011-01-05 14:00'
declare @usedItems table(itemID int)
insert into @usedItems(itemID)
select 1 union
select 2
declare @newTask table(taskID int)
insert into tasks(description, sTimeUTC, eTimeUTC)
output inserted.ID into @newTask
values(@taskDes, @sTime, @eTime)
insert into taskItems(taskID, itemID)
select taskID, itemID
from @newTask
cross join @usedItems
Now, I want a way of simplifying/streamlining the creation of new tasks. My first thought w开发者_开发问答as to use a stored proc, but table variables can't be used as inputs, so it won't work. I think I can do this with a view with an insert trigger, but I'm not sure... Is that my best (or only) option?
I have had great luck using XML to pass data to procedures. You can use OPENXML (Transact-SQL) to parse the XML.
-- You already had an example of @usedItems
-- declared and populated in the question
declare @usedItems table(itemID int)
insert into @usedItems(itemID)
select 1 union
select 2
-- Build some XML, either directly or from a query
-- Here I demonstrate using a query
declare @itemsXML nvarchar(max);
select @itemsXML =
'<Items>'
+ (select itemID from @usedItems as Item for xml auto)
+ '</Items>'
print @itemsXML
-- Pass @itemsXML to the stored procedure as nvarchar(max)
-- Inside the procedure, use OPENXML to turn the XML
-- back into a rows you can work with easily
DECLARE @idoc int
EXEC sp_xml_preparedocument @idoc OUTPUT, @itemsXML
SELECT *
FROM OPENXML (@idoc, '/Items/Item',1)
WITH (itemID int)
EXEC sp_xml_removedocument @idoc
Results
<Items><Item itemID="1"/><Item itemID="2"/></Items>
itemID
-----------
1
2
精彩评论