SQL Server SELECT INTO @variable?

332

我有一段代码在我的Sql(2008)存储过程中,它可以完美地执行:

    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

那么我的问题是,你们是否有可能做出类似以下的操作:

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

我希望能够在其他语句中重复使用内存中的数据,不过使用上述语句会导致 SQL Server 出错。但我不想创建单独的变量,并通过针对同一表的单独 SELECT 语句初始化每个变量... 唉!!!

有没有关于如何在不对同一表进行多次查询的情况下实现类似的功能的建议?


1
“创建单独的变量并通过单独的SELECT语句对每个变量进行初始化” - 为什么需要这样做?只需一次声明declare @t table,如果需要重复使用它,请在再次插入之前执行DELETE @TempCustomer - RichardTheKiwi
您可以使用表变量 - https://www.mssqltips.com/sqlservertip/6039/sql-server-table-variable-example/ - AquaAlex
7个回答

636
如果你想要简单地给一些变量赋值以备后用,你可以使用以下方式一次性完成:
declare @var1 int,@var2 int,@var3 int;

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

如果那正是你想要的类型


2
在我看来,这是最好的答案。但是如果结果不止一个,会发生什么呢? - capitano666
如果结果大于一个,则可以获得其中一个可用值。这可能会成为一个有趣的谜题!请参阅https://www.mssqltips.com/sqlservertip/1888/when-to-use-set-vs-select-when-assigning-values-to-variables-in-sql-server。 - Smandoli
16
为了强制查询只返回一行记录,请使用 SELECT TOP 1。 - Adrian
1
@Adrian 是的,上面的查询假设您选择了单行数据。如果您想要更高级的逻辑,您还可以使用排序和聚合函数。 - dougajmcdonald
1
如果你没有使用OP正在使用的数据库类型,那么并不是所有类型都支持Adrian提到的TOP 1。SQL Server/MS Access使用TOP,MySQL使用LIMIT,Oracle使用ROWNUM。请参考https://www.w3schools.com/sql/sql_top.asp获取更多信息。 - Tyler
只需使用表变量。 - AquaAlex

244

你不能使用SELECT .. INTO ..语句将数据插入到表变量中。最好的方法是先创建表变量,然后再向其中插入数据。你的第二段代码应该是:

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

5
需要注意的是,在公共表达式(CTE)上下文中,这也能够完美地运作。巴芝嘎! - Michael Krauklis
5
为什么不能像实际临时表一样选择到一个表变量中?这是有人可以回答的问题吗? - KSwift87
为什么不可能呢?很可能是为了防止内存溢出异常导致数据库服务器崩溃。数据库服务器需要是一个非常稳定的进程... - Justin Rowe

43
你可以这样做:
SELECT 
    CustomerId, 
    FirstName, 
    LastName, 
    Email
INTO #tempCustomer 
FROM 
    Customer
WHERE 
    CustomerId = @CustomerId

然后稍后
SELECT CustomerId FROM #tempCustomer

你不需要声明 #tempCustomer 的结构

3
这两个观点都是不正确的。临时表在存储过程外部没有作用域,而表变量与临时表一样,并非仅限于“内存中使用”。 - Martin Smith
9
当不再需要使用#tempCustomer表时,不要忘记添加DROP TABLE #tempCustomer语句,否则下一条SELECT语句会因为#tempCustomer already exists错误而失败。请注意保持原意并确保翻译通俗易懂。 - ViRuSTriNiTy
@ViRuSTriNiTy 这个表只对当前会话可见。一旦会话结束或连接终止,该表将自动删除。 - undefined

21

看起来你的语法有些问题。 这里有一些好例子

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
稍后再说。
SELECT CustomerId FROM @TempCustomer

1
由于从dbforums的重定向,那个“好例子”链接已经变成了广告。您有更好的链接吗? - r2evans

4

2
##temptable - 直到所有者(创建者)删除它或断开连接。 - RichardTheKiwi
4
我不想使用临时表。临时表代价高且速度慢。我只想在一小段时间内保留特定记录的一些数据,并使其对多个 SQL 语句可用,而无需后续查找。由于表变量仅在定义它们的存储过程中有效,所以它们是存储该存储过程调用的元组数据的完美解决方案... - bleepzter
3
我忘了提到数据库存储在Azure中...我不想因为管理临时表而引入混乱。 - bleepzter
变量表是最好的选择。声明 @varTable 表 (....) - ARLibertarian

3
我在寻找解决同样问题的方案时发现了您的问题,而其他答案未能指出的是一种使用变量的方法,以永久形式更改表的名称,而非暂时性地更改。目前我所做的是将整个SQL代码与要使用的变量连接起来。就像这样:
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''
    ');

我希望这有所帮助,但如果代码太大,可能会变得繁琐。所以,如果你找到更好的方法,请分享!


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

这意味着创建一个新的@tempCustomer表变量,并将数据从Customer插入其中。您已经在上面声明了它,因此无需再次声明。最好使用现有声明。
INSERT INTO @tempCustomer SELECT * FROM Customer

4
不起作用,仍然需要事先声明表变量。 - Johan Boulé

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接