为什么在使用临时表两次时会出现无效的列名错误?

问题描述

如果我分别运行这些批次中的每一个,它就可以工作。但是,如果将它们组合到一个脚本中(就像运行 DACPAC 脚本时所做的那样,或者将它们都放在 SSMS 中的一个选项卡中),我会在第二次插入时收到 Invalid column name 错误。这是为什么?如果我需要这些在一个脚本中运行,我是否需要为第二批的临时表使用不同的名称?还是我遗漏了一些可以让我使用相同名称的东西?

IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
SELECT FirstName,LastName INTO #source FROM Musician WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( FirstName,LastName )
VALUES
('Geddy','Lee'),('Alex','Lifeson') 

SELECT * FROM #source

GO

IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
SELECT [Name],Genre INTO #source FROM Band WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( [Name],Genre )
VALUES
('rush','Rock'),('Ratt','Rock') 

SELECT * FROM #source

GO

解决方法

每个批次都是独立解析的。所以当您使用 GO 时它有效,因为它们在不同的批次中。

当你把所有东西都放在同一个批处理中时,SQL Server 会解析它看到的东西,它对隐藏在 DROP 条件后面的 IF 命令之类的逻辑视而不见。尝试以下操作,您会发现相同的内容:

IF (1=0) DROP TABLE IF EXISTS #x; CREATE TABLE #x(i int);
IF (1=1) DROP TABLE IF EXISTS #x; CREATE TABLE #x(j date);

你我都知道只有其中一个会执行,但解析器会在它开始执行(或评估任何条件)之前发现冗余表名。

这是可行的,因为现在每个批次都是单独解析的:

IF (1=0) DROP TABLE IF EXISTS #x; CREATE TABLE #x(i int);
GO
IF (1=1) DROP TABLE IF EXISTS #x; CREATE TABLE #x(j date);

这实际上会失败,即使它通过了解析(突出显示并选择 Parse 而不是 Execute),所以盲目是双向的:

IF (1=0) DROP TABLE IF EXISTS #x; CREATE TABLE #x(i int);
GO
IF (1=1) CREATE TABLE #x(j date);
,

在删除两个块中的表后使用 go 可以解决问题。

IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
go
SELECT FirstName,LastName INTO #source FROM Musician WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( FirstName,LastName )
VALUES
('Geddy','Lee'),('Alex','Lifeson') 

SELECT * FROM #source

GO

IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
go
SELECT [Name],Genre INTO #source FROM Band WHERE 1 = 0; -- set up temp table schema
INSERT INTO #source ( [Name],Genre )
VALUES
('Rush','Rock'),('Ratt','Rock') 

SELECT * FROM #source

GO