我得到了以下问题:
编写一个SQL语句,以表格形式连接表salesman,customer和orders,每个表的相同列将出现一次,只有关系行才会出现。
我执行了以下查询:
SELECT * FROM orders NATURAL JOIN customer NATURAL JOIN salesman;
但是,我没想到会有以下结果:
我的疑问在于第2步。
为什么我没有使用salesman_id 5002,5003& 5007?
我知道自然连接使用公共列来完成行。
此处所有Salesman_ids都出现在步骤1的结果中。
为什么最终结果不等于第1步产生的表格,并且销售员的非重复列已添加到其中?
答案 0 :(得分:1)
...每个表的同一列将出现一次
是Natural Join
就是这样。
...只会出现关系行。
我不知道这意味着什么。
我不同意那些说:不要使用Natural Join
。但是,如果您打算使用Natural Join
进行查询,那么您必须设计架构,以便(松散地说)“相同的列名称意味着同样的事情”。
然后,本练习教你如何使用同名的列并不意味着相同的东西。危险有时被称为“连接陷阱”或“连接陷阱”。 (不是真正的陷阱:你只需要学习在设计不良的模式上编写查询的方法。)
更精确的说法:如果在两个不同的表中有相同的列,则该列必须至少是其中一个的键。所以:
city
不是任何表格中的关键字,
所以不应该在Natural Join
中被“捕获”。salesman_id
不是表customer
中的关键字,
因此,不应在表orders
的联接中“捕获”。修复此查询的主要方法是重命名一些列以避免“捕获”(见下文)。值得一提的是,SQL的一些方言允许:
SELECT *
FROM orders
NATURAL JOIN customer ON customer_id
...
ON column(s)
短语表示:验证两个表之间唯一的共同列是那些命名的列。否则拒绝查询。所以你的查询将被拒绝。
重命名意味着您不应使用SELECT *
。 (无论如何,这对于'生产代码'是危险的,因为每次有架构更改时,您的查询可能会生成不同的列。)解决此问题的最简单方法可能是为您的三个基表创建三个视图,其中“意外”相同 - 命名列给出了一些其他名称。对于这一个查询:
SELECT ord_no, purch_amt, ord_date, customer_id,
salesman_id AS order_salesman_id
FROM orders
NATURAL JOIN (SELECT customer_id, cust_name,
city AS cust_city, grade,
salesman_id AS cust_salesman_id
FROM customer) AS customer_grr
NATURAL JOIN (SELECT salesman_id, name,
city AS salesman_city,
commission
FROM salesman) AS salesman_grr
我正在使用显式AS
来显示重命名。 SQL的大多数方言都允许您省略该关键字;只需添加city cust_city, ...
。
答案 1 :(得分:0)
为什么最终结果与[...]步骤1中的表格相等?
因为自然联合并不像你期望的那样 - 无论如何,因为你不会说。
就关系代数而言:自然连接返回行
•其列集是输入列集和
的并集
•在两个输入中都有一个子行。
在商业方面:每张桌子和一张桌子查询结果包含创建一些语句模板的行 - 它的(特征)谓词 - 它的"含义" - 成为一个真实的语句。设计器为基表提供谓词。在这里,像:
Orders = rows where
order [ord_no] ... and was sold by salesman [salesman_id] to customer [customer_id]
Customer = rows where
customer [customer_id] has name [cust_name] and lives in city [city]
and ... and is served by salesman [salesman_id]
Salesman = rows where
salesman [salesman_id] has name [name] and works in city [city] ...
定义自然连接,以便如果每个输入都包含使其谓词成为真实语句的行,则它们的自然连接将保存将这些谓词的AND /连接成为真实语句的行。所以(你的查询):
Orders natural join Customer natural join Salesman = rows where
order [ord_no] ... and was sold by salesman [salesman_id] to customer [customer_id]
and customer [customer_id] has name [cust_name] and lives in city [city]
and ... and is served by salesman [salesman_id]
and salesman [salesman_id] has name [name] and works in city [city] ...
因此,自然联合会要求行,其中包括客户居住在销售员工作的城市。如果这不是您想要的,那么您不应该使用该表达式
注意表的自然连接的含义是否是其输入表的含义的(简单)函数。这对于所有关系运营商来说都是如此。因此,每个查询表达式都有一个含义,它是根据其基表含义构建的。关系运算符 Is there any rule of thumb to construct SQL query from a human-readable description?
为什么我没有使用salesman_id 5002,5003& 5007?
因为这些销售人员不在一个客户所居住的城市工作。