Ограничения уникальности в MS Access

В базе данных, которую мне нужно разработать для MS Access, у меня есть таблица под названием «Измерения», в которой хранятся определенные параметры измерения (измеренные значения, стандартное отклонение и т. д.) — каждая строка имеет целочисленный идентификатор в качестве первичного ключа.

Затем другие таблицы связываются с этой таблицей измерений, используя отношения внешнего ключа. Некоторые таблицы содержат два разных поля «measurementID», которые оба ссылаются на эту одну таблицу измерений. Однако каждое измерение должно быть связано только с одним из этих полей.

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


person Smashery    schedule 08.04.2009    source источник
comment
Вы намекаете на «подклассы» или, скорее, на «распределенные внешние ключи» (погуглите эти термины, если они вам незнакомы).   -  person onedaywhen    schedule 09.04.2009


Ответы (5)


Такие ограничения действительно могут быть реализованы в ACE/JET с использованием CHECK ограничений.

Человек, который сказал, что обычно использует триггеры для подобных вещей, не знает о разнице между ограничениями CHECK в ACE/Jet и SQL Server соответственно: в SQL Server они не могут включать подзапросы, то есть они не могут ссылаться на значения в других строки в той же таблице или в другие таблицы, тогда как в ACE/Jet это возможно.

В идеальном (но пока еще несуществующем) продукте SQL-92 описанная уникальность будет реализована с использованием ASSETION на уровне схемы. Поскольку ограничения CHECK находятся на уровне таблицы и проверяются только в том случае, если таблица, в которой они определены, имеет значение UPDATEd или INSERTed, вам потребуется установить соответствующие ограничения CHECK для всех ссылающихся таблиц (то же самое применимо к триггерам SQL Server). Вот краткий пример:

CREATE TABLE Parent 
(
   parent_ID INTEGER NOT NULL IDENTITY UNIQUE, 
   data_col INTEGER NOT NULL
)
;
CREATE TABLE Child1
(
   parent_ID INTEGER NOT NULL
      REFERENCES parent (parent_ID), 
   data_col INTEGER NOT NULL
)
;
CREATE TABLE Child2
(
   parent_ID INTEGER NOT NULL
      REFERENCES parent (parent_ID), 
   data_col INTEGER NOT NULL
)
;
ALTER TABLE Child1 ADD
   CONSTRAINT child1__no_dups_in_child2
   CHECK (NOT EXISTS (
                      SELECT * 
                        FROM Child1 AS C1
                             INNER JOIN Child2 AS C2
                                ON C1.parent_ID = C2.parent_ID
                     ))
;
ALTER TABLE Child2 ADD
   CONSTRAINT child2__no_dups_in_child1
   CHECK (NOT EXISTS (
                      SELECT * 
                        FROM Child1 AS C1
                             INNER JOIN Child2 AS C2
                                ON C1.parent_ID = C2.parent_ID
                     ))
;

Однако мне интересно, есть ли у вас подклассы (т.е. каждая сущность, представленная идентификатором, может быть типизирована), и в этом случае вы должны иметь возможность использовать ограничения FOREIGN KEYs и CHECK на уровне строки (или правила проверки, если вам удобнее использовать Интерфейс MS Access, чем SQL DLL, который требуется для CHECK ограничений). Логику будет проще реализовать, чем CHECK ограничения на уровне таблицы, просто следите за циклами в CASCADE ссылочных действиях. Вот еще один простой пример:

CREATE TABLE Parent 
(
   parent_ID INTEGER NOT NULL IDENTITY, 
   child_type VARCHAR(4) NOT NULL, 
   CONSTRAINT child_type__values 
      CHECK (child_type IN ('Boy', 'Girl')), 
   UNIQUE (child_type, parent_ID)
)
;
CREATE TABLE Girls
(
   parent_ID INTEGER NOT NULL, 
   child_type VARCHAR(4) DEFAULT 'girl' NOT NULL, 
   CONSTRAINT girl_child_type__must_be_girl
      CHECK (child_type = 'girl'),
   FOREIGN KEY (child_type, parent_ID)
      REFERENCES Parent (child_type, parent_ID), 
   data_col INTEGER NOT NULL
)
;
CREATE TABLE Boys
(
   parent_ID INTEGER NOT NULL, 
   child_type VARCHAR(4) DEFAULT 'boy' NOT NULL, 
   CONSTRAINT boy_child_type__must_be_boy
      CHECK (child_type = 'boy'),
   FOREIGN KEY (child_type, parent_ID)
      REFERENCES Parent (child_type, parent_ID), 
   data_col INTEGER NOT NULL
)
;
person onedaywhen    schedule 09.04.2009

