Соединение таблиц по столбцам составного внешнего/первичного ключа в запросе

CREATE TABLE subscription (
   magazine_id bigint,
   user_id     bigint,
   PRIMARY KEY (magazine_id, user_id)
);

CREATE TABLE delivery (
   magazine_id bigint,
   user_id     bigint,
   FOREIGN KEY (subscription) REFERENCES subscription (magazine_id, user_id)
);

Каков хороший способ запроса доставки с учетом конкретной подписки? Есть ли способ присвоить имя столбца PRIMARY KEY (magazine_id, user_id) и соответствующий внешний ключ, чтобы я мог делать запросы следующим образом:

SELECT *
FROM subscription
JOIN delivery ON (delivery.subscription_fk = delivery.subscription_pk);

Примечание. Я могу написать что-то вроде этого:

SELECT *
FROM subscription
JOIN delivery ON (delivery.magazine_id = subscription.magazine_id
              AND delivery.user_id = subscription.user_id);

Однако у меня сложилось впечатление, что есть менее подробный способ добиться этого.


person samol    schedule 14.02.2014    source источник


Ответы (2)


Есть NATURAL JOIN:

SELECT *
FROM   subscription
NATURAL JOIN delivery;

Цитирование руководства по SELECT:

NATURAL

NATURAL — это сокращение для списка USING, в котором упоминаются все столбцы в двух таблицах с одинаковыми именами.

Это сработает для вашей тестовой установки, но не совсем то, о чем вы просите. Соединение основано на том, что все столбцы имеют одно и то же имя. Внешние ключи не учитываются. Случаи, когда NATURAL JOIN является хорошей идеей, немногочисленны.

Упростить код/менее многословный

Для начала вы можете использовать псевдонимы таблиц, и вам не нужны круглые скобки вокруг условий соединения с ON (в отличие от USING):

SELECT *
FROM   subscription s
JOIN   delivery     d ON d.magazine_id = s.magazine_id
                     AND d.user_id = s.user_id;

Так как имена столбцов в условиях соединения идентичны, вы можете еще больше упростить с помощью USING:

SELECT *
FROM   subscription s
JOIN   delivery     d USING (magazine_id, user_id);

Не существует варианта синтаксиса, автоматически создающего объединения на основе ограничений внешнего ключа. Вам придется запрашивать системные каталоги и динамически создавать SQL.

person Erwin Brandstetter    schedule 15.02.2014
comment
@alumns: я добавил еще несколько деталей. - person Erwin Brandstetter; 15.02.2014
comment
Будет ли какое-либо особое преимущество в создании пользовательского типа для этого сценария? - person IamIC; 08.12.2015
comment
@IamIC: Не уверен, к чему ты клонишь. Вы можете начать новый вопрос с подробностей. Вы всегда можете дать ссылку на это для контекста и, при желании, оставить комментарий здесь. - person Erwin Brandstetter; 08.12.2015
comment
Это отличный ответ, потому что он показывает, как вы можете это сделать, но также явно указывает, что, хотя он может работать для данной настройки, это не из-за каких-либо автоматическая магия ФК - person kevlarr; 11.10.2019

Разве delivery не имеет двух столбцов, представляющих внешний ключ? Тогда это должно работать как с несоставным первичным ключом SELECT * FROM subscription JOIN delivery ON (delivery.magazine_id = subscription.magazine_id AND delivery.user_id = subscription.user_id).

person Smutje    schedule 15.02.2014
comment
Да, я искал способ написать это, чтобы запрос был менее подробным. Я был под впечатлением, что это может быть сделано - person samol; 15.02.2014