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

Sql server SQL Server:NOT EXISTS子句在并行执行SQL时不会停止重复,sql-server,vb.net,sql-server-2008,sql-server-2008-r2,sql-server-2012,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, serie

我有如下三个数据库表:

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条记录。 上传电子表格时,如果bookseries表中不存在book_id和series_id的组合,我需要在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表duplicate book_id+series_id

我无法理解为什么/如何插入重复项,因为我希望WHERE NOT EXISTS子句停止重复插入

示例:插入bookseriesbook\u id,series\u id选择100,如果不存在,则选择1000从book\u id=100和series\u id=1000的bookseries中选择1

有谁能告诉我为什么这不能像我预期的那样工作,或者是否有解决办法

先谢谢你


PS:我知道参数化SQL的使用、SQL注入、字典以及直接在服务器上执行原始SQL的缺点等,所以请不要质疑我为什么不在这个实例中使用它们。上面的例子只是为了让事情简单化,并解释我试图实现的目标。我的问题纯粹是关于为什么notexists子句不停止代码中的重复插入

最简单的解决方案是对book\u id、series\u id设置唯一的约束,因为它们构成链接表的自然复合键。然后,在执行插入并继续处理时,只需处理唯一约束错误号2601或2627


我不清楚为什么您当前的代码不能按预期工作。是否有两个用户试图同时上载重复记录?如果是这样,我猜事务范围是错误的,您应该在每次插入后提交,而不是在处理所有记录后提交。

也许您的WHERE子句SELECT SQL返回Null

那么:

... WHERE ((SELECT Count(*) FROM bookseries WHERE book_id=100 AND series_id=1000) = 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

取决于提交查询的时间。在您的情况下,我建议您将所有ID插入一个数组中,一次推送临时表中的所有项,然后执行一个查询,将临时表中所有不重复的行复制到实际表中。事务的边界在哪里?你有吗?谢谢你的评论,@the_lotus和@sstan。我没有边界,只是执行插入..的查询。。;插入。。。;插入。。。;一次过。@Sathish在提交查询之前,插入的值将不可供其他事务查看。这是一个问题、注释还是一个答案?是的,这是一个问题、注释和一个可能的答案。我添加了WHERE语法。