3

我正在使用 postgresql,尽管我也在 sqlfiddle.com 中确认了这一点。

我的表格和元素是:

create table Publisher(pID int PRIMARY KEY, name varchar(255), address varchar(255));
create table Book(ISBN int PRIMARY KEY, name varchar(255), genre varchar(255), price int, copies int, pID int REFERENCES Publisher(pID));
insert into Publisher values(1, 'Oxford University Press', 'Senkosova');
insert into Book values(111, 'Alamut', 'Horror', 50, 100, 1);

我想自然地加入 Book and Publisher 并获得牛津大学出版社出版的书籍。

这有效:

select b.name
from Book as b, Publisher as p
where b.pid = p.pid and p.name ='Oxford University Press';

这不会:

select b.name
from Book as b natural join Publisher as p
where p.name = 'Oxford University Press';

即使这样也不会:

select *
from Book natural join Publisher;

为什么??

4

2 回答 2

3

不要使用natural join,这是一个等待发生的错误。相反,使用显式onorusing子句:

select b.name
from Book b join
     Publisher p
     using (pid)
where p.name = 'Oxford University Press';

或者:

select b.name
from Book b join
     Publisher p
     where b.pid = p.pid
where p.name = 'Oxford University Press';

问题有natural join两个方面。首先,它基于通用名称比较列,甚至不基于声明的外键关系。您的两个表都有一name列和一id列,因此自然连接查询至少相当于:

select b.name
from Book b join
     Publisher p
     where b.pid = p.pid and b.name = p.name 
where p.name = 'Oxford University Press';

(并且可能还有其他列具有相同的名称。)我怀疑任何书籍都被命名为“牛津大学出版社”,因此您在数据中没有匹配项。

第二个问题是相关的。通过不明确包括用于连接的列,查询的读者不知道。这使得查询更难调试和理解。就我而言,我创建的几乎所有表都有列,因此CreatedAts无论如何都不会在我的数据库中工作。CreatedBynatural join

于 2016-11-06T16:20:31.057 回答
3

您在两个表中都有一对以上具有相同名称的列:idname. 所以

select *
from book 
natural join publisher;

相当于

select *
from book b
join publisher p on b.pid = p.pid 
and b.name = p.name;

根据文档:

NATURAL 是 USING 的简写形式:它形成一个 USING 列表,其中包含出现在两个输入表中的所有列名。与 USING 一样,这些列在输出表中只出现一次。如果没有公用列名,则 NATURAL 的行为类似于 CROSS JOIN。

于 2016-11-06T16:21:58.087 回答