ChatGPT解决这个技术问题 Extra ChatGPT

SELECT INTO T-SQL 中的表变量

有一个复杂的 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

表变量中的数据稍后将用于将其插入/更新回不同的表(主要是相同数据的副本,并进行少量更新)。这样做的目的是让脚本比直接在正确的表中执行 SELECT INTO 更具可读性和更容易定制。性能不是问题,因为 rowcount 相当小,并且仅在需要时手动运行。
...或者告诉我我是否做错了。


C
CristiC

尝试这样的事情:

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;

如果您将“SELECT name, location FROM myTable”作为您将插入到 UserData 表中的值,则选择中的变量名称是否与表定义中的名称匹配无关紧要。您正在选择“名称”以进入 UserData 的“名称”变量,但您正在选择“位置”并以某种方式将其分配给 UserData 的“旧位置”变量。 SQL 会自动映射这些还是会抛出某种异常?
名称无关紧要,只有列类型。
哇,这很有意义,但同时我的解析器感觉有点冒犯了:)
我似乎无法在 UPDATE 语句中使用它:gist link
在插入语句中,如果您没有显式声明列,那么它们将按照原始 create table 语句中声明的顺序进行映射,就像 select * 一样。因此,select 语句中的 location 映射到 @userData 表中的 oldlocation,因为 location 在 select 的结果集中位于位置 2,而 oldlocation 是表定义中的第 2 列。也就是说,永远不要这样做。不依赖于列或行的数据库排序。始终明确这一点。
A
AakashM

SELECT INTO 的目的是(根据文档,我强调)

从另一个表中的值创建新表

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

INSERT 语句向表中添加一个或多个新行 您可以通过以下方式指定数据值: ... 通过使用 SELECT 子查询为一个或多个行指定数据值,例如: INSERT INTO MyTable (PriKey , 描述) SELECT ForeignKey, Description FROM SomeView

this 语法中,允许 MyTable 是一个表变量。


真的希望接受的答案包括此信息!
我得到 MyTable is "Invalid Object Name" 这样做,所以这个答案中缺少一些东西。
@MikeFlynn MyTable 这里是 your 实际 table 名称的 placeholder。我认为没有任何真正的数据库具有名为 MyTable 的表 ...
如果我想用 SELECT INTO... 创建/声明一个表变量?例如,要将表变量的列定义为 t1.somecolumn, t1.othercolumn, t2.*
啊,但这就是我想做的!我想从另一个表中的值创建一个表变量,所以我不必指定表的列 3 次。一次在创建表中,两次在插入中。
n
nanestev

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

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

我认为这不会复制,如果您从 userData 中删除或更新,它不会删除和更新原始表中的记录吗?
是的,只要 CTE 不使用连接、联合等引用多个表,CTE 上的 DELETE 和 UPDATE 就会修改源表。
这样做的缺点是您只能在紧随其后的命令中使用 CTE 表。如果您出于某种原因需要多次通过结果集,CTE 将不起作用。 OP 似乎暗示将进行多项修改,在这种情况下这将不起作用 - “表变量中的数据稍后将用于将其插入/更新回不同的表(主要是相同数据的副本更新)。”
当您加入从大表中选择的 CTE 时,使用 CTE 的真正缺点就会出现。通过使用表变量而不是 CTE,我能够将处理时间减少两个数量级以上(来源:500 万行,增益:>30 分钟到 5 秒)!
W
Whimsical

您可以尝试使用临时表...如果您不是从应用程序中执行此操作。 (手动运行可能没问题)

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 应用程序的选项,因为会话可以重用,在这些情况下坚持使用临时变量


抱歉,忘了说我没有 CREATE TABLE 的权限。
创建一个临时文件有更多的开销。
使用临时表并不总是安全的。例如,网络服务。使用具有单个连接的 Web 服务来限制服务器上的最大连接并更多地保护 SQL,临时表将存在于每个通过的查询中,并且可以覆盖当前使用它的人。
@Franck - 如果您使用全局临时表(两个哈希前缀),那么您是正确的。但是,本地临时表(一个哈希前缀)将被隔离到单个会话(也称为单个连接),因此除非您对所有请求使用单个连接(不是建议)。但是,可能的性能影响仍然存在。
@GazB 当然,任何具有副作用的语句都不能在 function 中使用。根据我的经验,在大多数情况下,如果有人认为他们需要这样的语句,这实际上意味着他们应该重新考虑他们的 function,或者至少重构为 procedure。至少为我自己说话。 :-)
N
Noel Abrahams

尝试使用 INSERT 而不是 SELECT INTO

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

    INSERT @UserData   
    SELECT name, oldlocation

如果您不首先声明表变量,则不是,这是我试图解决的问题:i.imgur.com/2PXIubF.png
N
Nerdroid

首先创建一个临时表:

步骤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

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

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

select * from @tblOm_Variable

R
RahulJha

好的,现在通过足够的努力,我可以使用以下内容插入@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', ERRORFILE= N'C:\Temp\MovieLensRatings.txt' ) 作为一个;

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


我收到“必须声明表变量“@TempWithheldTable”编译错误消息
S
Smern

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

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

这不适用于表变量,这太糟糕了......


不过,您可以使用 IDENTITY 列声明表变量。