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

У нас есть несколько офисов, и в каждом офисе есть несколько отделов (некоторые отделы имеют сотрудников в нескольких офисах). У нас есть две существующие системы, которые идентифицируют сотрудников по-разному: в одной сотрудники идентифицируются IDA; в остальных сотрудники идентифицированы ИБР.

В тех случаях, когда сотрудник идентифицируется IDA, нам необходимо указать руководителя этого сотрудника, если таковой имеется, в SUPERVISOR_IDA.

Моя таблица выглядит так:

IDA
IDB
SUPERVISOR_IDA
OFFICE
DEPARTMENT

Сотрудники могут иметь должности более чем в одном офисе или более чем в одном отделе, поэтому один и тот же IDA или IDB может существовать более одного раза, но с другим офисом, отделом или и тем, и другим.

Проблема в том, что IDA может быть нулевым (и если это так, то IDB не является нулевым) или IDB может быть нулевым (и если это так, то IDA не является нулевым), или оба могут присутствовать.

Я пытаюсь настроить уникальные и/или первичные ключи и ограничения, чтобы обеспечить целостность базы данных.

Поэтому я создал уникальный ключ на (IDA, IDB, OFFICE, DEPARTMENT).

Вот моя проблема:

Мне нужно убедиться, что сотрудники ссылаются на своих руководителей. Я хотел иметь самоссылающийся внешний ключ, чтобы удаление супервизоров не оставляло потерянных записей о сотрудниках, имеющих ненулевой SUPERVISOR_IDA. Но поскольку мне нужно было включить IDB в свой уникальный ключ в этой таблице, если я создам этот внешний ключ, мне нужно будет включить IDB как таковой:

local PARENT_IDA -> reference IDA
local OFFICE -> reference OFFICE
local DEPARTMENT -> reference DEPARTMENT
**local IDB -> reference IDB**

Это проблема, поскольку IDB сотрудника НЕ ​​ДОЛЖЕН совпадать с IDB супервизора.

Я знаю, что кажется, что я пытаюсь сделать слишком много вещей в одной таблице, но на самом деле мою область довольно сложно описать, и поэтому я создал сотрудника/офис/отдел в качестве примера, чтобы проиллюстрировать свои проблемы. Я действительно не могу разделить IDA и IDB на отдельные таблицы, так как они переплетаются некоторыми проблематичными способами, и наличие одного, другого или обоих имеет какое-то важное значение, которое невозможно разделить.

Сначала я хотел настроить уникальный ключ (IDA, OFFICE, DEPARTMENT) в дополнение к вышеупомянутому уникальному ключу, но в отличие от уникальных ключей, состоящих из одного столбца, составные уникальные ключи будут обрабатывать (null, 'A') и (null, 'A') как дубликаты вместо того, чтобы разрешить нулевой столбец, чтобы избежать нарушения ограничения уникальности.


person aw crud    schedule 28.01.2010    source источник


Ответы (3)


Думаю проблема в модели. Таблица должна иметь первичный ключ (и если IDA или IDB могут быть нулевыми, то они не являются столбцами PK), а внешний ключ должен ссылаться на PK.

Я думаю, вы пытаетесь использовать FK для уникального индекса, чтобы обеспечить выполнение набора правил проверки между строками в модели данных, таких как «сотрудник может контролироваться только кем-то в том же офисе и отделе» и «IDA работника может контролировать только другой сотрудник IDA».

На практике их очень сложно реализовать, если учесть, что несколько человек могут одновременно обновлять разные столбцы в разных строках.

Тем не менее, вы можете попробовать добавить столбцы DEPT_IDA и OFFICE_IDA и использовать триггеры для их установки из DEPT и OFFICE только тогда, когда установлен IDA. Затем создайте Великобританию в этих столбцах.

person Gary Myers    schedule 29.01.2010

Я думаю, что ваша модель данных неверна. У вас должна быть только одна запись EMPLOYEE для каждого сотрудника. Затем вы можете иметь ключи unique для каждого из IDA и IDB.

Поскольку сотрудники работают в нескольких офисах, вам нужна таблица для представления этого; POSTS будет таблицей пересечения между OFFICES и EMPLOYEES.

Дело в том, что SUPERVISOR_IDA и SUPERVISOR_IDB являются свойствами POSTS, и поэтому вы можете установить внешний ключ между этими столбцами и таблицей EMPLOYEES. Используйте проверочные ограничения, чтобы гарантировать, что если запись POSTS идентифицируется EMPLOYEE_IDA, заполняется SUPERVISOR_IDA, и то же самое для EMPLOYEE_IDB.

person APC    schedule 29.01.2010

Я не уверен, работает ли это в Oracle, но в SQL Server я бы создал триггер для таблицы SUPERVISORS, который срабатывает при UPDATE и DELETE. Триггер запросит в таблице EMPLOYEES любые записи, в которых SUPERVISORS.SUPERVISOR_IDA = EMPLOYEES.SUPERVISOR_IDA. Если какие-либо записи будут найдены, транзакция откатится.

Я нашел, что эта ссылка описывает, что вам нужно сделать.

http://www.techonthenet.com/oracle/triggers/before_delete.php

person mvonlintel    schedule 28.01.2010
comment
Использование триггеров для обеспечения реляционной целостности не является хорошей идеей. Он плохо масштабируется и ломается в многопользовательской среде (поскольку Oracle разрешает транзакции только с уровнем изоляции READ COMMITTED. - person APC; 29.01.2010