SQL: Создание нескольких внешних ключей с одним оператором эквивалентно созданию их с одним оператором? - PullRequest
0 голосов
/ 06 июля 2019

Например, давайте иметь следующее определение таблицы:

CREATE TABLE table1 
(
    id INT UNIQUE,
    name VARCHAR(100) UNIQUE,
    description VARCHAR(100),

    PRIMARY KEY (id, name)
);

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

1)

CREATE TABLE table2 
(
     id INT PRIMARY KEY,
     table1_id INT,
     table1_name VARCHAR(100),

     FOREIGN KEY (table1_id) REFERENCES table1(id),
     FOREIGN KEY (table1_name) REFERENCES table1(name)
);

2)

CREATE TABLE table2 
(
     id INT PRIMARY KEY,
     table1_id INT,
     table1_name VARCHAR(100),

     FOREIGN KEY (table1_id, table1_name) REFERENCES table1(id, name),
);

Я заметил, что Postgre SQL за кадром создает два объекта FK db в случае 1) и один объект FK в случае 2). Все ли будет работать так же?

1 Ответ

2 голосов
/ 06 июля 2019

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

Когда вы используете составной первичный ключ (ваш второй пример), вы гарантируете, что id / name выровнены в первой таблице. Когда вы используете отдельные ссылки (ваш первый пример), вы не знаете, что они выровнены, поэтому id может ссылаться на одну строку в table1, а name - на другую строку. Я сомневаюсь, что это твое намерение.

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

CREATE TABLE table1 (
  id INT PRIMARY KEY,
  name VARCHAR(100) UNIQUE,
  description VARCHAR(100),
);

CREATE TABLE table2 (
  id INT PRIMARY KEY,
  table1_id INT,
  FOREIGN KEY (table1_id) REFERENCES table1(id)
);

Затем, если вы хотите соответствующий name, найдите имя в первой таблице.

Как заметка, в Postgres я ожидал, что INT будет действительно SERIAL, поэтому база данных присваивает уникальное, увеличивающееся значение при вставке новых строк.

Если вы действительно хотите две ссылки на table1, тогда используйте две ссылки на id:

CREATE TABLE table2 (
  id INT PRIMARY KEY,
  table1_id INT,
  table1_id_2 INT,
  FOREIGN KEY (table1_id) REFERENCES table1(id),
  FOREIGN KEY (table1_id_2) REFERENCES table1(id)
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...