【问题标题】:Why DROP TABLE doesn't seem to take effect before a SELECT INTO?为什么 DROP TABLE 在 SELECT INTO 之前似乎没有生效?
【发布时间】:2015-03-09 14:17:14
【问题描述】:

下面的 tSQL 查询让我很困惑:

select 1 as FIELD into #TEMP
drop table #TEMP
select 1 as FIELD into #TEMP

当我从 SQL Server Management Studio 会话窗口运行它时(按 F5 到整个查询,作为一个组),我收到以下错误:

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

请注意,在执行查询之前,表 #TEMP 不存在。

我认为代码不应该产生任何错误,因为第 2 行正在删除临时表。但是当执行第 3 行时,就好像 drop 没有生效。

我的问题:

  1. 为什么会发生错误?
  2. 如何修复查询以使其按预期执行?

PS。上面的查询是我的真实世界查询的简化,它显示了相同的症状。

PS2。不管这是否是一种合理的编程实践(正如 Sean 在他的 cmets 中暗示的那样),这种意想不到的行为促使我寻找有关如何解析这些查询的信息,希望这些知识将来对我有所帮助。

【问题讨论】:

  • 这与 sql 编译器和解析器的工作方式有关。我的问题是,为什么世界上单个过程中的临时表会有相同的名称???这听起来像是让我感到困惑的秘诀。
  • 您可以在第一个 drop table 之后添加 GO 以指示批处理的结束,但如果这实际上是存储过程的一部分,它将不起作用,即使它是 不在存储过程中,Sean 的 cmets 仍然适用。
  • @Sean - 这是一个很好的观点。实际上,这就是我最终要做的——为临时表使用不同的名称。但我对这个问题很感兴趣,这就是我问的原因。
  • @Sean - 我虽然 INSERT INTO 会在运行时解决 #TEMP 对象的存在,但事实并非如此,是吗?一位同事暗示可能会在编译时解析对象,但我不明白在这种情况下它是如何工作的。你有什么暗示为什么会这样吗?

标签: sql-server tsql sql-server-2012


【解决方案1】:

因为我发现现有表的搜索是不同的:

select 1 as FIELD into #TEMP
drop table #TEMP

当您在这些命令之后使用into 语句时:

select 1 as FIELD into #TEMP

错误是:

数据库中已经有一个名为“#TEMP”的对象。

当您在这些命令之后在#TEMP 上使用select 时:

select * from #TEMP

错误是:

对象名称“#TEMP”无效。

所以,在第一种情况下,有一个名称为 #TEMP 的对象,而在另一种情况下,没有一个名称为 #TEMP 的对象!。

technet.microsoft 的重要说明是:

DROP TABLE 和 CREATE TABLE 不应在同一批次中的同一张表上执行。否则可能会发生意外错误。


在 SQL Server 数据库引擎删除表的注释中:

SQL Server 数据库引擎将实际的页面释放及其关联的锁推迟到事务提交之后。

因此,使用select 语句的第二个错误可能与实际页面释放有关,而使用into 语句的第一个错误可能与与事务相关的锁之间的持续时间有关提交

【讨论】:

  • 感谢您的回答。我现在明白这个问题了。您从 technet.microsoft 引用的注释特别有用。
【解决方案2】:

这里试试这个:

select 1 as FIELD into #TEMP
drop table #TEMP
GO
select 1 as FIELD into #TEMP

【讨论】:

  • 我已经尝试过了,但问题是在GO 之后所有上下文(变量)都丢失了。但这很有帮助,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
相关资源
最近更新 更多