2009-05-15 8 views
7

Dans ma procédure stockée, j'ai plusieurs variables similaires @V1, @V2 ... @V20 (disons 20 d'entre elles) FETCHED à partir d'un enregistrement. Comment utiliser SQL dynamique pour effectuer 20 appels à une autre procédure stockée en utilisant ces variables comme paramètres?Accès de type tableau aux variables dans T-SQL

Bien sûr @V[i] syntaxe est incorrecte, mais il exprime l'intention

fetch next from maincursor into @status, @V1, @V2, ... 

    while @i<21 
    begin 
     -- ??? execute sp_executesql 'SecondSP', '@myParam int', @[email protected][i] 
     -- or 
     -- ??? execute SecondSP @V[i] 
     set @i = @i+1 
    end 
+0

Un peu de contexte serait bon. Pourquoi essayez-vous de faire cela? – Tomalak

Répondre

0

Pourquoi ne pas simplement utiliser la variable à la place de la table, et puis juste boucle à travers la table obtenir chaque valeur.

Traitez fondamentalement chaque ligne d'une table comme votre cellule de tableau, avec une table qui a une colonne.

Juste une idée. :)

+0

Les performances étant importantes, je souhaite éviter autant que possible les boucles, insertions et extractions supplémentaires. Si ce n'est pas du tout possible, je préférerais recourir à une longue et horrible instruction CASE :( –

+0

Une variable de table est rapide, car elle est toute en mémoire, elle remplace l'utilisation d'une table temporaire, mais vous avez accès aux fonctions de la table –

0

Cela semble être une demande étrange - aurez-vous toujours un ensemble fixe de variables? Que se passe-t-il si le nombre passe de 20 à 21, et ainsi de suite, allez-vous constamment déclarer de nouvelles variables?

Est-il possible, au lieu de récupérer les valeurs dans des variables séparées, de les renvoyer chacune comme des lignes individuelles et de simplement les parcourir dans un curseur?

Sinon, et vous devez utiliser les variables individuelles comme cela est expliqué, voici une solution:

declare @V1 nvarchar(100) 
set @V1 = 'hi' 
declare @V2 nvarchar(100) 
set @V2 = 'bye' 
declare @V3 nvarchar(100) 
set @V3 = 'test3' 
declare @V4 nvarchar(100) 
set @V4 = 'test4' 
declare @V5 nvarchar(100) 
set @V5 = 'end' 

declare aCursor cursor for 
select @V1 
union select @V2 union select @V3 
union select @V4 union select @V5 

open aCursor 

declare @V nvarchar(100) 
fetch next from aCursor into @V 
while @@FETCH_STATUS = 0 
begin 
    exec TestParam @V 

    fetch next from aCursor into @V 

end 

close aCursor 
deallocate aCursor 

Je ne aime pas vraiment cette solution, il semble en désordre et infranchissable. En outre, en note - la façon dont vous avez formulé votre question semble demander s'il y a des tableaux dans T-SQL. Par défaut, il n'y en a pas, bien qu'une recherche rapide sur google puisse vous indiquer des solutions de contournement si vous en avez absolument besoin.

+0

1.Le nombre de variables ne changerait pas; ils sont des colonnes dans la table de base de données avec une structure assez stable 2. Le code est bien sûr simplifié. En réalité, il y a d'autres variables qui jouent un rôle dans la logique de la procédure, donc déplacer ces Vs dans une autre table temporaire n'est pas une bonne idée 3. Je suis conscient qu'il n'y a pas de tableaux dans T-SQL 4. Cette solution est vraiment désordre, je suis d'accord –

+2

Honnêtement, je ne vois pas pourquoi vous approchez les données de cette façon - avoir des variables nommées V1-VX ne fait que hurler une mauvaise pratique. Pourquoi les données dans les lignes d'une table ne sont-elles pas opposées aux colonnes? Il semble que si vous appliquez exactement la même logique à chaque colonne que la table peut être mal conçue. –

+0

@Dan Fuller a déclaré: «Je ne peux honnêtement pas voir pourquoi vous approchez les données de cette façon», car il semble plus facile de mettre les données dans des colonnes et de travailler avec que, puis en lignes. Certaines personnes ne pensent pas que ce soit des ensembles, et toujours en boucle, OP est un exemple, les défauts de conception le montrent aussi, abandonnent et bougent –

2

Utilisez un #temptable

si vous êtes à SQL Server 2005, vous pouvez créer un #temptable dans la procédure stockée mère, et il est disponible dans la procédure d'enfant stockée qui appelle.

CREATE TABLE #TempTable 
(col1 datatype 
,col2 datatype 
,col3 datatype 
) 

INSERT INTO #TempTable 
    (col1, col2, col3) 
    SELECT 
     col1, col2, col3 
     FROM ... 

EXEC @ReturnCode=YourOtherProcedure 

dans l'autre procédure, vous avez accès à #temptable pour sélectionner, supprimer, etc ... faire ce travail de procédure d'enfant sur un ensemble de données non sur un élément à la fois

se souviennent , en SQL, les boucles aspirent la performance!

14

Comme d'autres l'ont dit, créez une table temporaire, insérez les valeurs dont vous avez besoin. Ensuite, parcourez-le en exécutant le SQL nécessaire à partir de ces valeurs. Cela vous permettra d'avoir 0 à BEAUCOUP de valeurs à exécuter, donc vous n'avez pas besoin de configurer une variable pour chacun.

Vous trouverez ci-dessous un exemple complet de la façon de procéder sans curseurs.

SET NOCOUNT ON 

DECLARE @dict TABLE (
        id   INT IDENTITY(1,1), -- a unique identity column for reference later 
        value  VARCHAR(50),  -- your parameter value to be passed into the procedure 
        executed BIT    -- BIT to mark a record as being executed later 
        ) 

-- INSERT YOUR VALUES INTO @dict HERE 
-- Set executed to 0 (so that the execution process will pick it up later) 
-- This may be a SELECT statement into another table in your database to load the values into @dict 
INSERT @dict 
SELECT 'V1Value', 0 UNION ALL 
SELECT 'V2Value', 0 

DECLARE @currentid INT 
DECLARE @currentvalue VARCHAR(50) 
WHILE EXISTS(SELECT * FROM @dict WHERE executed = 0) 
BEGIN 
    -- Get the next record to execute 
    SELECT 
    TOP 1 @currentid = id 
    FROM @dict 
    WHERE executed = 0 

    -- Get the parameter value 
    SELECT @currentvalue = value 
    FROM @dict 
    WHERE id = @currentid 

    -- EXECUTE THE SQL HERE 
    --sp_executesql 'SecondSP', '@myParam int', @myParam = 
    PRINT 'SecondSP ' + '@myParam int ' + '@myParam = ' + @currentvalue 

    -- Mark record as having been executed 
    UPDATE d 
    SET  executed = 1 
    FROM @dict d 
    WHERE id = @currentid 
END 
Questions connexes