Как создать ограничение таблицы для предотвращения дублирования значений в двух столбцах?

StackOverflow https://stackoverflow.com/questions/626609

  •  06-07-2019
  •  | 
  •  

Вопрос

У меня есть следующая таблица:

CREATE TABLE [dbo].[EntityAttributeRelship](
    [IdNmb] [int] IDENTITY(1,1) NOT NULL,
    [EntityIdNmb] [int] NOT NULL,
    [AttributeIdNmb] [int] NOT NULL,
    [IsActive] [bit] NOT NULL CONSTRAINT [DF_EntityAttributeRelship_IsActive]  DEFAULT ((0)),
CONSTRAINT [PK_EntityAttributeRelship] PRIMARY KEY CLUSTERED 
([IdNmb] ASC) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]

Часть данных в таблице выглядит примерно так:

IdNmb    EntityIdNmb    AttributeIdNmb  IsActive
1        22             7               0
2        22             8               0
3        22             9               0
4        22             10              1

Я хочу добавить ограничение, чтобы убедиться, что никто не добавляет и не обновляет запись с IsActive = 1, если запись EntityIdNmb уже существует, где IsActive = 1.

Как мне это сделать?

Это было полезно?

Решение

Если вы используете SQLServer, вы можете создать кластерное индексированное представление.

CREATE VIEW dbo.VIEW_EntityAttributeRelship WITH SCHEMABINDING AS
SELECT EntityIdNmb 
FROM dbo.EntityAttributeRelship
WHERE IsActive = 1
GO

CREATE UNIQUE CLUSTERED INDEX UIX_VIEW_ENTITYATTRIBUTERELSHIP 
  ON dbo.VIEW_EntityAttributeRelship (EntityIdNmb)

Это гарантирует, что в вашей таблице есть только один EntityIdNmb с IsActive = 1.

Другие советы

Похоже, вам нужно реализовать триггер (при условии, что ваш продукт db поддерживает его). Если вам нужна только одна активная и одна неактивная запись, будет работать уникальный индекс. В противном случае вам нужно написать какое-то пользовательское ограничение или триггер (вероятно, 2 - один для вставок, один для обновлений), который гарантирует, что у вас нет 2 записей с одинаковым идентификатором, где обе активны.

Если вы используете MSSQL (я думаю, именно так выглядит ваш синтаксис), создайте представление, включающее только строки с IsActive = 1, затем добавьте уникальный индекс EntityIdNmb в представление.

В PostgreSQL, с которым я больше работал в последнее время, вы можете создать частичный индекс: http://www.postgresql.org/docs/8.3/interactive/ индексы-partial.html

При написании триггера нужно решить, хотите ли вы отклонить запись, изменить значение на 0 вместо единицы или обновить старую запись на ноль и оставить эту единицу равной единице. Если вы удаляете запись со значением 1, нужно ли изменить другую запись на активную, как выбрать какую? Как только вы сможете определить, что вы хотите сделать в триггере, мы можем помочь вам лучше спроектировать процесс.

Мы делаем последние два шага, чтобы сделать любой адрес основным почтовым адресом в нашей базе данных. Нашим бизнес-правилом является один и только один адрес может быть основным, и если есть какие-либо адреса, он должен быть помечен как основной. Ключ к такому типу триггера заключается в том, чтобы помнить, что вставки / обновления / удаления могут происходить в пакетах (даже если это не норма), и чтобы убедиться, что триггер работает на основе набора. Когда я попал сюда, у нас была реализована многострочная обработка с помощью курсора, что стало плохо, когда мне пришлось обновить 200 000 адресов при импорте. (Примечание для неопытных - никогда не используйте курсор в триггере!)

Для чего будут использоваться неактивные записи? Они не используются и просто существуют, чтобы отслеживать ранее активные записи? Если это так, можно ли разбить данные на несколько таблиц? Что-то вроде ...

EntityAttributeRelship (IDNmb, EntityIDNmb, AttributeIDNmb)

EntityAttributeRelshipHistory (IDNmb, EntityIDNmb, AttributeIDNmb)

Если он находится в таблице EntityAttributeRelship, он активен. Если он находится в таблице истории, то он был активирован в какой-то момент и с тех пор был деактивирован?

Если вам нужно все в одной таблице, я бы согласился с предложением todd.run использовать триггер.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top