【问题标题】:sql unique constraint with time window带有时间窗口的sql唯一约束
【发布时间】:2021-09-30 16:52:22
【问题描述】:

我有一个表,其中记录有一个(开始、结束)存在时间窗口(例如就业时间、出生和死亡、租金持续时间……)

begin IS NULL 或 end 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, 1, '2021-07-25', NULL);

没问题

INSERT INTO mytable VALUES(1, 1, '2021-07-23', '2021-07-30'),(2, 1, '2021-07-25', NULL);

不行,因为两条记录的 value=1 和重叠的时间窗口。

有没有办法在 SQL 中强制执行这样的约束?

【问题讨论】:

    标签: sql sql-server unique-constraint referential-integrity


    【解决方案1】:

    你不能在桌子上这样做,不,因为没有什么可以让UNIQUE 开启。 但是,您可以做的是使用 VIEW 来强制执行它。

    首先,让我们创建您的表格。我假设列datetime,实际上应该是beginend;我建议不要使用这些名称,因为它们是保留关键字。因此,我称他们为DateBeginDateEnd。我还假设它们只是日期(没有时间部分)值,因此将它们定义为 date 而不是 datetime

    CREATE TABLE dbo.mytable(ID int primary key,
                             Value int, 
                             [BeginDate] date NULL,
                             [EndEnd] date NULL);
    

    我们将INSERT您的前 2 行,因为它们“正常”:

    INSERT INTO dbo.mytable (ID, Value, BeginDate, EndDate)
    VALUES(1, 1, '20210723', '20210724'),
          (2, 1, '20210725', NULL);
    

    现在我们需要创建一个VIEW,但我们需要每个日期一行。因此,您需要创建一个日历表。我不打算在这里介绍如何创建一篇文章,但实际上有 100 篇文章,例如 SQL Server Central 上的文章:Bones of SQL - The Calendar TableCalendar 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, Value, BeginDate, EndDate)
    VALUES(3, 1, '20210720', '20210723');
    

    无法在具有唯一索引“MyIndex”的对象“dbo.MyView”中插入重复的键行。重复键值为 (1, 2021-07-23)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多