SQL 自然连接困境重新订购、客户和销售员表

问题描述 投票:0回答:3

我被问到以下问题:

编写一条 SQL 语句对 salesman、customer 和orders 表进行联接,其形式是每个表的相同列只出现一次,并且只出现相关行。

我执行了以下查询:

SELECT * FROM orders NATURAL JOIN customer NATURAL JOIN salesman;

然而,我没想到会出现以下结果:

我的疑问在于步骤2。

为什么我没有获得 salesman_id 5002、5003 和 5007 的行?

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

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

为什么最终结果不等于步骤 1 中添加了来自销售人员的非重复列的表?

mysql join relational-database natural-join
3个回答
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, ...


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] ...

自然连接的定义是,如果每个输入保存使其谓词成为 true 语句的行,那么它们的自然连接将保存使这些谓词的 AND/连接成为 true 语句的行。所以(你的问题):

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] ...

因此,自然连接要求的行中,除其他外,客户居住在推销员工作的城市。如果这不是您想要的,那么您不应该使用该表达式。

注意表的自然连接的含义如何是其输入表的含义的(简单)函数。对于所有关系运算符都是如此。因此,每个查询表达式都有一个含义,是根据其基表含义和关系运算符构建的。
是否有任何经验法则可以根据人类可读的描述构建 SQL 查询?

为什么我没有获得 salesman_id 5002、5003 和 5007 的行?

因为这些推销员不在他们的客户居住的城市工作。


0
投票

编写SQL语句连接表salesman、customer和orders,以便每个表的相同列出现一次并且仅返回关系行。但它在 SQL Server 中是如何工作的 如果我编写查询“SELECT * FROM ORDERS JOIN SALESMAN ON ORDERS.salesman_id = SALESMAN.salesman_id JOIN CUSTOMER ON ORDERS.cut_id = CUSTOMER.cut_id;” 这会显示重复的列

© www.soinside.com 2019 - 2024. All rights reserved.