何时使用左外连接?

Posted

技术标签:

【中文标题】何时使用左外连接?【英文标题】:When to use a left outer join? 【发布时间】:2011-08-17 23:59:06 【问题描述】:

我不明白左外连接、右外连接的概念,或者根本不明白为什么我们需要使用连接!我正在努力解决的问题和我正在使用的表格在这里:Link

问题 3(b)

在 SQL 中构造一个命令来解决以下查询,解释为什么它必须使用 (外)连接方法。 [5分] “找到每个工作人员及其受抚养配偶的姓名(如果有)”

问题 3(c) -

在 SQL 中构造一个命令来解决以下查询,使用 (i) 连接方法,和 (ii) 子查询方法。 [10 分] “找到每个工作超过 20 小时的工作人员的身份名称 计算机化项目”

谁能简单的给我解释一下?

【问题讨论】:

它的“如果有的话”......左外连接与左连接(在 mysql 中)相同,即使它们不一定与另一个表中的行匹配,您也可以使用它们返回行。 另外,您需要使用连接,因为这很简单,就是数据库查询的工作方式。这就像问我们为什么需要用肺来呼吸。联接是对关系数据库进行查询的机制。联接根本不是一个复杂的概念,如果您遇到问题,我建议您对关系数据库进行额外的入门阅读。如果您确实是科克大学的学生,那么您应该可以访问此资源:proquest.safaribooksonline.com/… 【参考方案1】:

当您需要来自一个连接表的所有结果时,您可以使用外连接,无论另一个表中是否存在匹配行。

【讨论】:

这里有完整的解释:http://***.com/questions/38549/sql-difference-between-inner-and-outer-join【参考方案2】:

联接用于将两个相关的表组合在一起。

在您的示例中,您可以组合 Employee 表和 Department 表,如下所示:

SELECT FNAME, LNAME, DNAME
FROM
EMPLOYEE INNER JOIN DEPARTMENT ON EMPLOYEE.DNO=DEPARTMENT.DNUMBER

这将产生如下记录集:

FNAME   LNAME   DNAME
-----   -----   -----
John    Smith   Research
John    Doe     Administration

我在上面使用了INNER JOININNER JOINs 合并两个表,以便显示在两个表中匹配的记录,并且在这种情况下,它们加入部门编号(Employee 中的字段 DNO , DNUMBER 在部门表中)。

LEFT JOINs 允许您在第一个表中有记录但可能没有第二个表中有记录时合并两个表。例如,假设您想要一份所有员工以及所有家属的列表:

SELECT EMPLOYEE.FNAME as employee_first, EMPLOYEE.LNAME as employee_last, DEPENDENT.FNAME as dependent_last, DEPENDENT.LNAME as dependent_last
FROM
EMPLOYEE INNER JOIN DEPENDENT ON EMPLOYEE.SSN=DEPENDENT.ESSN

这里的问题是,如果员工没有有受抚养人,那么他们的记录根本不会显示——因为在 DEPENDENT 表中没有匹配的记录。

因此,您使用 left 连接将所有数据保留在“左侧”(即第一个表)并在“右侧”(第二个表)中提取任何匹配的数据:

SELECT EMPLOYEE.FNAME as employee_first, EMPLOYEE.LNAME as employee_last, DEPENDENT.FNAME as dependent_first, DEPENDENT.LNAME as dependent_last
FROM
EMPLOYEE LEFT JOIN DEPENDENT ON EMPLOYEE.SSN=DEPENDENT.ESSN

现在我们获得了所有的员工记录。如果给定员工没有匹配的家属,dependent_firstdependent_last 字段将为空。

【讨论】:

是的,当我完成回答时,我意识到这基本上是一项家庭作业(我忽略了底部的问题,只关注第一部分以及链接的文档)。我添加了“标记为作业”这句话,但后来看到其他人打了我一拳,所以我删除了那行。 :) 这不是家庭作业。非常感谢您的回答,非常有帮助:)。【参考方案3】:

示例(不使用您的示例表 :-)

我有一家汽车租赁公司。

Table car
id: integer primary key autoincrement
licence_plate: varchar
purchase_date: date

Table customer
id: integer primary key autoincrement
name: varchar

Table rental
id: integer primary key autoincrement
car_id: integer
bike_id: integer
customer_id: integer
rental_date: date

