如何强制SQL Server每3分钟只允许一次记录插入

时间:2016-02-12 00:12:59

标签: sql sql-server

我正在使用SQL Server,我需要一种方法来强制我的数据库只允许在3分钟内插入某个记录。

例如,如果我插入电话号码为3053333333的记录,我需要一种方法在3分钟后再强制输入同一电话号码。

我需要在数据库级别执行此操作。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

不完全是你要求的,但它应该是一个足够好的近似值。 这种方法的好处是它易于实现和高效。无需触发器。

使用此表达式向表中添加int列,该列将使用默认值自动填充:

datediff(minute,'2001-01-01',getdate())/(3)

此表达式计算自某个参考日期(2001-01-01)以来经过了多少分钟(除以3)。

然后在PhoneNumber和此PhoneTimestamp列上添加唯一索引。

CREATE TABLE [dbo].[TestTable](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [PhoneNumber] [varchar](50) NOT NULL,
    [PhoneTimestamp] [int] NOT NULL CONSTRAINT [DF_TestTable_PhoneTimestamp]  
    DEFAULT (datediff(minute,'2001-01-01',getdate())/(3)),
CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
))
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_PhoneNumber] ON [dbo].[TestTable]
(
    [PhoneNumber] ASC,
    [PhoneTimestamp] ASC
)
GO

在不明确设置PhoneTimestamp的情况下向表中插入值,让默认表达式起作用:

INSERT INTO [dbo].[TestTable] ([PhoneNumber]) VALUES
('124');

第一个INSERT可以正常工作,但如果您尝试在相同的3分钟“广告位”内再次运行它,则会失败并显示以下消息:

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.TestTable' with unique index 
'IX_PhoneNumber'. The duplicate key value is (124, 2649888).
The statement has been terminated.

这是近似值,因为您可以插入两行不到3分钟。如果插入了第一行,例如10:02:58,第二行插入10:03:02,则会被接受。但是,如果您在10:03:02处插入一行,则只有在10:06:00之后才会接受下一行。

答案 1 :(得分:1)

如果在过去三分钟内还没有记录,请插入。

DECLARE @ThreeMinutesAgo datetime2 = 
    DATEDIFF(minute, -3, getdate())

IF NOT EXISTS (
    SELECT * FROM PhoneRecords 
    WHERE PhoneNumber = @PhoneNumber 
    AND TimeStamp > @ThreeMinutesAgo)
  INSERT INTO PhoneRecords 
    (PhoneNumber, TimeStamp, MoreStuff) 
    VALUES 
    (@PhoneNumber, getdate(), @MoreStuff)

编辑,以解决下面弗拉基米尔的评论:

我使用带有PhoneNumber作为键的第二个表来跟踪最近的记录。

CREATE TABLE PhoneNumbers (
    PhoneNumber varchar(50) NOT NULL PRIMARY KEY,
    LastTimeStamp datetime2
)

PhoneNumber将是PhoneRecords表中的外键。要添加新记录:

DECLARE @Timestamp datetime2 = getdate()
DECLARE @ThreeMinutesAgo datetime2 = 
        DATEDIFF(minute, -3, @Timestamp)

UPDATE PhoneNumbers 
    SET LastTimeStamp = @TimeStamp
    WHERE PhoneNumber = @PhoneNumber AND LastTimeStamp < @ThreeMinutesAgo

仅在时间戳超过3分钟时才有效 - 请注意,如果另一个进程正在更新记录,我必须等待它解锁才能尝试更新。所以,如果我要进行更新,

IF @@ROWCOUNT = 1
    INSERT INTO PhoneRecords 
        (PhoneNumber, TimeStamp, MoreStuff) 
        VALUES 
        (@PhoneNumber, @Timestamp, @MoreStuff)

您希望将其放入交易中,并且还要检查是否需要在第一次在PhoneNumbers表中插入电话号码。

答案 2 :(得分:0)

在插入时在记录上存储时间戳。

在每次插入时,检查当前时间与同一手机的最后一个时间戳是否至少为3分钟。

如果您通过存储过程进行插入,请在那里执行检查。否则,您必须在触发器中执行此操作