我使用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;
为什么?
答案 0 :(得分:3)
不要使用natural join
,这是一个等待发生的错误。相反,请使用明确的on
或using
子句:
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';
(并且可能还有其他列具有相同的名称。)我怀疑任何书名都被命名为牛津大学出版社,因此您在数据中没有匹配。
第二个问题是相关的。通过不明确包括用于加入的列,查询的读者不知道。这使得查询更难以调试和理解。就我而言,我创建的几乎所有表都有CreatedAt
和CreatedBy
列,因此natural join
无论如何都不会在我的数据库中运行。
答案 1 :(得分:3)
在两个表中,您有多个具有相同名称的列:id
和name
。所以
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。