临时表仅存在于创建它的范围内(以及该范围的“子范围”),并且仅在该范围内持续存在。
所以,例如。如果您要运行以下内容,则不会出现任何错误:
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int);';
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int);';
这是因为表 #temp 只存在于“动态”语句的范围内,并且在完成后立即停止。
另一方面,像下面这样的事情会失败(这是错误的,请参阅底部的我的编辑):
CREATE TABLE #temp (ID int);
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int);';
DROP TABLE #temp;
这是因为“动态”语句可以访问“外部”范围,因此会看到 #temp 已经存在并生成错误。
不可能在同一个连接中同时运行 2 个语句,因此您将无法同时调用同一个存储过程。这意味着两者将具有不同的范围,因此将引用它们自己的对象#temp,这是特定于它们的范围的。
您可以用类似的想法再次对此进行测试。运行以下,然后打开一个新连接并再次运行它(在另一个完成之前)。你会注意到他们都成功了:
CREATE TABLE #temp (ID int);
WAITFOR DELAY '00:30'; --Waits 30 seconds
--While the WAITFOR happens, open the another connection and run all this SQL at the same time
DROP TABLE #temp;
旁注,全局临时表的行为方式不同,但我在这里特别只引用临时表,而不是全局表。
编辑:似乎我错了,有点,在内部范围。你实际上得到了一些非常奇怪的行为。采取以下措施:
CREATE TABLE #temp (ID int);
INSERT INTO #temp VALUES(1);
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int); SELECT * FROM #temp;';
SELECT *
FROM #temp
DROP TABLE #temp;
这将返回 2 个数据集,一个没有行,一个有 1 行。但是,如果您在 deferred 语句中删除 CREATE,那么您会从两者中获得 1 行:
CREATE TABLE #temp (ID int);
INSERT INTO #temp VALUES(1);
EXEC sys.sp_executesql N'SELECT * FROM #temp;';
SELECT *
FROM #temp
DROP TABLE #temp;
这发生在 SQL Server 2019 上,但我记得我记得这种行为在以前的版本上不是这样。也许我正在回忆(非常)旧的行为。