0

我有三個數據庫表這樣的條款不停止重複:SQL服務器:NOT EXISTS當SQL並行地執行

book(book_id INT IDENTITY(1,1) PK, book_name VARCHAR(255), book_code INT UNIQUE) 
series(series_id INT IDENTITY(1,1) PK, series_name VARCHAR(255), series_code INT UNIQUE) 
bookseries(bookseries_id INT IDENTITY(1,1) PK, book_id INT FK, series_id INT FK) -- The combination (book_id + series_id) should be unique. 

我有一個功能,用戶可以上傳電子表格,book_id和series_id人口(電子表格中有大約5萬條記錄)。 上傳電子表格時,如果book_id和series_id的組合尚未存在於bookseries表中,則需要將記錄插入bookseries表中。

所以,我做這樣的事情(僞):

Dim sqlList As New List(Of String) 
Dim sql As String = String.Empty 
For each row in spreadsheetRows 
    sql = String.Format("INSERT INTO bookseries(book_id, series_id) SELECT {0},{1} WHERE NOT EXISTS (SELECT 1 FROM bookseries WHERE book_id={0} AND series_id={1})", row.book_id, row.series_id) 
    sqlList.Add(sql) 

    If sqlList.Count MOD 500 = 0 Then insertListIntoDB(sqlList) 
Next 
If sqlList.Count > 0 Then insertListIntoDB(sqlList) 

這是正常工作(插入一條記錄,如果它不存在),當一個用戶上傳的電子表格。 但是,如果兩個用戶上載電子表格並且電子表格中填充了相同的記錄,則會將重複記錄插入bookseries表(重複book_id + series_id)。

我不明白爲什麼/如何插入重複項,因爲我期待WHERE NOT EXISTS子句停止重複插入。

例子:INSERT INTO bookseries(book_id, series_id) SELECT 100, 1000 WHERE NOT EXISTS (SELECT 1 FROM bookseries WHERE book_id=100 AND series_id=1000)

誰能勸這是爲什麼不工作,我會期望或建議是否有解決方法嗎?

預先感謝您。

PS:我知道了parameterized SQL使用,SQL InjectionDictionary,並直接在服務器上等執行raw SQL的缺點,所以請不要我爲什麼不能在這種情況下使用這些質疑。上面的例子只是爲了讓事情簡單並解釋我想要達到的目標。我的問題純粹與爲什麼NOT EXISTS子句不會停止我的代碼中的重複插入有關。

+2

取決於提交查詢的時間。在你的情況下,我建議你在數組中插入所有的ids,將所有的項目一次推入臨時表中,然後做一個查詢,從臨時表複製到真正的表中所有不重複的行。 –

+1

交易的邊界在哪裏?你甚至有嗎? – sstan

+0

感謝您的評論,@the_lotus和@sstan。我沒有一個邊界,只是一次性執行查詢'(insert into ...; insert into ...; insert into ...;)'。 – Sathish

回答

0

最簡單的解決方法是在book_id,series_id上設置唯一約束,因爲它們形成鏈接表的自然組合鍵。然後,只需要在插入並繼續處理時處理唯一的約束錯誤(編號2601或2627)。

這對我來說並不明顯,爲什麼你當前的代碼不能按預期工作。兩個用戶是否試圖同時上傳重複記錄?如果是這樣,我的猜測是事務範圍是錯誤的,你應該在每次插入後提交,而不是在處理所有記錄之後提交。

0

也許你的WHERE子句SELECT SQL返回Null?

如何:

... WHERE ((SELECT Count(*) FROM bookseries WHERE book_id=100 AND series_id=1000) = 0) 
+0

這是一個問題,評論或答案? – sstan

+0

是的,這是一個問題,評論和一個可能的答案。我添加了WHERE語法。 – rheitzman

0

根據您的要求,並捎帶過傑米,你可以考慮在與另外忽略重複作爲一個潛在的解決辦法所提到的兩列加入了獨特的指數。我沒有足夠的關於您的應用程序的信息來了解這是否是一個好建議,但它是一種替代方案。

在這個例子中,有意義的部分是IGNORE_DUP_KEY = ON。這可以讓你嘗試插入重複的行,但是SQL Server會默默地忽略它們。這可能會有插入前刪除您的WHERE NOT EXISTS檢查額外的好處。

CREATE UNIQUE CLUSTERED INDEX [UCX_bookseries] ON dbo.bookseries 
(
    book_id ASC, 
    series_id ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ON, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO