SQL Server:存储过程输入表变量解决方法

时间:2011-01-20 18:02:30

标签: sql-server-2005 stored-procedures pivot-table

我正试图找到一个好的工作,不能使用表变量作为存储过程的输入。我想将一条记录插入基表,将多条记录插入数据透视表。我最初的思考过程使我想要一个存储过程,其中包含基表的单独输入,以及用于数据透视表记录的单个列表输入,即:

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

如前所述,由于表变量输入@items(我认为主要是由于可变范围问题),上述代码将无效。那么,这有什么好的解决方法吗?

原始问题
我有三张桌子:

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)
)

使用一些初始项目数据:

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'

我有一些用于创建新任务的代码:

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

现在,我想要一种简化/简化新任务创建的方法。我的第一个想法是使用存储过程,但表变量不能用作输入,因此它不起作用。我想我可以使用插入触发器查看这个,但我不确定......这是我最好的(或唯一的)选项吗?

1 个答案:

答案 0 :(得分:0)

我很幸运使用XML将数据传递给程序。您可以使用OPENXML (Transact-SQL)来解析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

<强>结果

<Items><Item itemID="1"/><Item itemID="2"/></Items>
itemID
-----------
1
2