在T-SQL中选择表变量


372

有一个复杂的SELECT查询,我想从中将所有行插入表变量中,但是T-SQL不允许这样做。

同样,不能在SELECT INTO或INSERT EXEC查询中使用表变量。 http://odetocode.com/Articles/365.aspx

简短示例:

declare @userData TABLE(
                        name varchar(30) NOT NULL,
                        oldlocation varchar(30) NOT NULL
                       )

SELECT name, location
INTO @userData
FROM myTable
    INNER JOIN otherTable ON ...
WHERE age > 30

table变量中的数据以后将用于将其插入/更新回不同的表中(大多数情况下是对相同数据的复制,并进行了较小的更新)。这样做的目的是使脚本比SELECT INTO直接放入正确的表中更易于理解和自定义。性能不是问题,因为rowcount它很小,只有在需要时才手动运行。
...或者只是告诉我我做错了什么。

Answers:


601

尝试这样的事情:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData (name, oldlocation)
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

2
如果将“ SELECT name,location FROM myTable”作为要插入到UserData表中的值,则与select中变量的名称与表定义中的名称匹配无关紧要。您正在选择“名称”以进入UserData“名称”变量,但您正在选择“位置”,并以某种方式将其分配给UserData“ oldlocation”变量。SQL会自动映射这些映射还是会引发某种异常?
阿兰·穆赫兰

名称无关紧要,仅列类型无关。
CristiC

5
哇,这是有道理的,但同时我的解析器也感到有点冒犯:)
Aran Mulholland 2015年

我似乎无法在UPDATE语句中使用此功能:要点链接
Paul-Sebastian Manole

1
在insert语句中,如果不显式声明这些列,则它们将按照原始create table语句中声明的顺序进行映射,就像select *一样。因此,将select语句中的位置映射到@userData表中的oldlocation,因为location在select的结果集中的位置2中,而oldlocation是表定义中的第2列。就是说,永远不要这样做。不依赖列或行的数据库排序。始终对此明确。
absmiths

94

的目的SELECT INTO是(根据文档,我的重点是)

创建另一个表从值的新表

但是您已经有了目标表!所以你想要的是

INSERT语句将一个或多个新行添加到表中

您可以通过以下方式指定数据值:

...

通过使用SELECT子查询来指定一个或多个行的数据值,例如:

  INSERT INTO MyTable 
 (PriKey, Description)
        SELECT ForeignKey, Description
        FROM SomeView

并且在这种语法中,允许它MyTable是一个表变量。


1
真的希望接受的答案包含此信息!
戴维·布朗

我得到MyTable是执行此操作的“无效对象名称”,因此此答案中缺少某些内容。
迈克·弗林

@MikeFlynn MyTable您的实际表格名称的占位符。我认为没有任何真正的数据库,其表名为...MyTable
AakashM

如果我想用SELECT INTO创建/声明一个表变量...?例如,要将表变量的列定义为t1.somecolumn,t1.othercolumn,t2。*
Armando

27

您还可以使用公用表表达式来存储临时数据集。它们更加优雅和友好:

WITH userData (name, oldlocation)
AS
(
  SELECT name, location 
  FROM   myTable    INNER JOIN 
         otherTable ON ...
  WHERE  age>30
)
SELECT * 
FROM   userData -- you can also reuse the recordset in subqueries and joins

喜欢这个!谢谢。
fourpastmidnight

我不认为这会构成副本,如果您从userData删除或更新,它将不会删除和更新原始表中的记录吗?
atreeon

是的,删除和对CTE UPDATE将修改源表只要CTE不使用连接,联合等参考多个表
nanestev

2
不利的是,您只能在紧随其后的命令中使用CTE表。如果出于任何原因您需要多次通过结果集,那么CTE将无法工作。OP似乎暗示将进行多次修改,在这种情况下这将不起作用-“表变量中的数据以后将用于将其插入/更新回不同的表中(多数情况下是相同数据的副本,更新)。”
托尼

16

您可以尝试使用临时表...如果不从应用程序执行此操作。(可以手动运行此方法)

SELECT name, location INTO #userData FROM myTable
INNER JOIN otherTable ON ...
WHERE age>30

您省去了以这种方式声明表的工作...帮助临时查询...这将创建一个本地临时表,除非您处于同一会话中,否则其他会话将不可见。如果您正在从应用程序中运行查询,则可能是一个问题。

如果您要求它在应用程序上运行,请使用以这种方式声明的变量:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

编辑:你们中许多人提到从连接更新到会话的可见性。创建临时表不是Web应用程序的选项,因为可以重复使用会话,在这种情况下,请坚持使用临时变量


2
抱歉,忘了提及我没有CREATE TABLE的权限。
Indrek

6
创建一个临时文件会有更多的开销。
狗仔队2012年

2
使用临时表并不总是安全的。例如,Web服务。通过具有单个连接的Web服务来限制服务器上的最大连接并进一步保护SQL,临时表将存在于每个通过的查询中,并且可以覆盖当前正在使用它的用户。
法兰克

12
@Franck-如果使用全局临时表(两个哈希前缀),则表示正确。但是,本地临时表(一个哈希前缀)将被隔离到单个会话(也称为单个连接)中,因此除非您对所有请求使用单个连接(否则,否则不会涉及到并发问题)建议)。但是,可能的性能影响仍然存在。
maf748 2014年

@GazB当然,带有副作用的任何语句都将被排除在之外function。根据我的经验,在大多数情况下,某些人认为他们需要这样的声明,这实际上意味着他们应该重新考虑function-或至少重构为procedure。至少为我自己说话。:-)
underscore_d


5

首先创建一个临时表:

步骤1:

create table #tblOm_Temp (

    Name varchar(100),
    Age Int ,
    RollNumber bigint
)

**步骤2:**在Temp表中插入一些值。

insert into #tblom_temp values('Om Pandey',102,1347)

步骤3:声明一个表变量以保存临时表数据。

declare   @tblOm_Variable table(

    Name Varchar(100),
    Age int,
    RollNumber bigint
)

步骤4:从临时表中选择值,然后插入表变量中。

insert into @tblOm_Variable select * from #tblom_temp

最后将值从临时表插入到Table变量中

步骤5:可以检查表变量中插入的值。

select * from @tblOm_Variable

1

好的,现在我可以通过下面的努力将其插入@table中:

INSERT @TempWithheldTable SELECT
a.SuspendedReason,a.SuspendedNotes,a.SuspendedBy,a.ReasonCode FROM OPENROWSET(BULK 'C:\ databases中\ WithHeld.csv',FORMATFILE = N'C:\ databases中\ Format.txt”,
错误文件= N'C:\ Temp \ MovieLensRatings.txt')AS a;

这里最主要的是选择要插入的列。


我得到一个“必须声明表变量“ @TempWithheldTable”的编译错误消息
atreeon

-5

使用SELECT INTO的原因之一是它允许您使用IDENTITY:

SELECT IDENTITY(INT,1,1) AS Id, name
INTO #MyTable 
FROM (SELECT name FROM AnotherTable) AS t

这对表变量不起作用,这太糟糕了...


6
但是,您可以声明带有IDENTITY列的表变量。
马丁·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.