SQL Server:NOT EXISTS子句在并行执行SQL时不会停止重复

时间:2015-10-06 14:02:06

标签: sql-server vb.net sql-server-2008 sql-server-2008-r2 sql-server-2012

我有三个这样的数据库表:

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(电子表格中有大约50K条记录)。 上传电子表格时,如果bookser表格中尚未存在book_id和series_id的组合,我需要在bookseries表中插入记录。

所以,我正在做这样的事情(Pseudocode):

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子句不能在我的代码中停止重复插入的原因有关。

3 个答案:

答案 0 :(得分:0)

最简单的解决方案是在book_id,series_id上放置一个唯一约束,因为它们构成了链接表的自然复合键。然后,您只需要在执行插入并继续处理时处理唯一约束错误(编号2601或2627)。

对我来说,为什么你现在的代码没有按预期工作,这一点并不明显。两个用户是否同时尝试上传重复记录?如果是这样,我的猜测是事务范围是错误的,你应该在每次插入后提交,而不是在处理完所有记录之后提交。

答案 1 :(得分:0)

也许你的WHERE子句SELECT SQL正在返回Null?

怎么样:

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

答案 2 :(得分:0)

根据您的要求和Jamie的搭载,您可以考虑在所提到的两个列上添加一个唯一索引,并添加忽略重复作为潜在的解决方法。我没有足够的关于您的申请的信息,知道这是一个很好的建议,但它是另一种选择。

在此示例中,重要部分是 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