Одно поле с двумя ссылками в MySQL

0

У меня есть три таблицы:

CREATE TABLE Address (
  ResidentID CHAR(5) NOT NULL,
  Location varchar(255) NOT NULL,
  KEY ResidentID(ResidentID)
);

CREATE TABLE Customer (
  CustomerID CHAR(5) NOT NULL,
  ContactName varchar(40) NOT NULL,
  PRIMARY KEY (CustomerID)
);

CREATE TABLE Supplier (
  SupplierID CHAR(5) NOT NULL,
  SupplierName varchar(40) NOT NULL,
  PRIMARY KEY (SupplierID)
);

Я хочу сохранить CustomerID и ProviderID в поле Address.ResidentID с использованием внешних ключей:

ALTER TABLE Address ADD CONSTRAINT fk_CustomerID1 FOREIGN KEY(ResidentID) REFERENCES Customer(CustomerID);
ALTER TABLE Address ADD CONSTRAINT fk_SupplierID1 FOREIGN KEY(ResidentID) REFERENCES Supplier(SupplierID);

Но второй "ALTER TABLE" вызывает Ошибка: отношение уже существует

Любые предложения?

Пример данных:

CustomerID  ContactName
C0001       Den

SupplierID  ContactName
S0001       John

So Address table should contains:

ResidentID  Location
C0001       Alaska
S0001       Nevada
  • 1
    Я запустил это в моем местном, не получил никакой ошибки.
  • 0
    Просто чтобы прояснить, вы хотите, чтобы одна запись адреса ВСЕГДА имела соответствующие записи клиента и поставщика? Я думаю, что Клиент может иметь или не иметь адрес, а Клиент может быть, а может и не быть Поставщиком, что позволит вам связать как Адрес, так и Поставщика с Заказчиком; Адрес кажется странным местом, чтобы связать их обоих. Однако, если предполагается, что адрес связан с одним ИЛИ другим, для каждого должно быть добавлено другое поле.
Показать ещё 7 комментариев
Теги:
foreign-keys

2 ответа

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

Вам нужно либо указать адреса от Клиента/Поставщика (если у них есть только один), либо два разных столбца.

Причина, которую вы видите в этом SQLFiddle Вы не можете INSERT нужных столбцов в таблице Address, если ResidentID содержит ссылки на таблицы BOTH. Вы можете вставлять строки, которые бы соответствовали содержимому Customer AND Supplier, но вы хотите, чтобы соединение OR, которое вы не можете создать таким образом.

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

Или:

CREATE TABLE Address (
  AddressID CHAR(5) NOT NULL,
  Location varchar(255) NOT NULL,
  PRIMARY KEY (AddressID)
);

CREATE TABLE Customer (
  CustomerID CHAR(5) NOT NULL,
  AddressID CHAR(5),
  ContactName varchar(40) NOT NULL,
  PRIMARY KEY (CustomerID)
);

CREATE TABLE Supplier (
  SupplierID CHAR(5) NOT NULL,
  AddressID CHAR(5),
  SupplierName varchar(40) NOT NULL,
  PRIMARY KEY (SupplierID)
);

ALTER TABLE Customer ADD CONSTRAINT fk_AddressID_Cust FOREIGN KEY(AddressID) REFERENCES Address(AddressID);
ALTER TABLE Supplier ADD CONSTRAINT fk_AddressID_Supp FOREIGN KEY(AddressID) REFERENCES Address(AddressID);

или

CREATE TABLE Address (
  CustomerID CHAR(5),
  SupplierID CHAR(5),
  Location varchar(255) NOT NULL,
  PRIMARY KEY (CustomerID, SupplierID)
);

CREATE TABLE Customer (
  CustomerID CHAR(5) NOT NULL,
  ContactName varchar(40) NOT NULL,
  PRIMARY KEY (CustomerID)
);

CREATE TABLE Supplier (
  SupplierID CHAR(5) NOT NULL,
  SupplierName varchar(40) NOT NULL,
  PRIMARY KEY (SupplierID)
);

ALTER TABLE Address ADD CONSTRAINT fk_CustomerID1 FOREIGN KEY(CustomerID) REFERENCES Customer(CustomerID);
ALTER TABLE Address ADD CONSTRAINT fk_SupplierID1 FOREIGN KEY(SupplierId) REFERENCES Supplier(SupplierID);
  • 0
    +1 хороший совет, но я подозреваю, что это не является основной причиной вопроса ОП. Я думаю, что он использует два разных экземпляра RDBMS, один MySQL и один PostgreSQL, и он не знает, к какому из них он применяет изменения.
  • 0
    ПРИМЕЧАНИЕ: a) Поскольку столбцы FK 1-го решения не определены как NOT NULL , строка таблицы C / S не будет иметь строку таблицы A. b) Даже если бы они были сделаны как NOT NULL , это заставило бы каждую строку таблицы C / S иметь строку таблицы A, но не наоборот. c) Так как MySQL (и, между прочим, также SQL Server) заставляет PK-столбцы иметь NOT NULL , 2-е решение фактически будет реализовывать «И» (если не будут добавлены фиктивные строки таблиц C и S, которые по-прежнему будут принудительно заставлять каждую строку таблицы) есть C и S, но не наоборот). Я считаю, что OP хочет соединения «ИЛИ», а также отношения 1 к 1 между А и C «ИЛИ» S.
Показать ещё 4 комментария
-2

Подход, который вы пытаетесь, (а) невозможен и (б) нежелателен, даже если это возможно.

Наилучшим подходом является наличие таблицы CustomerAddress и таблицы SupplierAddress, каждая из которых имеет один FK для соответствующей базовой таблицы; или, если необходимо, таблицу перекрестных ссылок с соответствующими ограничениями.

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

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

Angelo Я немного пересмотрю это на основе вашего комментария ---

Angelo, я проверил ваш пример кода в локальном экземпляре MySQL (а не SQLFiddle) и заметил ошибку.

Я был удивлен (вы что-то узнали каждый день), что MySQL разрешил два ограничения внешнего ключа в одном поле; однако, когда вы пытаетесь вставить данные, при попытке указать FK в таблицу Customer, я получаю сообщение об ошибке, когда ограничение внешнего ключа не ссылается на таблицу Поставщика; и наоборот для вставки, пытаясь указать FK на таблицу Поставщика.

Итак, мой пересмотренный оператор: (a) можно создать гид-возглавляемую FK, по крайней мере, в некоторых СУБД, проверенных в MySQL, MS SQL Server и Oracle, хотя (b) это имеет смысл использовать только тогда, когда внешний ключ может ссылаться на один и тот же логический объект по идентификатору через несколько таблиц (например, чтобы обеспечить, например, соответствующую запись во всех необходимых таблицах); и (c) если используется для ссылки на несколько таблиц, где первичный ключ НЕ является одним и тем же логическим сущностью, работает только, если случайно одно и то же значение первичного ключа просто существует во всех ссылочных таблицах, что, вероятно, приведет к тонким, жестким ошибки поиска.

Другими словами, ваш пример будет работать при попытке вставить запись, относящуюся к идентификатору клиента = 3, только если был Идентификатор поставщика = 3, которые действительно логически не связаны.

Итак, мой слегка пересмотренный ответ OP - это то, что вы пытаетесь сделать, невозможно (или логично), когда внешний ключ ссылается на разные ENTITIES, как в примере OP клиентов и поставщиков.

  • 0
    Я согласен. Это возможно. Посмотрите: sqlfiddle.com/#!2/70e43/1/0
  • 0
    (Вы правы, что это нежелательно)
Показать ещё 2 комментария

Ещё вопросы

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