简单吧?我有 10 条汽车记录,因为我有 10 辆汽车。 我经营这家公司 10 年了,所以我有 1000 名客户。 我每年每辆车的租金约为 20 倍 = 10 年 x 10 辆汽车 x 20 = 2000 次租金。

如果我将所有内容存储在一张大表中,我就有 10x1000x2000 = 2000 万条记录。 如果我将它存储在 3 个表中,我有 10+1000+2000 = 3010 条记录。 那是 3 个数量级,所以这就是我使用 3 个表的原因。

但因为我使用 3 个表 (以节省空间和时间) 我必须使用连接才能再次获取数据(至少如果我想要名称和车牌而不是数字).

使用内部联接

客户 345 的所有租金?

SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id)
INNER JOIN car on (car.id = rental.car_id)
WHERE customer.id = 345.

这是一个INNER JOIN,因为我们想了解汽车linked to 租赁linked to 实际发生的客户。

请注意,我们还有一个bike_id,链接到bike table,它与car table 非常相似,但又有所不同。 我们如何为客户 345 获得所有自行车 + 汽车租赁服务。 我们可以尝试并做到这一点

SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id)
INNER JOIN car on (car.id = rental.car_id)
INNER JOIN bike on (bike.id = rental.bike_id)
WHERE customer.id = 345.

但这会给出一个空集!! 这是因为租赁可以是bike_rental 或car_rental,但不能同时是两者。 不工作的inner join 查询只会为我们在同一交易中同时租用自行车和汽车的所有租赁提供结果。我们正在尝试使用布尔值AND 加入。

使用外连接

为了解决这个问题,我们需要一个outer join

让我们用left join解决它

SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id) <<-- link always
LEFT JOIN car on (car.id = rental.car_id) <<-- link half of the time
LEFT JOIN bike on (bike.id = rental.bike_id) <<-- link (other) 0.5 of the time.
WHERE customer.id = 345.

这样看。 inner joinANDleft joinOR,如以下伪代码所示:

if a=1 AND a=2 then this is always false, no result
if a=1 OR a=2 then  this might be true or not

如果您创建表并运行查询,您可以看到结果。

关于术语

left joinleft outer join 相同。 没有额外前缀的 joininner join 还有一个full outer join。在 25 年的编程生涯中,我从未使用过它。

为什么要离开

这里有两张桌子。在我们链接的示例中 客户使用inner join 租用,在内部连接两个表必须链接,所以left:customer 表和right:rental 表之间没有区别。

下一个链接是位于left:rentalright:car 之间的left join。在左侧,所有行都必须链接,而右侧则不必。这就是为什么它是left join

【讨论】:

nice :D 感谢ANDOR 关系的精彩解释:D 这让我了解了其中的不同之处。在此之前,我不明白,为什么人们总是使用整张桌子时使用LEFT JOIN:D【参考方案4】:

我认为问题 3(b) 令人困惑,因为它的整个前提是错误的:您不必使用外连接来“解决查询”,例如考虑一下(遵循试卷中的语法风格可能是明智的):

SELECT FNAME, LNAME, DEPENDENT_NAME
  FROM EMPLOYEE, DEPENDENT
 WHERE SSN = ESSN
       AND RELATIONSHIP = 'SPOUSE'
UNION 
SELECT FNAME, LNAME, NULL
  FROM EMPLOYEE
EXCEPT 
SELECT FNAME, LNAME, DEPENDENT_NAME
  FROM EMPLOYEE, DEPENDENT
 WHERE SSN = ESSN
       AND RELATIONSHIP = 'SPOUSE'

【讨论】:

【参考方案5】:

一般来说: JOIN 将两个表连接在一起。 当您想“查找”时使用 INNER JOIN,例如查找任何特定列的详细信息。 当您想“演示”时使用 OUTER JOIN,例如列出 2 个表的所有信息。

【讨论】:

以上是关于何时使用左外连接?的主要内容,如果未能解决你的问题,请参考以下文章

Linq to Sql:多个左外连接

左外连接和右外连接的区别

Linq左外连接 多字段连接

如何强制 Hibernate 在组件上使用左外连接进行命名查询?

如何使用 Dynamic Linq 进行左外连接?

为啥我什至没有使用左连接时会收到左外连接错误消息?