Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何强制SQL Server每3分钟只允许插入一条记录_Sql_Sql Server - Fatal编程技术网

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

如何强制SQL Server每3分钟只允许插入一条记录,sql,sql-server,Sql,Sql Server,我正在使用SQL Server,我需要一种方法来强制我的数据库在3分钟内只允许插入一条特定记录 例如,如果我插入一条电话号码为305333333的记录,我需要一种方法来强制在3分钟后再输入相同的电话号码 我需要在数据库级别执行此操作。任何帮助都将不胜感激。插入时在记录上存储时间戳 每次插入时,检查同一电话号码的当前时间与最后时间戳是否至少为3分钟 如果要通过存储过程进行插入,请在此处执行检查。否则,您将不得不在触发器中执行此操作不完全是您要求的,但它应该是一个足够好的近似值。 这种方法的优点是易

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

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


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

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

每次插入时,检查同一电话号码的当前时间与最后时间戳是否至少为3分钟


如果要通过存储过程进行插入,请在此处执行检查。否则,您将不得不在触发器中执行此操作

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

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');
第一次插入将正常工作,但如果您尝试在相同的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
之后才能接受下一行,如果在最后三分钟内没有记录,只需插入即可

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

你想把它放在交易中,还要检查是否需要在第一次在PhoneNumber表中插入电话号码。

您不能限制插入的方式吗?首先想到的是一个insert而不是insert触发器。为什么需要在数据库级别?在数据库抽象级别很容易做到。我想使用存储使用where子句来处理插入,并检查where子句中的条件,但这不会100%准确,因为如果两个插入请求的执行时间相差微秒,会发生什么情况,可能在我检查第二个插入请求时,第一个插入请求尚未完成,那么,也许两个都完成了插入。当多次尝试同时插入相同的值时,如何使其100%可靠地工作?我指的是OP在对问题的评论中所写的担忧。在上面添加了一个编辑来解决这个问题@VladimirBaranov@VladimirBaranov:我喜欢你的方法,结果非常简洁:TRY--do insert--CATCH--do nothing。我的问题是,我尽量不对预期条件使用
CATCH
。是否有任何性能方面的考虑?如果这种情况发生的并不罕见,但可能大部分都失败了,那该怎么办?我想知道与先检查一个有效的外键相比,尝试插入一个坏的外键是否会有性能损失。这可能取决于与有效记录相比,您尝试添加不需要的记录的频率。我的答案是使用内置数据库机制声明所需的约束,而不是性能。你的方法也是有效的。我最近看到了亚伦·伯特兰的帖子,看看吧。不过,您应该为您的环境进行自己的测试。
IF @@ROWCOUNT = 1
    INSERT INTO PhoneRecords 
        (PhoneNumber, TimeStamp, MoreStuff) 
        VALUES 
        (@PhoneNumber, @Timestamp, @MoreStuff)