У меня есть три таблицы:
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
Вам нужно либо указать адреса от Клиента/Поставщика (если у них есть только один), либо два разных столбца.
Причина, которую вы видите в этом 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);
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.
Подход, который вы пытаетесь, (а) невозможен и (б) нежелателен, даже если это возможно.
Наилучшим подходом является наличие таблицы 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 клиентов и поставщиков.