如何解决带有时间窗口的sql唯一约束
我有一个表格,其中记录有一个(开始、结束)存在时间窗口(例如雇佣期限、出生和死亡、租金期限等)
如果没有界限,则开始IS NULL或结束IS NULL。
CREATE TABLE mytable(
id int primary key,value int,--UNIQUE at any point in time
begin datetime NULL,end datetime NULL
);
我希望列值在任何时间点都是唯一的。
INSERT INTO mytable VALUES(1,1,'2021-07-23','2021-07-24'),(2,'2021-07-25',NULL);
没问题
然而
INSERT INTO mytable VALUES(1,'2021-07-30'),NULL);
不行,因为两个记录都有 value=1 和重叠的时间窗口。
有没有办法在 sql 中强制执行这样的约束?
解决方法
你不能在桌子上做这个,不,因为没有什么可以制作UNIQUE
。
但是,您可以做的是使用 VIEW
来强制执行。
首先,让我们创建您的表。我假设列 datetime
,实际上应该是 begin
和 end
;我建议不要使用这些名称,因为它们是保留关键字。因此,我称它们为 DateBegin
和 DateEnd
。我还假设它们只是日期(无时间部分)值,因此将它们定义为 date
而不是 datetime
:
CREATE TABLE dbo.mytable(ID int primary key,Value int,[BeginDate] date NULL,[EndEnd] date NULL);
我们将INSERT
您的前两行,因为它们“正常”:
INSERT INTO dbo.mytable (ID,Value,BeginDate,EndDate)
VALUES(1,1,'20210723','20210724'),(2,'20210725',NULL);
现在我们需要创建一个 VIEW
,但我们每个日期需要一行。因此,您需要创建一个日历表。我不打算在这里介绍如何创建一个,但实际上有 100 多篇文章,例如 SQL Server Central 上的文章:Bones of SQL - The Calendar Table、Calendar Tables in T-SQL。
拥有日历表后,您可以创建下面的 VIEW
,它将表中的数据JOIN
转换为日历表。我们将使其VIEW
只返回列value
和日期。我们还将对其进行模式绑定;这意味着我们将能够向其添加 UNIQUE INDEX
:
CREATE VIEW dbo.MyView
WITH SCHEMABINDING
AS
SELECT MT.[Value],CT.CalendarDate
FROM dbo.MyTable MT
JOIN dbo.CalendarTable CT ON MT.BeginDate <= CT.CalendarDate --I assume,despite your schema,MT.BeginDate can't be NULL
AND (MT.EndDate >= CT.CalendarDate OR MT.EndDate IS NULL);
现在我们有一个 VIEW
,每个日期和每个值都有一行。这意味着我们现在可以创建我们的 UNIQUE INDEX
:
CREATE UNIQUE CLUSTERED INDEX MyIndex ON dbo.MyView ([Value],CalendarDate);
现在,如果我们尝试 INSERT
具有相同日期和值的行,我们会得到一个错误:
INSERT INTO dbo.MyTable (ID,EndDate)
VALUES(3,'20210720','20210723');
无法在具有唯一索引“MyIndex”的对象“dbo.MyView”中插入重复的键行。重复的键值为 (1,2021-07-23)。
,Trigger 会帮助你,例如像这样:
CREATE TRIGGER mytable__tr_iu ON mytable
FOR INSERT,UPDATE
AS
IF EXISTS(
SELECT 1
FROM mytable t
JOIN inserted i ON t.id <> i.id AND t.value = i.value AND
(t.BeginDate IS NULL OR i.EndDate IS NULL OR t.BeginDate <= i.EndDate) AND
(t.EndDate IS NULL OR i.BeginDate IS NULL OR t.EndDate >= i.BeginDate)
)
THROW 51200,'Date range error for value',10
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。