Каков наилучший способ представления ограниченных отношений «многие ко многим» в реляционной базе данных? - PullRequest
1 голос
/ 31 июля 2011

Я хотел бы установить отношение «многие ко многим» с ограничением, согласно которому только один или ни один объект с каждой стороны отношения может быть связан одновременно.

Хорошая аналогия проблемыесть автомобили и парковочные места в гараже.Здесь много машин и много мест.Пространство может содержать одну машину или быть пустым;автомобиль может находиться только в одном месте за раз или без места (не припаркован).

У нас есть таблица автомобилей и таблица пробелов (и, возможно, таблица ссылок).Каждая строка в таблице автомобилей представляет уникальный экземпляр автомобиля (с лицензией, владельцем, моделью и т. Д.), А каждая строка в таблице «Пространства» представляет уникальное парковочное место (с адресом уровня этажа гаража, строки и номера).Как лучше всего связать эти таблицы в базе данных и применить ограничение, описанное выше?

(я использую C #, NHibernate и Oracle.)

Ответы [ 3 ]

2 голосов
/ 31 июля 2011

Если вы не беспокоитесь об истории, то есть беспокоитесь только о «сейчас», сделайте следующее:

create table parking (
  car_id references car,
  space_id references space,
  unique car_id,
  unique space_id
);

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

1 голос
/ 05 декабря 2011

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

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

Итак, ваши таблицы данных могут выглядеть так:

таблица car car_id (целые числа / числа быстрее всего индексировать) ...

таблица парковочного места space_id location

таблица временного интервала time_id integer begin_datetime (не используйте секунды, если вы не обязаны!) End_time (не используйте секунды, если вы не обязаны!)

сейчас, вот где это весело.Вы добавляете среднюю таблицу с составным первичным ключом, который состоит из car.car_id + parking_space.space_id + time_id.Есть и другие вещи, которые вы могли бы добавить, чтобы оптимизировать их здесь, но вы поняли идею, я надеюсь.

резервирование таблицы car_id PK parking_space_id PK time_id PK (это целое число - просто старайтесь сохранять его как можно более детализированным - 30-минутные приращения или что-то в этом роде - если вы разрешите включить секунды / миллисекунды / и т. Д., Преимущества заключаются в том, чтоотменили, потому что вы не можете повторно использовать то же значение из таблицы времени) (это также место для хранения переменных ставок, скидок и т. д., отличных от этой конкретной учетной записи, бронирования и т. д.).

Теперь вы можете уменьшить объем данных, потому что вы не реплицируете метку времени в таблице соединений (резервирование).Используя целое число, вы можете повторно использовать этот временной интервал для нескольких парковочных мест, но вы также можете применить ограничение, не позволяющее двум автомобилям арендовать указанное место для одного и того же «временного интервала» для данного дня / периода.Это также облегчило бы сохранение некоторой истории о клиентах - кто знает, возможно, вы захотите увидеть отчеты о клиентах, которые арендуют чаще и предлагают им скидки или что-то в этом роде.

Используя модель троичных отношений, вы делаете каждое место уникальным для данного временного интервала (возможно, с некоторыми добавленными правилами проверки), поэтому система может хранить только один автомобиль на одном месте для парковки в течение одного заданного периода времени.

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

0 голосов
/ 31 июля 2011

создайте третью таблицу.

parking
--------
car_id
space_id
start_dt
end_dt

для ограничения, я полагаю, проблема вашей ситуации в том, что вам нужно проверить сложное правило по самой таблице пересечений.если вы попробуете это в триггере, он сообщит о мутации.

Один из способов избежать этого - репликация таблицы и запрос этой репликации для ограничения.

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