2011-01-20 3 views
0

J'essaie de trouver un bon travail pour ne pas être en mesure d'utiliser une variable de table en entrée d'une procédure stockée. Je veux insérer un seul enregistrement dans une table de base et plusieurs enregistrements dans un tableau croisé dynamique. Mon processus initial de pensée m'a amené à vouloir une procédure stockée avec des entrées séparées pour la table de base, et une seule entrée de liste pour les enregistrements de la table de pivot, à savoir:SQL Server: Variable table d'entrée de procédure stockée contournement

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 

Comme déjà indiqué, le code ci-dessus ne fonctionnera pas en raison de l'entrée variable de la table, @items (je crois principalement en raison de problèmes de portée variable). Alors, y a-t-il de bonnes solutions de contournement?

originale Question
J'ai trois 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) 
) 

avec des données de l'élément initial:

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' 

Et j'avoir un code pour créer une nouvelle tâche:

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 

Maintenant, je suis C'est un moyen de simplifier/rationaliser la création de nouvelles tâches. Ma première pensée a été d'utiliser un proc stocké, mais les variables de table ne peuvent pas être utilisées comme entrées, donc ça ne marchera pas. Je pense que je peux le faire avec une vue avec un déclencheur d'insertion, mais je ne suis pas sûr ... Est-ce ma meilleure (ou seule) option?

+0

Quelle partie de ce que tu veux dans un SP? Est-ce que le SP prendrait juste les 3 variables en haut en tant que params et le corps serait le reste de votre code? – RichardTheKiwi

+0

Les params d'entrée SP seraient '@ taskDes',' @ sTime', '@ eTime' et' @ usedItems' – chezy525

Répondre

0

J'ai eu beaucoup de chance en utilisant XML pour transmettre des données aux procédures. Vous pouvez utiliser OPENXML (Transact-SQL) pour analyser le code 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 

Résultats

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

Je ne aime pas particulièrement, parce qu'il n'y a pas moyen de garantir la structure du xml d'entrée. Cela dit, il semble que ce soit la meilleure option actuellement disponible. – chezy525