Sql-Server

指定執行儲存過程的順序

  • August 22, 2019

問題:

如果獨立執行,呼叫我的儲存過程的順序不會產生錯誤,但是當執行一次時,會產生以下錯誤:

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('...'); 語法

引用自:https://dba.stackexchange.com/questions/245712