База данных: как отличить отношения "один или более" и "нуль или больше"?

Инструменты проектирования позволяют различать "один TO нуль или более" и "один TO один или более". Я мог представить, как реализовать отношение "один к нулю или больше":


CHILD_TABLE

(pk) chid_id
(fk) parent_id (требуется)


PARENT_TABLE

(pk) parent_id


Как реализовать отношения "один или один"? Как сказать, что родитель требует хотя бы одного ребенка? Или " один или более" обычно реализуется как " ноль или более"?

Ответ 1

Реализация отношения 1 к 1 или более выполняется через бизнес-логику или, по крайней мере, с использованием транзакции. Вы не можете вставлять их в обе таблицы одновременно; вы вставляете в одну таблицу за раз. Поэтому вам необходимо вставить родительский элемент, прежде чем вы сможете вставить его, и нет встроенного способа для базы данных для обеспечения требуемой логики.

Если вы переносите два оператора INSERT внутри транзакции, тогда вы гарантируете, что если дочерняя вставка завершится с ошибкой, родительская вставка будет отброшена. Тем не менее, деловая логика заключается в том, чтобы убедиться, что родительский элемент не вставлен без дочернего элемента.

Ответ 2

Очевидно, что принудительные ограничения, такие как указанные вами, потребуют, чтобы клиенты иногда выдавали (и механизмы СУБД), чтобы они могли быть помечены как "одновременные обновления", то есть более чем одна отдельная таблица обновляется до любой проверки ограничений.

Язык SQL (я имею в виду, стандарт) предлагает поддержку для этого через CREATE ASSERTION. Увы, ни один из существующих двигателей не поддерживает это утверждение.

Единственный способ, который может быть достигнут с существующими в настоящее время механизмами SQL, заключается в том, чтобы отложить проверку ограничений до тех пор, пока все обновления не будут выполнены (если ваш движок поддерживает это, конечно). Обеспечение таких ограничений в коде приложения или бизнес-логике в конечном итоге сводится к тому, что в первую очередь не имеет ограничения, если ваша база данных "разделена" и также может быть обновлена ​​другими программами.

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

Решение aioobe довольно оригинально, но имейте в виду, что вы можете сделать это, дублируя все столбцы "много" (/дочерней) стороны на "одну" (/родительскую) сторону (поскольку в противном случае у вас все еще есть одна и та же проблема между двумя таблицами, за исключением того, что часть "или больше" ушла, но это не то, где проблема). И если вы сделаете это, вы столкнетесь с большими трудностями, когда:

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

Таким образом, решение aioobe, хотя и оригинальное, скорее всего, создаст новые проблемы, чем оно решает.

Ответ 3

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

Ответ 4

Вы можете реализовать его как "один к одному" плюс "один-к-ноль или больше"

Ответ 5

Лучший способ, который я знаю, - сделать все вставки через сохраненный процесс, который имеет транзакцию и rollsback родительскую вставку, если ребенок терпит неудачу.

Другой способ, который я видел (но это действительно что-то вроде взлома), состоит в том, чтобы сделать все поля в дочернем элементе, кроме автогенерированного Идентификатора и FK, но затем вставить запись только с идентификатором из триггера в родительской таблице, Затем для дочерней таблицы выполняется обновление для добавления данных для других полей. Это допустимо, если они должны быть обнуляемыми или если у вас могут не быть никаких данных во время ввода данных для дочерней таблицы, но они могут создавать проблемы с данными, если поля не должны быть пустыми.

Ответ 6

Язык SQL имеет очень ограниченную поддержку ограничений ссылочной целостности и целостности в целом. Стандартный SQL (и большинство, если не все популярные СУБД SQL) не поддерживает ограничения одного или более. Ограничения SQL FOREIGN KEY всегда являются необязательными на ссылочной стороне отношения. Инструменты и языки моделирования данных обычно поддерживают такие ограничения (ORM, ERD), но СУБД редко позволяют реализовать их.