Работа с циклической ссылкой при вводе данных в SQL - PullRequest
8 голосов
/ 05 июня 2009

Какие уловки SQL вы используете для ввода данных в две таблицы с циклической ссылкой между ними.

Employees
    EmployeeID <PK>
    DepartmentID <FK> NOT NULL

Departments
    DepartmentID <PK>
    EmployeeID <FK> NOT NULL

Сотрудник принадлежит к отделу, в отделе должен быть менеджер (начальник отдела).

Нужно ли отключать ограничения для вставки?

Ответы [ 9 ]

13 голосов
/ 05 июня 2009

Полагаю, ваш Departments.EmployeeID является начальником отдела. Что бы я сделал, это сделал бы этот столбец обнуляемым; затем вы можете сначала создать отдел, а затем сотрудника.

5 голосов
/ 05 июня 2009

Q: Нужно ли отключать ограничения для вставки?
A: В Oracle нет, нет, если ограничения внешнего ключа DEFERRABLE (см. Пример ниже)

Для Oracle:

    SET CONSTRAINTS ALL DEFERRED;
    INSERT INTO Departments values ('foo','dummy');
    INSERT INTO Employees values ('bar','foo');
    UPDATE Departments SET EmployeeID = 'bar' WHERE DepartmentID = 'foo';
    COMMIT;

Давайте распакуем это:

  • (автокоммит должен быть выключен)
  • отсрочить применение ограничения внешнего ключа
  • вставить строку в таблицу Department с помощью фиктивного значения для столбца FK
  • вставить строку в таблицу Employee с указанием FK для Отдела
  • заменить "фиктивное" значение в отделе ФК на реальную ссылку
  • повторно включить применение ограничений

ПРИМЕЧАНИЯ: отключение ограничения внешнего ключа вступает в силу для ВСЕХ сеансов, ОТСУТСТВУЯ ограничение на уровне транзакции (как в примере) или на уровне сеанса (ALTER SESSION SET CONSTRAINTS=DEFERRED;)

Oracle допускает, чтобы ограничения внешнего ключа определялись как DEFERRABLE, по крайней мере, в течение десятилетия. Я определяю все ограничения внешнего ключа (как само собой разумеющееся) как ЗАДЕРЖАЕМЫЕ ПЕРВОНАЧАЛЬНО НЕМЕДЛЕННЫЕ. Это сохраняет поведение по умолчанию, как все ожидают, но позволяет манипулировать, не требуя отключения внешних ключей.

см. AskTom: http://www.oracle.com/technology/oramag/oracle/03-nov/o63asktom.html

см. AskTom: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:10954765239682

см. Также: http://www.idevelopment.info/data/Oracle/DBA_tips/Database_Administration/DBA_12.shtml

[РЕДАКТИРОВАТЬ]

A: В Microsoft SQL Server вы не можете отложить ограничения внешнего ключа, как в Oracle. Отключение и повторное включение ограничения внешнего ключа является подходом, но я вздрагиваю от перспективы 1) влияния на производительность (ограничение внешнего ключа проверяется для таблицы ENTIRE при повторном включении ограничения), 2) обработка исключения, если (когда?) повторное включение ограничения не выполняется. Обратите внимание, что отключение ограничения повлияет на все сеансы, поэтому, пока ограничение отключено, другие сеансы могут потенциально вставлять и обновлять строки, что приведет к сбою повторного включения ограничения.

В SQL Server лучшим подходом является удаление ограничения NOT NULL и использование NULL в качестве временного заполнителя при вставке / обновлении строк.

Для SQL Server:

    -- (with NOT NULL constraint removed from Departments.EmployeeID)
    insert into Departments values ('foo',NULL)
    go
    insert into Employees values ('bar','foo')
    go
    update Departments set EmployeeID = 'bar' where DepartmentID = 'foo'
    go

[/ EDIT]

3 голосов
/ 05 июня 2009

Эта проблема может быть решена с помощью уязвимых ограничений. Такие ограничения проверяются при фиксации всей транзакции, что позволяет вам вставить сотрудника и отдел в одну транзакцию, ссылаясь друг на друга (Предполагая, что модель данных имеет смысл)

1 голос
/ 05 июня 2009

Я использовал несколько хороших дизайнов. Все это включает удаление EmployeeID «manager» из таблицы Department и удаление DepartmentID из таблицы Employee. Я видел пару ответов, в которых упоминается об этом, но я поясню, как мы его использовали:

Я обычно получаю таблицу связей взаимоотношений EmployeeDepartment - многие ко многим, обычно с флагами, такими как IsManager, IsPrimaryManager, IsAdmin, IsBackupManager и т. Д., Которые проясняют взаимосвязь. Некоторые из них могут быть ограничены, так что для каждого Разрешенного главного администратора разрешено отдел (хотя человек может быть PrimaryManager из нескольких отделов). Если вам не нравится одна таблица, то вы можете иметь несколько таблиц: EmployeeDepartment, ManagerDepartment и т. Д., Но тогда могут возникнуть ситуации, когда человек является менеджером, а не сотрудником и т. Д.

Мы также, как правило, позволяли людям входить в несколько отделов.

Для упрощенного доступа вы можете предоставить представления, которые выполняют соединение соответствующим образом.

1 голос
/ 05 июня 2009

Вы можете создать строку в таблице Department для 'Unassigned'

Чтобы создать новый отдел с новым сотрудником, вы бы

  1. Создать сотрудника (EmployeeA) в отделе «Неназначенные»
  2. Создать новый отдел (DepartmentA) с сотрудником EmployeeA
  3. Обновите EmployeeA, чтобы быть в DepartmentA

Это не сделает вашу текущую схему недействительной, и вы могли бы настроить задачу, которая будет запускаться регулярно, чтобы проверить, нет ли членов неназначенного отдела.

Вам также необходимо создать сотрудника по умолчанию, который будет Сотрудником неназначенного

EDIT:

Решение, предложенное хаосом, намного проще, хотя

1 голос
/ 05 июня 2009

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

Я бы рекомендовал рефакторинг схемы БД. Я не могу придумать никаких причин, почему вы хотели бы, чтобы это работало таким образом.

Может быть, что-то вроде Employee, EmployeeDepartment (EmployeeId, DepartmentId) и Department будет лучшим способом для достижения той же цели.

1 голос
/ 05 июня 2009

Выполните рефакторинг схемы, удалив циклическую ссылку.
Удалить столбец идентификатора из любой схемы таблицы.

Departments.EmployeeID , по-моему, там не место.

0 голосов
/ 05 июня 2009

Вам нужно навсегда избавиться от одной или другой ссылки. Это не жизнеспособная структура дизайна. Что должно быть введено первым? Отдел или сотрудник? Если все ваши отделы не имеют одного сотрудника, структура в любом случае не имеет смысла, так как каждый сотрудник должен иметь отдельный отдел.

0 голосов
/ 05 июня 2009

Да, в этом случае вам придется отключить внешний ключ.

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