SQL Server SELECT INTO @variable?

250

J'ai le code suivant dans l'un de mes procs stockés Sql (2008) qui s'exécute parfaitement:

    CREATE PROCEDURE [dbo].[Item_AddItem]
        @CustomerId uniqueidentifier,
        @Description nvarchar(100),
        @Type int,
        @Username nvarchar(100),
    AS
    BEGIN

        DECLARE @TopRelatedItemId uniqueidentifier;
        SET @TopRelatedItemId = 
        (
           SELECT top(1) RelatedItemId 
           FROM RelatedItems 
           WHERE CustomerId = @CustomerId
        ) 

        DECLARE @TempItem TABLE
        (
            ItemId uniqueidentifier,
            CustomerId uniqueidentifier,
            Description nvarchar(100),
            Type int,
            Username nvarchar(100),
            TimeStamp datetime
        );

        INSERT INTO Item
        OUTPUT INSERTED.* INTO @TempItem
        SELECT NEWID(), @CustomerId, @Description, @Type, @Username, GETDATE()

        SELECT
            ItemId,
            CustomerId,
            @TopRelatedItemId,
            Description,
            Type,
            Username,
            TimeStamp
        FROM
            @TempItem
END
GO

Donc, la question pour vous est la possibilité de faire quelque chose comme:

DECLARE @TempCustomer TABLE
(
   CustomerId uniqueidentifier,
   FirstName nvarchar(100),
   LastName nvarchar(100),
   Email nvarchar(100)
);
SELECT 
    CustomerId, 
    FirstName, 
    LastName, 
    Email 
INTO 
    @TempCustomer 
FROM 
    Customer
WHERE 
    CustomerId = @CustomerId

Afin que je puisse réutiliser ces données de la mémoire dans d'autres déclarations suivantes? SQL Server jette un ajustement avec l'instruction ci-dessus, mais je ne veux pas avoir à créer des variables distinctes et initialiser chacune d'entre elles via une instruction SELECT distincte contre la même table .... UGH !!!

Avez-vous des suggestions sur la façon de réaliser quelque chose le long des lignes sans plusieurs requêtes sur la même table?

bleepzter
la source
1
"pour créer des variables distinctes et initialiser chacune d'entre elles via une instruction SELECT distincte" - pourquoi auriez-vous besoin de faire cela? declare @t tableune fois, et si vous avez besoin de le réutiliser, tirez un DELETE @TempCustomeravant de l'insérer à nouveau
RichardTheKiwi

Réponses:

204

Vous ne pouvez pas CHOISIR .. DANS .. UNE VARIABLE DE TABLE. Le mieux que vous puissiez faire est de le créer d'abord, puis de l'insérer. Votre 2e extrait doit être

DECLARE @TempCustomer TABLE
(
   CustomerId uniqueidentifier,
   FirstName nvarchar(100),
   LastName nvarchar(100),
   Email nvarchar(100)
);
INSERT INTO 
    @TempCustomer 
SELECT 
    CustomerId, 
    FirstName, 
    LastName, 
    Email 
FROM 
    Customer
WHERE 
    CustomerId = @CustomerId
RichardTheKiwi
la source
5
Il convient de noter que cela fonctionne également très bien dans un contexte CTE. Bazinga!
Michael Krauklis
4
Quelqu'un a-t-il une réponse à la question de savoir pourquoi on ne peut pas sélectionner une variable de table comme vous le pouvez avec une table temporaire réelle?
KSwift87
504

Si vous vouliez simplement assigner certaines variables pour une utilisation ultérieure, vous pouvez les faire en une seule fois avec quelque chose comme ceci:

declare @var1 int,@var2 int,@var3 int;

select 
    @var1 = field1,
    @var2 = field2,
    @var3 = field3
from
    table
where
    condition

Si c'est le genre de chose que vous recherchez

dougajmcdonald
la source
1
Meilleure réponse à mon humble avis, mais que se passe-t-il si les résultats sont supérieurs à un?
capitano666
Si les résultats sont supérieurs à un, vous obtiendrez l'une des valeurs disponibles. Cela pourrait faire un puzzle intéressant! Voir mssqltips.com/sqlservertip/1888/…
Smandoli
8
Pour forcer la requête à renvoyer une seule ligne, utilisez SELECT TOP 1
Adrian
1
@Adrian Oui, la requête ci-dessus suppose que vous avez sélectionné une seule ligne. Vous pouvez également utiliser des fonctions de classement et d'agrégation si vous souhaitez une logique plus sophistiquée.
dougajmcdonald
1
Si vous n'utilisez pas le type de base de données utilisé par l'OP, tous ne prennent pas en charge TOP 1 comme l'a mentionné Adrian. SQL Server / MS Access utilisent TOP, MySQL utilise LIMIT et Oracle utilise ROWNUM. Voir w3schools.com/sql/sql_top.asp pour plus d'informations.
Tyler
33

