SQL Natural Join Dilemma re Order,Customer&推销员表

时间:2017-07-26 18:25:24

标签: mysql join relational-database natural-join

我得到了以下问题:

  

编写一个SQL语句,以表格形式连接表salesman,customer和orders,每个表的相同列将出现一次,只有关系行才会出现。

我执行了以下查询:

SELECT * FROM orders NATURAL JOIN customer NATURAL JOIN salesman;

但是,我没想到会有以下结果:

enter image description here

enter image description here

我的疑问在于第2步。

为什么我没有使用salesman_id 5002,5003& 5007?

我知道自然连接使用公共列来完成行。

此处所有Salesman_ids都出现在步骤1的结果中。

为什么最终结果不等于第1步产生的表格,并且销售员的非重复列已添加到其中?

2 个答案:

答案 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?

因为这些销售人员不在一个客户所居住的城市工作。