在查询中的复合外键/主键列上连接表

Posted

技术标签:

【中文标题】在查询中的复合外键/主键列上连接表【英文标题】:Join tables on columns of composite foreign / primary key in a query 【发布时间】:2014-03-14 12:42:26 【问题描述】:
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);

但是,我的印象是有一种不那么冗长的方法来实现这一点。

【问题讨论】:

【参考方案1】:

delivery 不是有两列代表外键吗?然后它应该像使用非复合主键 SELECT * FROM subscription JOIN delivery ON (delivery.magazine_id = subscription.magazine_id AND delivery.user_id = subscription.user_id) 一样工作。

【讨论】:

是的,我正在寻找一种方法来编写这个,以便查询不那么冗长。我的印象是可以做到这一点【参考方案2】:

有一个NATURAL JOIN

SELECT *
FROM   subscription
NATURAL JOIN delivery;

引用the manual on SELECT:

NATURAL

NATURALUSING 列表的简写,它提到了两个表中同名的所有列。

它适用于您的测试设置,但它并非严格按照您的要求进行。该连接基于共享相同名称的所有列。不考虑外键。 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。

【讨论】:

@alumns:我添加了更多细节。 为这种情况创建自定义类型会有什么特别的优势吗? @IamIC:不知道你要去哪里。您可能会开始一个包含详细信息的新问题。您可以随时链接到此链接以获取上下文 - 并可选择在此处发表评论。 这是一个很好的答案,因为它展示了您可以如何做到这一点,但也明确指出了这一点,虽然它可能适用于给定的设置,这不是因为任何自动 FK 魔法

以上是关于在查询中的复合外键/主键列上连接表的主要内容,如果未能解决你的问题,请参考以下文章

oracle:物化视图中的主键列

MYSQL外键约束

MySQL-其它整理

HQL 无法在公共外键列上连接两个表

外键约束小结

添加唯一约束时出错:表中的列的类型对于用作索引中的键列无效[重复]