Скажем, у меня есть таблица с первичным ключом a_id
и внешним ключом b_id
.
Важно, чтобы a_id
и b_id
никогда не пересекались, т.е. никогда не должно быть случая a_id = b_id
.
Каким будет лучший способ реализовать это? Могу ли я каким-то образом сделать это в конце базы данных (mySql), или это должно быть обеспечено программным путем? Если я гарантирую это программно, неуместно ли вставлять номер для первичного ключа (вместо того, чтобы иметь автоинкремент базы данных)? Я предполагаю, что я просто создаю процедуру, которая проверяет последний первичный ключ и просто увеличивает его (и мне также нужно будет убедиться, что диапазон a_id
никогда не пересекает диапазон b_id
). Любые предложения?
Вы можете создать другую таблицу с полем автоматического увеличения. После вставки записи она будет вставляться в эту "таблицу ключей" и использовать там ссылочные значения. Поэтому, если у вас есть два уникальных в глобальном масштабе ключей в одной таблице, каждая вставка будет представлять собой две ключевые вставки. Это решение будет масштабироваться и дальше 2.
Но я должен спросить: почему?
В Oracle вы можете реализовать это поведение, используя sequence
, который использовался для присвоения id строкам в обеих таблицах. Каждая таблица будет иметь триггер на INSERT
, где идентификатор будет установлен из следующего числа в последовательности.
Вы можете установить значение AUTO_INCREMENT
таким образом, чтобы одна таблица имела только нечетные числа, а другая - только.
Это, вероятно, будет очень результативным, но это не оставляет места для добавления третьей таблицы с еще одним уникальным ключом.
Я не уверен на 100% в отношении MySQL, но с Oracle вы можете определить последовательность, а затем просто используйте эту же последовательность для выбора всех своих значений, что, вероятно, является лучшим вариантом (если он доступен с помощью mysql).
b_id
является родительским идентификатором и ссылается на a_id
качестве своего надмножества.
Вы можете использовать GUID (UUID) как уникальные ключи.
Я использовал это в нескольких проектах, и он отлично работает для уникальности, хотя он не лучший для производительности индекса.
Самый простой способ добиться этого - использовать ограничение CHECK
. К сожалению, MySQL является MySQL, он не поддерживает CHECK
.
Чтобы добиться такого же эффекта в MySQL, вам нужно создать триггер BEFORE INSERT
и BEFORE UPDATE
, чтобы убедиться, что оба значения действительны. Сам FK отвечает за то, чтобы убедиться, что отношения действительны. Вот пример:
CREATE TRIGGER upd_check BEFORE UPDATE ON sometable
FOR EACH ROW
BEGIN
IF NEW.a_id = NEW.b_id THEN
call ERROR_SELFREFERENCING_ID();
END IF;
END;
Дополнительная информация о MySQL TRIGGERS доступна в руководстве по MySQL:
EDIT: MySQL в настоящее время не поддерживает RAISE
или SIGNAL
в своих триггерах, поэтому мне приходится прибегать к вызову несуществующей процедуры ERROR_SELFREFERENCING_ID()
для отказа. Это приведет к сбою INSERT
или UPDATE
, если a_id = b_id
, почти таким же образом, если вы установите недопустимый b_id
.