防止插入时出现重复行 [英] Preventing Duplicate Rows on Insert

查看:89
本文介绍了防止插入时出现重复行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表使用标识列作为其主键和两个

列(为简单而减少表)EmployeeNumber和ArrivalTime。


CREATE TABLE [tblRecords](

[ID] [bigint] IDENTITY(1,1)NOT NULL,

[EmployeeNumber] [varchar](10)COLLATE SQL_Latin1_General_CP1_CI_AS

NOT NULL,

[ArrivalTime] [datetime] NOT NULL,

CONSTRAINT [PK_tblRecords] PRIMARY KEY CLUSTERED



[ID]

)ON [PRIMARY]

)ON [PRIMARY]

GO


我有一个插入程序,在插入之前检查重复项

a新记录:


IF(SELECT TOP 1 [ID] FROM tblRecords WHERE EmployeeNumber =

@SocialSecurity)IS NULL

BEGIN

INSERT INTO tblRecords(EmployeeNumber,ArrivalTime)

VALUES (@EmployeeNumber,@ ArrivalTime)

SELECT SCOPE_IDENTITY()

END

ELSE

SELECT 0 AS DuplicateRecord


在99.9%的情况下,这很有效。但是,如果

插入尝试的字面意思是滴答。除此之外,SELECT TOP 1 ...

命令在第一次尝试完成之前完成两次尝试。

所以如果程序我最终会有重复的条目被称为多次

倍迅速。系统需要在过去45天内防止重复

EmployeeNumbers,因此将EmployeeNumber

设置为UNIQUE将不起作用。我可以很容易地查看较旧的条目(45天或

更新),但我不知道如何处理在毫秒内多次调用

过程的时间。在这种情况下使用ROLLBACK

进行INSERT后,是否会带有重复检查的

TRANSACTION?非常感谢任何帮助!


-E

I have a table using an identity column as its Primary Key and two
columns (table reduced for simplicity) EmployeeNumber and ArrivalTime.

CREATE TABLE [tblRecords] (
[ID] [bigint] IDENTITY (1, 1) NOT NULL ,
[EmployeeNumber] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS
NOT NULL ,
[ArrivalTime] [datetime] NOT NULL ,
CONSTRAINT [PK_tblRecords] PRIMARY KEY CLUSTERED
(
[ID]
) ON [PRIMARY]
) ON [PRIMARY]
GO

I have an insert procedure that checks for duplicates before inserting
a new record:

IF (SELECT TOP 1 [ID] FROM tblRecords WHERE EmployeeNumber =
@SocialSecurity) IS NULL
BEGIN
INSERT INTO tblRecords(EmployeeNumber,ArrivalTime)
VALUES (@EmployeeNumber, @ArrivalTime)
SELECT SCOPE_IDENTITY()
END
ELSE
SELECT 0 AS DuplicateRecord

In 99.9% of the cases, this works well. However, in the event that the
insert attempts are literally "ticks" apart, the "SELECT TOP 1..."
command completes on both attempts before the first attempt completes.
So I end up with duplicate entries if the procedure is called multiple
times vey quickly. The system needs to prevent duplicate
EmployeeNumbers within the past 45 days so setting the EmployeeNumber
to UNIQUE would not work. I can check for older entries (45 days or
newer) very easily, but I do not know how to handle the times when the
procedure is called multiple times within milliseconds. Would a
TRANSACTION with a duplicate check after the INSERT with a ROLLBACK
work in this case? Any help is greatly appreciated!

-E

推荐答案

试试这个:


INSERT INTO tblRecords(employeenumber,arrivaltime)

SELECT @eloyloyumber,@ arrivaltime

WHERE NOT EXISTS

(SELECT *

FROM tblRecords

WHERE employeenumber = @eloyloyumber

AND arrivaltime> = DATEADD(DAY,-45,@ arrivaltime) );


发布时你的桌面设计有缺陷,因为它没有替代密钥。

IDENTITY永远不应该是桌子的唯一键。