tu peux le faire:

SELECT 
    CustomerId, 
    FirstName, 
    LastName, 
    Email
INTO #tempCustomer 
FROM 
    Customer
WHERE 
    CustomerId = @CustomerId

puis plus tard

SELECT CustomerId FROM #tempCustomer

vous n'avez pas besoin de déclarer la structure de #tempCustomer

Victor Ribeiro da Silva Eloy
la source
3
@webturner Aucun de ces points n'est vrai. Les tables temporaires ne sont pas étendues en dehors du proc et les variables de table ne sont pas plus "mémoire seule" que les tables temporaires.
Martin Smith
7
N'oubliez pas d'ajouter un DROP TABLE #tempCustomerquand #tempCustomern'est plus nécessaire sinon la prochaine sélection provoquera une #tempCustomer already existserreur
ViRuSTriNiTy
15

Il semble que votre syntaxe soit légèrement dépassée. Cela a de bons exemples

DECLARE @TempCustomer TABLE
(
   CustomerId uniqueidentifier,
   FirstName nvarchar(100),
   LastName nvarchar(100),
   Email nvarchar(100)
);
INSERT @TempCustomer 
SELECT 
    CustomerId, 
    FirstName, 
    LastName, 
    Email 
FROM 
    Customer
WHERE 
    CustomerId = @CustomerId

Puis plus tard

SELECT CustomerId FROM @TempCustomer
Pat L
la source
2

On dirait que vous voulez des tables temporaires. http://www.sqlteam.com/article/temporary-tables

Notez que #TempTable est disponible dans tout votre SP.

Notez que ## TempTable est disponible pour tous.

Valamas
la source
2
## tentable - jusqu'à ce que le propriétaire (créateur) le supprime ou se déconnecte
RichardTheKiwi
4
Je ne veux pas de tables temporaires. Les tables temporaires sont chères et lentes. Je veux juste conserver un peu de données pour un enregistrement spécifique pendant un petit laps de temps et le rendre disponible pour plusieurs instructions SQL, sans recherches ultérieures. Étant donné que les variables de table ont une portée dans le proc stocké dans lequel elles ont été définies, elles sont la solution parfaite pour stocker des données tupplées pour cet appel de proc stocké ...
bleepzter
3
J'ai également oublié de mentionner que la base de données réside dans Azure .... Je ne veux pas introduire de gâchis dans la gestion des tables temporaires.
bleepzter
La table variable est la voie à suivre. declare @varTable Table (....)
ARLibertarian
1

J'ai trouvé votre question à la recherche d'une solution au même problème; et ce que les autres réponses ne parviennent pas à indiquer, c'est un moyen d'utiliser une variable pour changer le nom de la table pour chaque exécution de votre procédure sous une forme permanente, et non temporaire.

Jusqu'à présent, je concatène l'intégralité du code SQL avec les variables à utiliser. Comme ça:

declare @table_name as varchar(30)
select @table_name = CONVERT(varchar(30), getdate(), 112)
set @table_name = 'DAILY_SNAPSHOT_' + @table_name

EXEC('
        SELECT var1, var2, var3
        INTO '+@table_name+'
        FROM my_view
        WHERE string = ''Strings must use double apostrophe''
    ');

J'espère que cela aide, mais cela pourrait être fastidieux si le code est trop volumineux, donc si vous avez trouvé une meilleure façon, veuillez partager!

Rodrigo
la source
-2
"SELECT *
  INTO 
    @TempCustomer 
FROM 
    Customer
WHERE 
    CustomerId = @CustomerId"

Ce qui signifie créer une nouvelle @tempCustomertable variable et insérer des données du client. Vous l'aviez déjà déclaré ci-dessus, donc pas besoin de le déclarer à nouveau. Mieux vaut aller avec

INSERT INTO @tempCustomer SELECT * FROM Customer
koushik veldanda
la source
4
Ça ne marche pas. Vous devez toujours déclarer la variable de table au préalable.
Johan Boulé