Sql-Server
如果塊無法在過程中創建臨時表
我試圖在一個過程中做到這一點:
DECLARE @a bit = 1; BEGIN SELECT * INTO #aTemp FROM OPENROWSET( ... ); IF @a = 0 BEGIN SELECT ... INTO #bTemp FROM #aTemp; END ELSE BEGIN SELECT ... INTO #bTemp FROM #aTemp; END END
我得到錯誤:
Msg 2714, Level 16, State 1, Line 10 There is already an object named '#bTemp' in the database.
為什麼會發生這種情況,是否有解決方法?
更新
我試圖按照這裡
DROP
的建議添加一個語句,但它仍然不起作用:DECLARE @a bit = 1; BEGIN SELECT * INTO #aTemp FROM OPENROWSET( ... ); IF @a = 0 BEGIN IF OBJECT_ID('[tempdb]..#bTemp') IS NOT NULL BEGIN DROP TABLE #bTemp; END SELECT ... INTO #bTemp FROM #aTemp; END ELSE BEGIN IF OBJECT_ID('[tempdb]..#bTemp') IS NOT NULL BEGIN DROP TABLE #bTemp; END SELECT ... INTO #bTemp FROM #aTemp; END END
根據文件:
如果在單個儲存過程或批處理中創建了多個臨時表,則它們必須具有不同的名稱。
我最終在塊之前創建了表格,
IF
如下所示:DECLARE @a bit = 1; BEGIN IF OBJECT_ID('[tempdb]..#bTemp') IS NOT NULL BEGIN DROP TABLE #bTemp; END CREATE TABLE #bTemp ( [c] int); IF @a = 0 BEGIN INSERT INTO #bTemp SELECT 1 AS [c]; END ELSE BEGIN INSERT INTO #bTemp SELECT 1 AS [c]; END DROP TABLE #bTemp; END
這不是問題的答案,只是向@SebastienMeine 展示##global 臨時表如何殺死並發。
在一個視窗中,執行以下操作:
CREATE PROCEDURE dbo.floob1 @p INT AS BEGIN SET NOCOUNT ON; SELECT a = @p INTO ##floob; END GO CREATE PROCEDURE dbo.floob2 AS BEGIN SET NOCOUNT ON; SELECT a FROM ##floob; END GO EXEC dbo.floob1 @p = 1; WAITFOR DELAY '00:01:00'; EXEC dbo.floob2;
結果:
a ---- 1
然後打開另一個視窗,執行以下操作:
BEGIN TRY EXEC dbo.floob1 @p = 2; END TRY BEGIN CATCH PRINT 'Something bad happened.'; END CATCH GO EXEC dbo.floob1 @p = 2; GO EXEC dbo.floob2;
結果:
發生了不好的事情。
消息 2714,級別 16,狀態 6,過程 floob1
數據庫中已經有一個名為“##floob”的對象。
a ---- 1
所以##table 仍然存在,即使它創建的過程早已完成。
然後在第一個視窗完成後,再次嘗試在第一個視窗中執行此部分:
EXEC dbo.floob1 @p = 1;
結果:
消息 2714,級別 16,狀態 6,過程 floob1
數據庫中已經有一個名為“##floob”的對象。
因此,即使同一使用者只是嘗試再次創建,##table 仍然存在。
這說明:
- 一次只有一個使用者可以有效地呼叫此過程
- 不要打擾刪除#temp 表(我對此持懷疑態度)的標準建議不適用於##temp 表。