【问题标题】:SQL Server table only one Active Record at a given timeSQL Server 在给定时间仅表一个 Active Record
【发布时间】:2020-02-09 09:22:06
【问题描述】:

我有一个 SQL Server 2016 表,其中在任何给定时间都应该只有一条记录处于活动状态。将对它进行 CRUD 操作。

我正在尝试在该表上创建一个唯一的非聚集索引,以便它在任何时候都只有 1 条活动记录。活动记录的标准是今天的日期是否在StartDateStopDate 之间。 ID 是唯一键。其余的,我不确定我的语法和策略是否正确。

这是我的 SQL:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[GWFO_FlashNewsItem]
(
    [ID] [INT] IDENTITY(1,1) NOT NULL,
    [Title] [VARCHAR](150) NOT NULL,
    [NavigateToURL] [VARCHAR](250) NULL,
    [StartDate] [SMALLDATETIME] NOT NULL,
    [StopDate] [SMALLDATETIME] NULL,
    [Active] [BIT] NOT Null,
    [UpdateSOEID] [CHAR](7) NULL,
    [UpdateDate] [SMALLDATETIME] NULL,

    CONSTRAINT [PK_GWFO_FlashNewsItem] 
        PRIMARY KEY CLUSTERED ([ID] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE UNIQUE NONCLUSTERED INDEX uixf_GWFO_FlashNews_Active_filtered
ON GWFO_FlashNewsItem (Active)
INCLUDE (ID, Title) 
WHERE Active = 1

【问题讨论】:

  • 我非常有信心您不能根据当前日期创建过滤索引。 (我无法检查,但这没有任何意义,因为索引中的行会永远改变)。
  • @Larnu,这是正确的,仅限确定性子句。
  • 您可以提出其他解决方案吗?例如,添加另一个位列“活动”并在插入/更新操作期间相应地设置它。并对其应用索引?
  • 为什么要将 smalldatetime 转换为字符串进行比较?除了这不起作用,因为你正在尝试这是浪费精力。只需比较 smalldatetime 值。对于手头的任务,为什么需要过滤索引?只需使用排序逻辑创建一个顶部 1 的视图。
  • 触发器将允许您在每次更新表时检查所需的任何条件。

标签: sql-server non-clustered-index


【解决方案1】:

从上下文看来,您似乎试图限制插入或更新包含不在当前日期的日期范围的记录。为此,您可以使用触发器。如果日期范围不符合您的活动条件,您可以引发错误并阻止插入或更新发生。

我也刚刚尝试创建一个检查约束,并且效果也很好:

CREATE TABLE [dbo].[test]
(
    [d1] [DATETIME] NULL,
    [d2] [DATETIME] NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[test] WITH CHECK 
    ADD CONSTRAINT [CK_test] CHECK ((GETDATE() >= [d1] AND GETDATE() <= [d2]))
GO

ALTER TABLE [dbo].[test] CHECK CONSTRAINT [CK_test]
GO

这段代码:

INSERT INTO test SELECT '1/1/2000', '1/1/2001'

抛出此错误:

消息 547,第 16 级,状态 0,第 24 行
INSERT 语句与 CHECK 约束“CK_test”冲突。冲突发生在数据库“SysproSupport”、表“dbo.test”中。声明已终止。

最终,您似乎应该能够控制您使用前端处理的记录类型。如果您有一个正在处理数据的应用程序或数据输入接口,您可以将这些约束放入其中。将此作为约束或触发器实施将确保即使是管理员也无法在不禁用数据的情况下清理数据。

【讨论】:

  • 会试一试您的建议
【解决方案2】:

我认为您需要先更清楚地确定您需要什么。例如,您有一条设置了 Active 位的记录,StartDate 是今天 0:00:00,StopDate 是今天 23:59:59,一切都很好。

直到 23:59:59,您的条件(只有在 GetDate() 介于 StartDate 和 StopDate 之间时才应设置活动位)不再有效。你认为那一秒应该发生什么?那位神奇地转换为 0,就凭它自己?

另一个问题,即使满足条件,您的要求是否应该允许记录将 Active 设置为 0?如果这个问题的答案是“否”,那么您的活动位不是单独的字段,而只是 StartDate 和 StopDate 的 [非确定性] 函数,您唯一关心的是不允许重叠间隔。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2013-01-11
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多