-

David Portas

SQL Server MVP

-
Try this:

INSERT INTO tblRecords (employeenumber,arrivaltime)
SELECT @employeenumber, @arrivaltime
WHERE NOT EXISTS
(SELECT *
FROM tblRecords
WHERE employeenumber = @employeenumber
AND arrivaltime >= DATEADD(DAY,-45,@arrivaltime)) ;

As posted your table design is flawed because it has no alternate keys.
IDENTITY should never be the only key of a table.

--
David Portas
SQL Server MVP
--


更好的解决方案可能是使用触发器。


首先,添加最重要的UNIQUE约束:


ALTER TABLE tblRecords ADD CONSTRAINT ak_employees UNIQUE

(employeenumber,arrivaltime)


现在这里是一个触发器,将强制执行你的UPDATE业务规则为

以及INSERT:


CREATE TRIGGER trg_employee ON tblRecords FOR UPDATE,INSERT

AS

如果有EXISTS

(选择T1.employeenumber

FROM插入AS T1

加入tblrecords AS T2

ON T1.employeenumber = T2.employeenumber

AND T1.arrivaltime<> T2.arrivaltime

AND T2.arrivaltime< = DATEADD(DAY,45,T1.arrivaltime)

AND T2.arrivaltime> = DATEADD(DAY,-45, T1.arrivaltime))

BEGIN

ROLLBACK TRAN

RAISERROR(''员工人数在45天内重复',16,1)< br $>
结束


GO


-

David Portas

SQL Server MVP

-
A better solution is probably to use a trigger.

First, add the all-important UNIQUE constraint:

ALTER TABLE tblRecords ADD CONSTRAINT ak_employees UNIQUE
(employeenumber,arrivaltime)

Now here''s a trigger which will enforce your business rule for UPDATEs as
well as INSERTs:

CREATE TRIGGER trg_employee ON tblRecords FOR UPDATE, INSERT
AS
IF EXISTS
(SELECT T1.employeenumber
FROM inserted AS T1
JOIN tblrecords AS T2
ON T1.employeenumber = T2.employeenumber
AND T1.arrivaltime <> T2.arrivaltime
AND T2.arrivaltime <= DATEADD(DAY,45,T1.arrivaltime)
AND T2.arrivaltime >= DATEADD(DAY,-45,T1.arrivaltime))
BEGIN
ROLLBACK TRAN
RAISERROR(''Employee number repeated within 45 days'',16,1)
END

GO

--
David Portas
SQL Server MVP
--


David Portas(RE *************** *************@acm.org)写道:
David Portas (RE****************************@acm.org) writes:
试试这个:

INSERT INTO tblRecords(employeenumber,arrivaltime)
SELECT @eloyloyumber,@ arrivaltime
不存在
(SELECT *
FROM tblRecords
WHERE employeenumber = @eloyloyumber
AND arrivaltime> = DATEADD(DAY, - 45,@ arrivaltime));
Try this:

INSERT INTO tblRecords (employeenumber,arrivaltime)
SELECT @employeenumber, @arrivaltime
WHERE NOT EXISTS
(SELECT *
FROM tblRecords
WHERE employeenumber = @employeenumber
AND arrivaltime >= DATEADD(DAY,-45,@arrivaltime)) ;




这里需要可序列化的隔离级别。我认为SELECT语句中的UPDLOCK

是最好的。 (使用普通HOLDLOCK你可以

陷入僵局。)


至于触发器是否最好......你不必失眠结束

并发插入,但如果出现错误,你可以做更多工作(INSERT +

ROLLBACK)。是否需要错误消息我们不知道。再说一遍,

你可以同时拥有两者。强制执行业务规则的触发器,以及

应用程序代码,以提供良好的行为。


-

Erland Sommarskog ,SQL Server MVP, es****@sommarskog.se


联机丛书适用于SQL Server SP3
http:/ /www.microsoft.com/sql/techinf...2000/books.asp


这篇关于防止插入时出现重复行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