Таблица SQL Server только одна активная запись в данный момент - PullRequest
0 голосов
/ 11 октября 2019

У меня есть таблица SQL Server 2016, в которой в любой момент времени должна быть активна только одна запись. Там будут операции CRUD к нему.

Я пытаюсь создать уникальный некластеризованный индекс для этой таблицы, чтобы она имела только 1 активную запись в любое время. Критерии для активной записи: если сегодняшняя дата находится между StartDate и StopDate. 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

Ответы [ 2 ]

0 голосов
/ 12 октября 2019

Я думаю, вам нужно более четко определить, что вам нужно в первую очередь. Например, у вас есть запись с установленным активным битом, StartDate сегодня 0:00:00, StopDate сегодня 23:59:59, все в порядке.

До 23:59:59, когда ваше условие (активный бит должен быть установлен только тогда, когда GetDate () находится между StartDate и StopDate) больше недействительно. Как вы думаете, что должно произойти в эту секунду? Этот бит магически преобразован в 0, просто сам по себе?

Еще один вопрос, должны ли ваши требования разрешить для записей значение Active, равное 0, даже если условие выполнено? Если ответ на этот вопрос «нет», то ваш активный бит - это не отдельное поле, а просто [недетерминированная] функция StartDate и StopDate, и ваша единственная задача - не допускать перекрывающихся интервалов.

0 голосов
/ 12 октября 2019

Из контекста кажется, что вы пытаетесь ограничить вставку или обновление записи, которая содержит диапазон дат, который не относится к текущей дате. Для этого вы можете использовать триггер. Если диапазон дат не соответствует вашим критериям активности, вы можете вызвать ошибку и предотвратить вставку или обновление.

Я также только что попытался создать проверочное ограничение, и это также работает:

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 конфликтует сПРОВЕРЬТЕ ограничение "CK_test". Конфликт произошел в базе данных «SysproSupport», таблица «dbo.test». Утверждение было прекращено.

В конечном счете, похоже, что вы должны иметь возможность контролировать типы записей, которыми вы манипулируете с помощью своего внешнего интерфейса. Если у вас есть приложение или интерфейс ввода данных, который управляет вашими данными, вы можете наложить эти ограничения на него. Реализация этого в качестве ограничения или триггера гарантирует, что даже администратор не сможет очистить данные, не отключив их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...