多次创建和删除#SomeTable是“合法的”吗?


8

我已经将代码分类为“连贯的块”,可以一遍又一遍地插入较长的“配置脚本”中,而我使用的模式之一是:

CREATE TABLE #WidgetSetting 
(
    WidgetID bigint not null,
    Name nvarchar(100) not null,
    Value nvarchar(max) not null,
    CreateDate datetime not null
)

INSERT VALUES

MERGE TABLES

DROP TABLE #WidgetSetting

但是现在SSMS抱怨到下次CREATE TABLE火灾时该对象已经存在。是什么赋予了?

我认为很明显,我将不得不在脚本开始时声明一次表,然后截断而不是删除,但是自然地,令人沮丧的是,无法仅删除表并再次使用相同的名称。


正如Aaron在下面评论的那样,如果这是您采用的方法,那么最简单的解决方法可能是将#TABLE放在脚本的最后,然后在它们之间的步骤中将其截断。这是假设不可能仅仅重新设计脚本以使其在不同的地方工作。:)
卡恩(Kahn)

1
实际上,这就是我要解决的问题。我只是对这种行为感到困惑。他解释了为什么要解决这个问题而不是如何解决。
jcolebrand

Answers:


11

不,解析器不允许您在同一批处理中两次创建相同的#temp表(这与SSMS无关)。即使只能创建#temp表的一个副本也没关系;例如,在以下条件逻辑中,人类显然只能执行一个分支,而SQL Server则看不到它:

IF 1 = 1
BEGIN
  CREATE TABLE #x(i INT);
  DROP TABLE #x;
END
ELSE
BEGIN
  CREATE TABLE #x(j INT);
  DROP TABLE #x;
END

消息2714,级别16,状态1,第8
行在数据库中已经有一个名为“ #x”的对象。

为了证明不是SSMS在编译时抱怨(常见的误解):

DECLARE @sql NVARCHAR(MAX) = N'IF 1 = 1
BEGIN
  CREATE TABLE #x(i INT);
  DROP TABLE #x;
END
ELSE
BEGIN
  CREATE TABLE #x(j INT);
  DROP TABLE #x;
END';

EXEC sp_executesql @sql;

即使SSMS在通过将动态SQL发送到服务器之前未尝试解析或验证动态SQL,也会产生完全相同的错误sp_executesql

当然,解决方法是重新使用相同的#temp表而不是删除它们,每次都使用不同的#temp表,或者首先不要使用#temp表。

这不是您应该期望SQL Server更好地处理的事情。换句话说,习惯于您决定采用的任何解决方法。

另请参阅有关堆栈溢出的此相关答案,它给出了另一种解释:

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.