2016-09-28 51 views
0

我有一個名爲dbo.mtestUnique的表,其中有兩個列id和desc,我在「desc」上有一個唯一索引,兩個進程在這個表中插入數據同一時間,我該如何避免插入重複值並違反唯一索引?SQL Server 2014-並行進程在具有唯一索引的表格中插入相同的值

不存在,左連接不起作用。

複製這個你可以測試數據庫中創建表:

CREATE TABLE mtestUnique 
(
    id INT , 
    [DESC] varchar(50), 
    UNIQUE([DESC]) 
) 

,然後在兩個不同的查詢上SSMS運行下面的腳本。

SET XACT_ABORT ON; 
DECLARE @time VARCHAR(50) 

WHILE (1=1) 
BEGIN 
    IF OBJECT_ID('tempdb..#t') IS NOT NULL 
     DROP TABLE #t 

    SELECT @time = CAST(DATEPART(HOUR , GETDATE()) AS VARCHAR(10)) + ':' + RIGHT('00' +CAST(DATEPART(MINUTE , GETDATE())+1 AS VARCHAR(2)),2) 

    SELECT MAX(id) + 1 id , 'test' + @time [DESC] 
     INTO #t 
    FROM dbo.mtestUnique 

    -- to insert as exact same time 
    WAITFOR TIME @time 

     INSERT INTO dbo.mtestUnique 
       (id, [DESC]) 
     SELECT * 
     FROM #t t 
     WHERE NOT EXISTS (
         SELECT 1 
         FROM dbo.mtestUnique u 
         WHERE u.[DESC] = t.[Desc] 

         ) 

END 

我甚至把插入一個TRAN,但沒有運氣。

感謝您的幫助提前。

+0

您可以在ID列上使用[Identity](https://msdn.microsoft.com/en-us/library/ms186775.aspx)嗎? – SMM

+0

它會如何幫助? – user3951476

+0

如果你需要一個獨特的desc,那麼使其獨特,而不僅僅是時間。使用,例如NEWID()或當前session_ID +時間。 – Anton

回答

0

防止唯一約束衝突的唯一方法是不爲列插入重複值。如果你有唯一的約束,當你嘗試插入一個重複的描述時它會拋出一個錯誤,但它不會控制試圖插入什麼描述。這就是說,如果你只需要一個唯一的標識符,我會強烈建議使用ID來代替。將其設置爲自動中斷整數,並且不要手動插入。只需提供描述,SQL Server將爲您填充ID,避免重複。

+0

這只是一個示例,假設我有一個用戶名錶和用戶名是唯一的,所以我把一個唯一的約束,現在不同的進程試圖插入userName在該表中。在這種情況下,我不需要ID或標識符。
「防止唯一約束衝突的唯一方法是不要爲該列插入重複值。」
這就是爲什麼我不存在。 – user3951476

+0

是的,如果你只想要一個唯一的用戶名,那麼唯一的約束就是你所需要的,儘管我會強烈推薦一個自動控制的整數,如果不是主鍵,那麼至少有一個索引反對它,如果用戶名是反對任何其他表格。 你看到什麼問題?其中一個查詢在嘗試插入時是否違反約束條件?即使您等到@time,其中一個插入應在表上鎖定一個鎖,以便它們不會實際並行插入。 –

+0

準確地說,一個進程應該有一個鎖,第二個進程應該等到第一個進程完成,然後插入它應評估「不存在」並插入行而不違反唯一約束,但看起來像sql服務器做不同的事情。我認爲SQL Server要求對錶進行IU鎖定,並評估兩個進程上的「not exist」語句,並且在插入步驟中,一個進程將鎖升級爲U,並且第二個進程等待此步驟的鎖定。 – user3951476

相關問題