Дизайн таблиц для трех связанных объектов

#database #database-design

#База данных #проектирование базы данных

Вопрос:

Сценарий такой, как показано ниже:

        n   ownership    1
stocks <-------------------- users

      n    belong to         n
users -----------------------> sectors 

       n    having            1
stocks <---------------------- sectors
  

В моем дизайне для них используется таблица 6: T_Stocks, T_Users, T_Sectors, T_UserStocks, T_UserSectors, T_SectorStocks, но я не думаю, что это хороший дизайн. Если у вас есть какие-либо идеи по этому поводу, пожалуйста, помогите поделиться ими со мной.

Комментарии:

1. если пользователь принадлежит к сектору, может ли пользователь владеть запасом, которого нет в секторе?

2. нет, пользователь владеет запасами только с одним сектором.

Ответ №1:

Вы правы, это не очень хороший дизайн. (Извините! :P) Поскольку у каждого stock есть только один user владелец, вы можете просто поместить ownerId столбец в свою stocks таблицу. Дайте ему ограничение внешнего ключа и не забудьте указать на него индекс!! Аналогично, у каждого sector есть только один user , поэтому у вас также может быть userId столбец в sectors . (Но мне это кажется обратным; вы намеревались установить эти отношения наоборот ??)

Однако на этом этапе ввод sectorId в stocks нарушает нормализацию, потому что вы могли бы создать запас, пользователь которого не совпадает с пользователем его сектора. Если вас не волнует нормализация, вы можете просто молиться, чтобы у вас никогда не получилось напортачить. С другой стороны, поскольку комбинация двух вторых взаимосвязей подразумевает первую, вы могли бы просто отбросить userId столбец на stocks и иметь только sectorId .

Комментарии:

1. Спасибо за идею, Пол. Прошу прощения за ошибку в моем вопросе, я просто изменил отношение между пользователями и секторами на n: n.

Ответ №2:

Если пользователи могут владеть запасами только в секторах, в которых они участвуют, то, возможно, пересечение секторов с пользователями (n: m) на самом деле не обязательно. Может ли пользователь находиться в секторе, но не владеть запасами в этом секторе? Если пользователь находится в секторе исключительно благодаря владению акциями в этом секторе, то ваша модель немного проще. Что-то вроде этого:

 SECTOR
  sector_id
, name_of_sector
, ... (anything else about sectors)

STOCK
  stock_id
, name_of_stock
, ... (whatever that pertains to the stock as a whole)
, sector_id     -- What sector is this stock in?

STOCK_CERTIFICATE
  stock_certificate_id
, stock_id        -- Which stock is it?
, quantity        -- number of shares, etc.
, user_id  NULL   -- who owns this stock, could be nobody?

USER
  user_id
, user_name
, ... (anything else about the user)
  

Теперь, если вы хотите узнать, кому сколько принадлежит акций, вы просто посмотрите в таблицу STOCK_CERTIFICATE. Если вы хотите узнать, в каких секторах находится пользователь, вы бы использовали запрос, подобный этому:

 SELECT DISTINCT
  A.sector_id
, A.name_of_sector
FROM SECTOR A 
  INNER JOIN STOCK B 
    ON A.sector_id = B.sector_id
  INNER JOIN STOCK_CERTIFICATE C
    ON B.stock_id = C.stock_certificate_id
WHERE
  C.user_id = {whatever your user ID is}
  

Вы также можете выполнить аналогичный distinct select в другом направлении, если хотите знать, какие пользователи находятся в данном секторе.

РЕДАКТИРОВАТЬ: Учет пользователей играет определенную РОЛЬ в секторах, к которым они принадлежат…

Если пользователи участвуют в секторах, имея роль в секторе (согласно комментарию @OP), тогда вам необходимо иметь таблицу пересечений между ПОЛЬЗОВАТЕЛЕМ и СЕКТОРОМ следующим образом…

 USER_ROLE_IN_SECTOR
  user_id    (PK, FK)
, sector_id  (PK, FK)
, role_id    (PK, might be FK if you also have a ROLE table...)
  

Это предполагает, что пользователи могут иметь одну или несколько ролей в любом заданном секторе. Если пользователь может иметь не более одной роли в любом заданном секторе, вам придется включить уникальное ограничение на user_id sector_id. Если только один пользователь может иметь определенную роль в любом заданном секторе, тогда вам потребуется уникальное ограничение для sector_id role_id .

Эта новая таблица учитывает тот факт, что пользователи могут участвовать в секторах, фактически не владея никакими акциями в данном секторе. Другие таблицы, предложенные изначально, выше, по-прежнему являются лучшим способом записи того, кто какими акциями владеет и какие акции принадлежат каким секторам. Эта модель находится в третьей нормальной форме, поэтому нет избыточности как таковой, даже несмотря на то, что user_id и sector_id повторяются в таблице USER_ROLE_IN_SECTOR.

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

Комментарии:

1. спасибо за твою идею, Джоэл! Но у пользователя есть роль в секторе, в вашем дизайне RoleId и SectorID будут повторяться много раз. Может быть сложно поддерживать согласованность.