Возможный сделать внешний ключ MySQL к одной из двух возможных таблиц?

Если вы хотите использовать механизмы кэширования, например Redis или Memcached , возможно, выбор DALMP может быть выбран. Он использует чистый MySQLi . Проверьте это: Уровень абстракции базы данных DALMP для MySQL с использованием PHP.

Кроме того, вы можете «подготовить» свои аргументы перед подготовкой своего запроса, чтобы вы могли создавать динамические запросы и в конце имеют полностью подготовленный запрос. Уровень абстракции базы данных DALMP для MySQL с использованием PHP.

169
задан Tommyixi 25 March 2015 в 23:11
поделиться

2 ответа

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

CREATE TABLE popular_places (
  user_id INT NOT NULL,
  place_id INT NOT NULL,
  place_type VARCHAR(10) -- either 'states' or 'countries'
  -- foreign key is not possible
);

нет никакого пути к модели Polymorphic Associations с помощью ограничений SQL. Ограничение внешнего ключа всегда ссылки одна целевая таблица.

Полиморфные Ассоциации поддерживаются платформами, такими как направляющие и В спящем режиме. Но они явно говорят, что необходимо отключить ограничения SQL для использования этой функции. Вместо этого приложение или платформа должны сделать эквивалентную работу, чтобы гарантировать, что ссылка удовлетворена. Таким образом, значение во внешнем ключе присутствует в одной из возможных целевых таблиц.

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

Вот некоторые альтернативные решения, которые действительно используют в своих интересах осуществленную базой данных ссылочную целостность:

Составляют одну дополнительную таблицу на цель. , Например popular_states и popular_countries, который ссылка states и countries соответственно. Каждая из этих "популярных" таблиц также ссылается на профиль пользователя.

CREATE TABLE popular_states (
  state_id INT NOT NULL,
  user_id  INT NOT NULL,
  PRIMARY KEY(state_id, user_id),
  FOREIGN KEY (state_id) REFERENCES states(state_id),
  FOREIGN KEY (user_id) REFERENCES users(user_id),
);

CREATE TABLE popular_countries (
  country_id INT NOT NULL,
  user_id    INT NOT NULL,
  PRIMARY KEY(country_id, user_id),
  FOREIGN KEY (country_id) REFERENCES countries(country_id),
  FOREIGN KEY (user_id) REFERENCES users(user_id),
);

Это действительно означает, что для получения всего популярного фаворита пользователя размещает Вас, должен запросить обе из этих таблиц. Но это означает, что можно полагаться на базу данных для осуществления непротиворечивости.

Создают places таблица как супертаблица. , Поскольку Abie упоминает, вторая альтернатива - то, что Ваши популярные места ссылаются на таблицу как [1 113], который является родителем и к [1 114] и к countries. Таким образом, и состояния и страны также имеют внешний ключ к [1 116] (можно даже заставить этот внешний ключ также быть первичным ключом [1 117] и countries).

CREATE TABLE popular_areas (
  user_id INT NOT NULL,
  place_id INT NOT NULL,
  PRIMARY KEY (user_id, place_id),
  FOREIGN KEY (place_id) REFERENCES places(place_id)
);

CREATE TABLE states (
  state_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (state_id) REFERENCES places(place_id)
);

CREATE TABLE countries (
  country_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (country_id) REFERENCES places(place_id)
);

Use два столбца. Вместо одного столбца, который может сослаться на любую из двух целевых таблиц, используйте два столбца. Эти два столбца могут быть NULL; на самом деле только один из них должен быть не - NULL.

CREATE TABLE popular_areas (
  place_id SERIAL PRIMARY KEY,
  user_id INT NOT NULL,
  state_id INT,
  country_id INT,
  CONSTRAINT UNIQUE (user_id, state_id, country_id), -- UNIQUE permits NULLs
  CONSTRAINT CHECK (state_id IS NOT NULL OR country_id IS NOT NULL),
  FOREIGN KEY (state_id) REFERENCES places(place_id),
  FOREIGN KEY (country_id) REFERENCES places(place_id)
);