Движок Microsoft ACE/Jet не поддерживает триггеры, как вы обычно реализуете этот тип функциональности.

РЕДАКТИРОВАТЬ: Как указал @onedaywhen, JET 4.0 и выше поддерживает проверочные ограничения, но реализовать ограничение типа xor для двух столбцов непросто.

Если вы используете формы доступа, вы можете реализовать событие перед обновлением формы и проверить критерии ограничений.

person Mitch Wheat    schedule 09.04.2009
comment
Вы говорите, что Microsoft не поддерживает триггеры. Ну, Microsoft SQL Server поддерживает, так что, по-видимому, это опечатка, и вы хотели сказать, что механизм Microsoft ACE/Jet не поддерживает триггеры), что правильно. - person onedaywhen; 09.04.2009
comment
Лично я обычно использовал бы ограничения CHECK на уровне таблицы для реализации этого типа функций, если рассматриваемый продукт их поддерживал. К счастью, ACE/Jet их поддерживает. - person onedaywhen; 09.04.2009
comment
@onedaywhen: это была опечатка! Спасибо! - person Mitch Wheat; 09.04.2009
comment
Что ж, реализовать ограничение типа xor для двух таблиц в любом продукте SQL непросто. Хью Дарвен называет это распределенным внешним ключом (см. dcs.warwick.ac.uk/~hugh/TTM/Missing-info-without-nulls.pdf). - person onedaywhen; 09.04.2009
comment
@onedaywhen: хорошая ссылка (этот доклад был сделан в университете, который я закончил) - person Mitch Wheat; 09.04.2009

Митч прав насчет того, что возможно в Access. Однако, если предположить, что у вас где-то есть BL, это приближается к тому, что является законным бизнес-правилом. Это то, что я, скорее всего, сделал бы.

person dkretz    schedule 09.04.2009
comment
Что вы имеете в виду под БЛ? Бизнес-уровень? - person Smashery; 09.04.2009
comment
Ага. Другими словами, не выполняйте эту проверку в базе данных. - person dkretz; 09.04.2009
comment
Я не думаю, что Митч прав в том, что возможно в Access, потому что он не учел ограничения CHECK на уровне таблицы, вероятно, потому, что он использует SQL Server, в котором их нет, поэтому, как и мне, приходится прибегать к триггерам для реализации данных. ограничения (тьфу!) - person onedaywhen; 09.04.2009

Учитывая, что вы разрабатываете эту базу данных. Вы уверены, что структуры ваших таблиц соответствуют стандартным правилам нормализации.

Звучит необычно для строки в таблице A, чтобы иметь возможность ссылаться на две строки в таблице Measurements в зависимости от того, какое поле A.row вы просматриваете. У меня такое ощущение, что данные в таблице «Измерения» действительно нужно разделить на две или более таблиц.

person Community    schedule 09.04.2009

Я сам настороженно отношусь к триггерам и ограничениям проверки, в основном потому, что я разрабатывал большинство своих приложений без них (Access/Jet и MySQL/MyISAM). Я согласен с BobClegg, что это похоже на ситуацию супертипа/подтипа. В этом случае вы должны использовать таблицу соединений с уникальным индексом внешнего ключа и столбцом, указывающим тип измерения. Уникальный индекс FK предотвратит добавление второго типа. Это также означало бы, что в вашей основной записи не будет пустых полей. Конечно, одно пустое числовое поле не является проблемой хранения, но два исключительных поля всегда кажутся мне ошибкой дизайна.

person David-W-Fenton    schedule 09.04.2009