指定執行儲存過程的順序
問題:
如果獨立執行,呼叫我的儲存過程的順序不會產生錯誤,但是當執行一次時,會產生以下錯誤:
Msg 2627, Level 14, State 1, Procedure sp_ETL_S1_tbl1, Line 40 Violation of PRIMARY KEY constraint 'PK__tbl1__EE1C17C10200000'. Cannot insert duplicate key in object 'S1.tbl1'. The duplicate key value is (0). The statement has been terminated.
假設:
我相信這是由於第一個包含
DROP TABLE
語句的儲存過程,並且由於某種原因,當所有儲存過程一起執行時它不會首先被呼叫。違規程式碼:
mssql execute_sps.sql USE db1; GO EXEC sp_ETL_db1_CreateSchemas; EXEC sp_ETL_dbo_tbl1; EXEC sp_ETL_dbo_tbl2;
上述程序定義:
創建模式和表的儲存過程。
sp_ETL_db1_CreateSchemas.sql USE db1; DROP PROCEDURE sp_ETL_db1_CreateSchemas; GO CREATE PROCEDURE sp_ETL_db1_CreateSchemas AS GO DROP TABLE S1.tbl1 DROP TABLE S1.tbl2 DROP SCHEMA S1; GO CREATE SCHEMA S1; GO CREATE TABLE S1.tbl1( SalesGroupID varchar(20) NOT NULL PRIMARY KEY , SalesGroupType int , SalesGroup varchar(20) ) ; GO CREATE TABLE S1.tbl2( [NameID] int NOT NULL PRIMARY KEY , [FirstName] varchar(50) , [MiddleName] varchar(50) , [LastName] varchar(50) , [LastUpdated] datetime ) ;
儲存過程到 ETL 數據從
(olddb.tbl1, olddb.tbl2)
到(db1.S1.tbl1 , db1.S1.tbl2)
USE db1; GO DROP PROCEDURE sp_ETL_S1_tbl1; GO CREATE PROCEDURE sp_ETL_S1_tbl1 AS SET NOCOUNT ON IF object_id('tempdb.dbo.#SalesGroup') IS NOT NULL BEGIN DROP TABLE #SalesGroup END SELECT [SalesGroupID] , [SalesGroupType] , [SalesGroup] INTO #SalesGroup FROM olddb.tbl1 ; INSERT INTO db1.S1.tbl1( [SalesGroupID] , [SalesGroupType] , [SalesGroup] ) SELECT [SalesGroupID] , [SalesGroupType] , [SalesGroup] FROM #SalesGroup
USE db1; GO DROP PROCEDURE sp_ETL_S1_tbl2; GO CREATE PROCEDURE sp_ETL_S1_tbl2 AS SET NOCOUNT ON IF object_id('tempdb.dbo.#Names') IS NOT NULL BEGIN DROP TABLE #Names END SELECT [NameID] , [FirstName] , [MiddleName] , [LastName] , [LastUpdated] INTO #Names FROM olddb.tbl2 ; INSERT INTO db1.S1.tbl2( [NameID] , [FirstName] , [MiddleName] , [LastName] , [LastUpdated] ) SELECT [NameID] , [FirstName] , [MiddleName] , [LastName] , [LastUpdated] FROM #Names
SQL Server 將一次一個地從上到下批量執行語句。每個語句將在下一個語句執行之前完成。在您的情況下,這意味著第一個 SP 執行完成,然後第二個啟動並執行完成,然後第三個啟動並執行完成。沒有任何情況可以發生其他任何事情。
您的錯誤在於您如何定義儲存過程 sp_ETL_db1_CreateSchemas。您使用 GO 命令就像它是儲存過程定義的一部分一樣。它不是。正如文件所說
GO 不是 Transact-SQL 語句;它是 sqlcmd 和 osql 實用程序以及 SQL Server Management Studio 程式碼編輯器辨識的命令。
SQL Server 實用程序將 GO 解釋為它們應該將目前批次的 Transact-SQL 語句發送到 SQL Server 實例的信號。
當您通過 SSMS(或任何其他實用程序)執行文件 sp_ETL_db1_CreateSchemas.sql 時,從文件開頭到第一個 GO 的語句將發送到 SQL Server 引擎。當該呼叫返回時,發送第一個 GO 和第二個 GO 之間的語句,依此類推。最終,該文件中的所有批次都被處理,結果就是您所期望的。
或者它主要是你所期望的。儲存過程的定義只是一個由三行組成的存根
CREATE PROCEDURE sp_ETL_db1_CreateSchemas AS
您可以通過查看SQL Server內部儲存的內容作為該 SP 的定義來驗證這一點:
exec sp_helptext 'sp_ETL_db1_CreateSchemas';
你只會看到那三行。
當您一起執行由三個 SP 組成的批處理時,將執行這個空存根。從語法上講,它是正確的,因此您不會收到錯誤消息。但它沒有語句,因此不會刪除任何表,並且所有數據都保持完好。因此,當後續 SP 嘗試重新載入相同的數據時,就會出現密鑰違規。
如果您需要在儲存過程中批處理語句,您可以使用
EXECUTE('...');
語法。