Идентификаторы в ромбовидной связи между таблицами
-
21-08-2019 - |
Вопрос
У меня есть четыре таблицы (A,B,C,D), где A является родительским элементом отношений «один ко многим» с B и C.C и D являются родительскими элементами связи один-ко-многим с таблицей D.Концептуально первичными ключами этих таблиц могут быть:
- А:Помогать
- Б:Помощь, bnum (с внешним ключом к A)
- С:Помощь, cnum (с внешним ключом к A)
- Д:Aid, bnum, cnum (с внешними ключами для B и C)
Где столбцы «num» автоматически увеличиваются на основе каждого родительского идентификатора в отношениях, а не на каждой записи.Я использовал этот подход в предыдущем приложении, и это не было проблемой, поскольку создание записей B и C выполнялось последовательным процессом путем создания нового значения «num» с помощью запроса «select max()».Я никогда не был по-настоящему удовлетворен этим подходом, но он выполнил свою работу.
В конкретном случае, над которым я сейчас работаю, записи в таблицах A и B вводятся пользователями, поэтому автоматическое создание идентификаторов не является проблемой.В случае таблиц C и D записи в этих таблицах генерируются несколькими параллельными пакетными процессами, поэтому их идентификаторы необходимо каким-то образом сгенерировать.Предыдущий метод, который я перечислил, не будет работать в условиях гонки.
Обратите внимание, что это касается базы данных Oracle, поэтому я буду использовать последовательности, а не столбцы с автоматическим приращением.
Учитывая вышеизложенные ограничения, как бы вы разработали таблицы для представления A, B, C и D, чтобы отношения между сущностями были правильно реализованы, И коду приложения не требовалось бы генерировать какие-либо идентификаторы?
Решение
Если я правильно понимаю, у вас было решение, в котором вы могли
Table A
-------
100
101
102
Table B
-------
100 1
100 2
101 1
Table C
-------
100 1
100 2
101 1
Table D
-------
100 1 1
100 2 1
100 1 2
101 1 1
и т. д.
Итак, имеет ли значение, малы ли значения «num» и расположены ли они в последовательности без пробелов?Если нет, то просто используйте последовательности и для них.Таким образом, вы можете получить
Table B
-------
100 29125
100 29138
101 29130
Table D
-------
100 29125 401907
100 29138 404911
101 29130 803888
Я бы использовал отдельные последовательности для bnum и cnum.При выборе вы можете (при желании) использовать что-то вроде
SELECT AID,
RANK(BNUM) OVER (PARTITION BY AID ORDER BY BNUM) bnum_seq,
RANK(CNUM) OVER (PARTITION BY AID ORDER BY CNUM) cnum_seq
Другие советы
Последовательности или автонумерации всегда должны генерироваться системой базы данных, а не приложением.Для MSSQL это можно сделать с помощью хранимой процедуры и возврата «select @@identity» из хранимой процедуры, чтобы передать приложению идентификатор вставленной строки.
Последовательности отлично подходят для первичных ключей, но есть лагеря, которые поклоняются богу «естественных ключей».
Значение данных, хранящихся в таблице, и значение отношений важны для полного ответа на ваш вопрос, но отношения могут допускать каскадное удаление.
Лично я бы создал последовательности первичных ключей в каждой таблице и позволил бы использовать внешние ключи, которые не являются частью первичного ключа.Вы определите свои таблицы по основным объектам (например, сотрудник, товар, магазин), а затем отношения между ними будут состоять из комбинаций. Таким образом, у сотрудника в магазине будет таблица «storeemployee», а первичный ключ будет empid. , storeid без определенной последовательности.Обычно я думаю об этом с точки зрения объектов (которые всегда имеют последовательности для первичных ключей) и отношений между объектами (с использованием идентификаторов других таблиц в качестве комбинированных первичных ключей).
Надеюсь, это поможет!
Редактировать:Я должен добавить, что это прекрасно допускает ромбовидные отношения.Подумайте о «магазинах» и «сотрудниках».Одна таблица может быть «сотрудники магазина», а другая — «продажи в магазине».Оба идентифицируют магазин и сотрудника, но они означают совершенно разные вещи.Один — это, возможно, отработанные часы, а другой — объем продаж.