2013-07-12 115 views
2

我有以下腳本:IF NOT EXISTS似乎沒有奏效

BEGIN 
    IF NOT EXISTS (SELECT SessionID FROM SessionData WHERE SessionID = @SessionID) 
    BEGIN 
    SELECT @RegionID = RegionID 
    FROM Region 
    WHERE Domain = @Domain 
    INSERT INTO SessionData (
    SessionID, 
    SystemID, 
    RegionID, 
    RegionDomain, 
    RemoteAddr, 
    CreatePage) 
    VALUES (
    @SessionID, 
    @SystemID, 
    @RegionID, 
    @RegionDomain, 
    @RemoteAddr, 
    @CreatePage) 
END 
END 

偶爾如下網站產生一個錯誤:

PRIMARY KEY約束 'PK_SessionData' 的相關規定。不能在對象的'sbuser.SessionData'中插入 重複鍵。重複鍵 的值爲(1h6l61h069srw1nmw73j)。來源:Microsoft OLE DB提供程序 SQL服務器編號:-2147217873

爲什麼它運行腳本,如果有重複鍵..?我很困惑..任何幫助將不勝感激。

非常感謝..

+0

不知道爲什麼你會得到這個錯誤,但我建議使用「MERGE」語句來完成這項工作,因爲它一次執行檢查/更新。 –

+0

如果使'... WHERE NOT EXISTS(SELECT ...)'部分插入語句而不是條件分支會發生什麼? – Tim

+1

@Tim - [這不會阻止沒有附加鎖定提示的競爭條件](http://stackoverflow.com/q/3407857/73226) –

回答

4

兩個併發的重疊進程都將通過NOT EXISTS檢查並嘗試INSERT。

也就是說,NOT EXISTS是對INSERT

無論是NOT EXISTS和INSERT可以寫入到一個單一的MERGE

MERGE INTO 
    SessionData WITH (SERIALIZABLE) S 
USING (
    SELECT 
     @SessionID AS SessionID , 
     @SystemID AS SystemID , 
     RegionID, 
     @RegionDomain AS RegionDomain , 
     @RemoteAddr AS RemoteAddr , 
     @CreatePage AS CreatePage 
    FROM Region 
    WHERE Domain = @Domain 
    ) src ON S.SessionID = src.SessionID 
WHEN NOT MATCHED THEN 
    INSERT (
     SessionID, 
     SystemID, 
     RegionID, 
     RegionDomain, 
     RemoteAddr, 
     CreatePage) 
    VALUES (
     src.SessionID, 
     src.SystemID, 
     src.RegionID, 
     src.RegionDomain, 
     src.RemoteAddr, 
     src.CreatePage); 
+0

你能解釋一下嗎..?我將如何重寫腳本以避免此問題? – neojakey

+0

你有沒有試過把它放在交易中? – openshac

+0

@openshac:我不需要一個MERGE:這是合併的要點,做一個電話,並刪除需要一個 – gbn

-1
如何

這個單獨的查詢:

INSERT INTO SessionData (
    SessionID, 
    SystemID, 
    RegionID, 
    RegionDomain, 
    RemoteAddr, 
    CreatePage) 
SELECT 
    @SessionID, 
    @SystemID, 
    (SELECT TOP 1 RegionID FROM Region WHERE Domain = @Domain), 
    @RegionDomain, 
    @RemoteAddr, 
    @CreatePage) 
WHERE 
    NOT EXISTS (SELECT SessionID FROM SessionData WITH (UPDLOCK, HOLDLOCK) 
           WHERE SessionID = @SessionID) 

這是一個簡潔的方式來獲得沒有任何MERGE或交易的原子操作。

+1

-1:併發性仍然不安全。不存在仍然可以給予真實。爲什麼我使用MERGE和SERIALIZABLE ...請參閱我的答案http://stackoverflow.com/search?tab = votes&q = user%3a27535%20jfdi – gbn

+0

您可以按照http://stackoverflow.com/a/3407890/27535(請參閱評論)使用鎖定提示以確保安全。但是你的代碼是MERGE在內部完成的任務......另請參閱http://michaeljswart.com/2011/09/mythbusting-concurrent-updateinsert-solutions/ – gbn