SQL 检查插入的数据周期
SQL check data period for insert
我有一个带日期时间的 table,我想检查是否有一些带日期时间的条目相对于插入值在 +-30 分钟内。所以我写了这个约束:
USE [Test]
GO
/****** Object: UserDefinedFunction [dbo].[CanInsertReception] Script Date: 23.09.2015 12:19:51 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[CanInsertReception] (@receptionBegin datetime)
RETURNS bit
AS
BEGIN
DECLARE @result bit;
IF EXISTS(SELECT * FROM Main
where DATEDIFF(MINUTE, ReceptionBegin, @receptionBegin) <= 30 or DATEDIFF(MINUTE, @receptionBegin, ReceptionBegin) <= 30)
SET @result = 0
ELSE
SET @result = 1
return @result;
END;
GO;
ALTER TABLE Main
ADD CONSTRAINT CheckIfCanInsertReception
CHECK (dbo.CanInsertReception(ReceptionBegin) = 1);
但是当我尝试插入任何数据时,这个检查不允许插入它,但是当我执行这个脚本时,它在做同样的事情:
DECLARE @receptionBegin datetime = '2015-01-01 09:00:00'
DECLARE @result bit;
IF EXISTS(SELECT * FROM Main
where DATEDIFF(MINUTE, ReceptionBegin, @receptionBegin) <= 30 or DATEDIFF(MINUTE, @receptionBegin, ReceptionBegin) <= 30)
SET @result = 0
ELSE
SET @result = 1
SELECT @result
我得到了预期的输出1
我做错了什么?
结果取决于 table 上的数据。
如果您的 table 为空,您似乎无法使用此约束在 table 中插入任何记录。
Main 的 table 上有多少行?
但无论如何最好使用
WHERE ReceptionBegin BETWEEN DATEADD (minute , -30 , @receptionBegin) AND DATEADD (minute , 30 , @receptionBegin)
它会工作得更快,即使您没有必要的索引。
使用触发器而不是检查约束可能是一个不错的选择!
如果创建了这样的测试table:
ReceptionId ReceptionText ReceptionBegin ReceptionEnd
1 A 2015-09-23 13:00 2015-09-23 13:45
2 B 2015-09-23 14:00 2015-09-23 14:45
3 C 2015-09-23 15:00 2015-09-23 15:45
4 D 2015-09-23 16:00 2015-09-23 16:45
触发器看起来像这样:
CREATE TRIGGER dbo.IO_IU_Test ON dbo.Test
INSTEAD OF INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @IsUpdate BIT = 0
DECLARE @ErrMessage NVARCHAR(255)
IF EXISTS (SELECT TOP 1 1 FROM deleted d)
SET @IsUpdate = 1
SET @ErrMessage = 'Value(s) can not be ' + IIF(@IsUpdate=1,'updated','inserted') + ' - there are existing Receptions which are less than 30 Minutes away!'
IF EXISTS(
SELECT TOP 1 1
FROM inserted i
INNER JOIN dbo.Test t ON
ABS(DATEDIFF(MINUTE,i.ReceptionBegin,t.ReceptionBegin)) <= 30
)
BEGIN
RAISERROR(@ErrMessage,16,1)
RETURN
END
IF @IsUpdate = 1
BEGIN
UPDATE t
SET t.ReceptionText = i.ReceptionText,
t.ReceptionBegin = i.ReceptionBegin,
t.ReceptionEnd = t.ReceptionEnd
FROM dbo.Test t
INNER JOIN inserted i ON t.ReceptionId = i.ReceptionId
END
ELSE
BEGIN
INSERT INTO dbo.Test(ReceptionText,ReceptionBegin,ReceptionEnd)
SELECT i.ReceptionText, i.ReceptionEnd, i.ReceptionEnd FROM inserted i
END
END
优点:
- 基于集合的操作
- 您可以提出自定义错误消息
- 可以通过使用 try-catch and/or 事务进行改进
测试:
INSERT INTO dbo.Test (ReceptionText, ReceptionBegin, ReceptionEnd)
VALUES ('E','2015-09-23 12:31','2015-09-23 12:36')
你得到一个错误:Value(s) can not be inserted - there are existing Receptions which are less than 30 Minutes away!
UPDATE dbo.Test SET ReceptionBegin = '2015-09-23 13:30'
WHERE ReceptionId = 1
你得到一个错误:Value(s) can not be updated - there are existing Receptions which are less than 30 Minutes away!
INSERT INTO dbo.Test (ReceptionText, ReceptionBegin, ReceptionEnd)
VALUES ('E','2015-09-23 10:00','2015-09-23 10:21')
这是有效的 -> 在 09:30 和 10:30
之间没有接收开始
我有一个带日期时间的 table,我想检查是否有一些带日期时间的条目相对于插入值在 +-30 分钟内。所以我写了这个约束:
USE [Test]
GO
/****** Object: UserDefinedFunction [dbo].[CanInsertReception] Script Date: 23.09.2015 12:19:51 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[CanInsertReception] (@receptionBegin datetime)
RETURNS bit
AS
BEGIN
DECLARE @result bit;
IF EXISTS(SELECT * FROM Main
where DATEDIFF(MINUTE, ReceptionBegin, @receptionBegin) <= 30 or DATEDIFF(MINUTE, @receptionBegin, ReceptionBegin) <= 30)
SET @result = 0
ELSE
SET @result = 1
return @result;
END;
GO;
ALTER TABLE Main
ADD CONSTRAINT CheckIfCanInsertReception
CHECK (dbo.CanInsertReception(ReceptionBegin) = 1);
但是当我尝试插入任何数据时,这个检查不允许插入它,但是当我执行这个脚本时,它在做同样的事情:
DECLARE @receptionBegin datetime = '2015-01-01 09:00:00'
DECLARE @result bit;
IF EXISTS(SELECT * FROM Main
where DATEDIFF(MINUTE, ReceptionBegin, @receptionBegin) <= 30 or DATEDIFF(MINUTE, @receptionBegin, ReceptionBegin) <= 30)
SET @result = 0
ELSE
SET @result = 1
SELECT @result
我得到了预期的输出1
我做错了什么?
结果取决于 table 上的数据。 如果您的 table 为空,您似乎无法使用此约束在 table 中插入任何记录。 Main 的 table 上有多少行? 但无论如何最好使用
WHERE ReceptionBegin BETWEEN DATEADD (minute , -30 , @receptionBegin) AND DATEADD (minute , 30 , @receptionBegin)
它会工作得更快,即使您没有必要的索引。
使用触发器而不是检查约束可能是一个不错的选择!
如果创建了这样的测试table:
ReceptionId ReceptionText ReceptionBegin ReceptionEnd
1 A 2015-09-23 13:00 2015-09-23 13:45
2 B 2015-09-23 14:00 2015-09-23 14:45
3 C 2015-09-23 15:00 2015-09-23 15:45
4 D 2015-09-23 16:00 2015-09-23 16:45
触发器看起来像这样:
CREATE TRIGGER dbo.IO_IU_Test ON dbo.Test
INSTEAD OF INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @IsUpdate BIT = 0
DECLARE @ErrMessage NVARCHAR(255)
IF EXISTS (SELECT TOP 1 1 FROM deleted d)
SET @IsUpdate = 1
SET @ErrMessage = 'Value(s) can not be ' + IIF(@IsUpdate=1,'updated','inserted') + ' - there are existing Receptions which are less than 30 Minutes away!'
IF EXISTS(
SELECT TOP 1 1
FROM inserted i
INNER JOIN dbo.Test t ON
ABS(DATEDIFF(MINUTE,i.ReceptionBegin,t.ReceptionBegin)) <= 30
)
BEGIN
RAISERROR(@ErrMessage,16,1)
RETURN
END
IF @IsUpdate = 1
BEGIN
UPDATE t
SET t.ReceptionText = i.ReceptionText,
t.ReceptionBegin = i.ReceptionBegin,
t.ReceptionEnd = t.ReceptionEnd
FROM dbo.Test t
INNER JOIN inserted i ON t.ReceptionId = i.ReceptionId
END
ELSE
BEGIN
INSERT INTO dbo.Test(ReceptionText,ReceptionBegin,ReceptionEnd)
SELECT i.ReceptionText, i.ReceptionEnd, i.ReceptionEnd FROM inserted i
END
END
优点:
- 基于集合的操作
- 您可以提出自定义错误消息
- 可以通过使用 try-catch and/or 事务进行改进
测试:
INSERT INTO dbo.Test (ReceptionText, ReceptionBegin, ReceptionEnd)
VALUES ('E','2015-09-23 12:31','2015-09-23 12:36')
你得到一个错误:Value(s) can not be inserted - there are existing Receptions which are less than 30 Minutes away!
UPDATE dbo.Test SET ReceptionBegin = '2015-09-23 13:30'
WHERE ReceptionId = 1
你得到一个错误:Value(s) can not be updated - there are existing Receptions which are less than 30 Minutes away!
INSERT INTO dbo.Test (ReceptionText, ReceptionBegin, ReceptionEnd)
VALUES ('E','2015-09-23 10:00','2015-09-23 10:21')
这是有效的 -> 在 09:30 和 10:30
之间没有接收开始