С точки зрения реляционной теории, Полиморфные Ассоциации нарушают Первая Нормальная форма , потому что эти popular_place_id в действительности столбец с двумя значениями: это - или состояние или страна. Вы не сохранили бы человека age и их phone_number в отдельном столбце, и по той же причине Вы не должны хранить и state_id и country_id в отдельном столбце. То, что эти два атрибута имеют совместимые типы данных, является случайным; они все еще показывают различные логические объекты.

Полиморфные Ассоциации также нарушают Третья Нормальная форма , потому что значение столбца зависит от дополнительного столбца, который называет таблицу, к которой относится внешний ключ. В Третьей Нормальной форме атрибут в таблице должен зависеть только от первичного ключа той таблицы.

<час>

комментарий Ре от @SavasVedova:

я не уверен, что следую Вашему описанию, не видя определения таблицы или запрос в качестве примера, но оно кажется, что у Вас просто есть [приблизительно 1 126] таблицы, каждый содержащий внешний ключ, который ссылается на центральное Products таблица.

CREATE TABLE Products (
  product_id INT PRIMARY KEY
);

CREATE TABLE FiltersType1 (
  filter_id INT PRIMARY KEY,
  product_id INT NOT NULL,
  FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

CREATE TABLE FiltersType2 (
  filter_id INT  PRIMARY KEY,
  product_id INT NOT NULL,
  FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

...and other filter tables...

Соединение продуктов к определенному типу фильтра легко, если Вы знаете, к какому типу Вы хотите присоединиться:

SELECT * FROM Products
INNER JOIN FiltersType2 USING (product_id)

, Если Вы хотите, чтобы тип фильтра был динамичным, необходимо записать код приложения для построения SQL-запроса. SQL требует, чтобы таблица была определена и зафиксирована в то время, когда Вы пишете запрос. Вы не можете заставить объединяемую таблицу быть выбранной динамично на основе значений, найденных в отдельных строках [1 128].

Единственная другая опция состоит в том, чтобы соединить с [1 131] весь таблицы фильтра с помощью внешних объединений. Те, которые не имеют никакого соответствия product_id, будут просто возвращены как единственная строка пустых указателей. Но у Вас все еще есть к hardcode весь объединяемые таблицы, и если Вы добавляете новые таблицы фильтра, необходимо обновить код.

SELECT * FROM Products
LEFT OUTER JOIN FiltersType1 USING (product_id)
LEFT OUTER JOIN FiltersType2 USING (product_id)
LEFT OUTER JOIN FiltersType3 USING (product_id)
...

Другой способ соединить со всеми таблицами фильтра состоит в том, чтобы сделать это последовательно:

SELECT * FROM Product
INNER JOIN FiltersType1 USING (product_id)
UNION ALL
SELECT * FROM Products
INNER JOIN FiltersType2 USING (product_id)
UNION ALL
SELECT * FROM Products
INNER JOIN FiltersType3 USING (product_id)
...

, Но этот формат все еще требует, чтобы Вы записали ссылки на все таблицы. Существует не обходящий это.

257
ответ дан Bill Karwin 23 November 2019 в 20:52
поделиться

Это не самое изящное решение в мире, но Вы могли использовать конкретное наследование таблицы для создания этой работы.

Концептуально Вы предлагаете понятие класса "вещей, которые могут быть популярными областями", которым наследовались Ваши три типа мест. Вы могли представить это как названную таблицу, например, places, где каждая строка имеет непосредственные отношения со строкой в regions, countries, или states. (Атрибуты, которые совместно используются регионами, странами или состояниями, если таковые имеются, могли быть продвинуты в это, помещает таблицу.) Ваш popular_place_id тогда была бы ссылка внешнего ключа на строку в таблице мест, которая тогда приведет Вас к региону, стране или состоянию.

решение Вы предлагаете со вторым столбцом описать тип ассоциации, оказывается, как направляющие обрабатывают полиморфные ассоциации, но я не поклонник этого в целом. Bill объясняет в превосходных деталях, почему полиморфные ассоциации не являются Вашими друзьями.

10
ответ дан Abie 23 November 2019 в 20:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: