Каков наилучший способ гарантировать, что первичный ключ и внешний ключ никогда не пересекаются?

0

Скажем, у меня есть таблица с первичным ключом a_id и внешним ключом b_id.

Важно, чтобы a_id и b_id никогда не пересекались, т.е. никогда не должно быть случая a_id = b_id.

Каким будет лучший способ реализовать это? Могу ли я каким-то образом сделать это в конце базы данных (mySql), или это должно быть обеспечено программным путем? Если я гарантирую это программно, неуместно ли вставлять номер для первичного ключа (вместо того, чтобы иметь автоинкремент базы данных)? Я предполагаю, что я просто создаю процедуру, которая проверяет последний первичный ключ и просто увеличивает его (и мне также нужно будет убедиться, что диапазон a_id никогда не пересекает диапазон b_id). Любые предложения?

  • 0
    Обычно внешний ключ должен соответствовать соответствующему первичному ключу; пересечение A и B должно равняться B (хотя могут быть записи в A без соответствующей записи в B). Итак, что вы подразумеваете под первичными и внешними ключами, не пересекающимися? Почему?
Теги:
database-design
primary-key

5 ответов

2
Лучший ответ

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

Но я должен спросить: почему?

  • 0
    По сути, идея заключалась в том, что каждый ключ представляет некоторый общий идентификатор объекта, который я в конечном итоге отображаю на странице. Я хотел, чтобы идентификаторы javascript в целом идентифицировали элементы по идентификатору объекта (что не сработало бы, если a_id и b_id пересекаются). Думаю, я мог бы просто перепроектировать это во внешнем интерфейсе, если слишком много хлопот, чтобы сделать это на сторона дб
  • 0
    Итак, вместо второго уникального столбца, почему бы не иметь другой столбец, такой как Object_Type? Далее вы можете сгенерировать GUID и использовать его.
Показать ещё 2 комментария
1

В Oracle вы можете реализовать это поведение, используя sequence, который использовался для присвоения id строкам в обеих таблицах. Каждая таблица будет иметь триггер на INSERT, где идентификатор будет установлен из следующего числа в последовательности.

1

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

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

Я не уверен на 100% в отношении MySQL, но с Oracle вы можете определить последовательность, а затем просто используйте эту же последовательность для выбора всех своих значений, что, вероятно, является лучшим вариантом (если он доступен с помощью mysql).

  • 0
    Это не будет работать, если b_id является родительским идентификатором и ссылается на a_id качестве своего надмножества.
  • 0
    Возможно, я неправильно прочитал вопрос, но я не увидел ничего, в котором говорилось бы, что он хочет, чтобы b_id был подмножеством a_id. Если это так, то вы правы. Однако этот же недостаток существует, если они используют последовательность, как предлагается в некоторых других ответах.
0

Вы можете использовать GUID (UUID) как уникальные ключи.

Я использовал это в нескольких проектах, и он отлично работает для уникальности, хотя он не лучший для производительности индекса.

0

Самый простой способ добиться этого - использовать ограничение 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:

18.3.1: Синтаксис триггера

EDIT: MySQL в настоящее время не поддерживает RAISE или SIGNAL в своих триггерах, поэтому мне приходится прибегать к вызову несуществующей процедуры ERROR_SELFREFERENCING_ID() для отказа. Это приведет к сбою INSERT или UPDATE, если a_id = b_id, почти таким же образом, если вы установите недопустимый b_id.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню