“INNER JOIN”和“OUTER JOIN”有什么区别?

时间:2008-09-01 22:36:07

标签: sql database join inner-join outer-join

LEFT JOINRIGHT JOINFULL JOIN如何适应?

29 个答案:

答案 0 :(得分:5794)

假设您正在加入没有重复的列,这是一种非常常见的情况:

  • A和B的内连接给出A交叉B的结果,即Venn diagram交点的内部。

  • A和B的外连接给出A联合B的结果,即维恩图联合的外部部分。

<强>实施例

假设您有两个表,每个表都有一个列,数据如下:

A    B
-    -
1    3
2    4
3    5
4    6

注意(1,2)是A独有的,(3,4)是常见的,(5,6)是B独有的。

内部联接

使用任一等效查询的内部联接给出了两个表的交集,即它们共有的两行。

select * from a INNER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b;

a | b
--+--
3 | 3
4 | 4

左外连接

左外连接将给出A中的所有行,以及B中的所有公共行。

select * from a LEFT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b(+);

a |  b
--+-----
1 | null
2 | null
3 |    3
4 |    4

右外连接

右外连接将给出B中的所有行,以及A中的所有常见行。

select * from a RIGHT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a(+) = b.b;

a    |  b
-----+----
3    |  3
4    |  4
null |  5
null |  6

全外联接

完全外连接将为您提供A和B的并集,即A中的所有行和B中的所有行。如果A中的某些内容在B中没有对应的数据,则B部分为空,反之亦然。

select * from a FULL OUTER JOIN b on a.a = b.b;

 a   |  b
-----+-----
   1 | null
   2 | null
   3 |    3
   4 |    4
null |    6
null |    5

答案 1 :(得分:609)

维恩的图表并不适合我。

例如,他们没有显示交叉连接和内连接之间的任何区别,或者更一般地显示不同类型的连接谓词之间的任何区别,或提供一个框架来推断它们将如何操作。

理解逻辑处理是无可替代的,无论如何都要相对简单。

  1. 想象一下交叉加入。
  2. 针对步骤1中的所有行评估on子句,并将谓词计算结果保留为true
  3. (仅适用于外部联接)在步骤2中丢失的任何外部行中添加回来。
  4. (注意:在实践中,查询优化器可能会找到比上面的纯逻辑描述更有效的执行查询的方法,但最终结果必须相同)

    我将开始使用完整外部联接的动画版本。进一步解释如下。

    enter image description here


    解释

    来源表

    enter link description here

    首先从CROSS JOIN(AKA笛卡尔积)开始。这没有ON子句,只返回两个表中的每个行组合。

    SELECT A.Colour,B.Colour from A CROSS JOIN B

    enter link description here

    内部和外部联接有一个&#34; ON&#34;子句谓词。

    • 内部加入。评估&#34; ON&#34;交叉连接结果中所有行的子句。如果为true则返回连接的行。否则丢弃它。
    • 左外连接。与内连接相同,然后左表中任何与任何内容不匹配的行输出这些与右表列的NULL值。
    • 右外连接。与内连接相同,然后对于右表中任何与之匹配的行,输出这些与左表列的NULL值。
    • 完全外部联接。与内部联接相同,然后保留左侧外部联接中的左侧非匹配行,右侧外部联接中保留右侧非匹配行。

    一些例子

    SELECT A.Colour,B.Colour from A INNER JOIN B ON A.Colour = B.Colour

    以上是经典的equi join。

    Inner Join

    动画版

    enter image description here

    SELECT A.Colour,B.Colour from A INNER JOIN B ON A.Colour NOT IN IN(&#39; Green&#39;,&#39; Blue&#39;)

    内连接条件不一定是相等条件,也不需要引用两个(甚至任何一个)表中的列。评估交叉连接的每一行上的A.Colour NOT IN ('Green','Blue')返回。

    inner 2

    SELECT A.Colour,B.Colour from A INNER JOIN B ON 1 = 1

    对于交叉连接结果中的所有行,连接条件的计算结果为true,因此这与交叉连接相同。我再也不会重复16行的图片了。

    SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour

    外连接的逻辑评估方式与内连接的方式相同,只是如果左表中的一行(左连接)没有与右表中的任何行连接,则它将保留在结果中右侧列的NULL值。

    LOJ

    SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour IS NULL

    这只是限制了之前的结果,只返回B.Colour IS NULL的行。在这种特殊情况下,这些行将被保留,因为它们在右侧表中没有匹配,并且查询返回表B中不匹配的单个红色行。这被称为反半连接。

    IS NULL测试选择一个不可为空的列,或者连接条件确保排除任何NULL值以使此模式正常工作并且除了未匹配的行之外,请避免仅返回恰好具有NULL值的行。

    loj is null

    SELECT A.Colour,B.Colour from A RUST OUTER JOIN B ON A.Colour = B.Colour

    右外连接的作用类似于左外连接,除了它们保留右表中不匹配的行,null扩展左侧列。

    ROJ

    SELECT A.Colour,B.Colour from A FULL OUTER B B ON A.Colour = B.Colour

    完全外连接组合了左连接和右连接的行为,并保留左右表中不匹配的行。

    FOJ

    SELECT A.Colour,B.Colour from A Full OUTER JOIN B ON 1 = 0

    交叉联接中的任何行都不匹配1=0谓词。使用常规外部联接规则保留两侧的所有行,并在另一侧的表中使用NULL。

    FOJ 2

    SELECT COALESCE(A.Colour,B.Colour)AS颜色来自一个完整的外部连接B ON 1 = 0

    通过对前一个查询的微小修改,可以模拟两个表中的UNION ALL

    UNION ALL

    SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour =&#39; Green&#39;

    请注意,WHERE子句(如果存在)在连接后以逻辑方式运行。一个常见错误是执行左外连接,然后包含WHERE子句,右子表上的条件最终排除不匹配的行。以上结果是执行外连接...

    LOJ

    ...然后&#34; Where&#34;子句运行。 NULL= 'Green'未评估为true,因此外部联接保留的行最终被丢弃(连同蓝色联接),有效地将联接转换回内部联接。

    LOJtoInner

    如果打算只包含B中的行,其中Color为绿色,而所有来自A的行都不包括正确的语法

    SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour AND B.Colour =&#39; Green&#39;

    enter image description here

    SQL小提琴

    请参阅以下示例run live at SQLFiddle.com

答案 2 :(得分:139)

联接用于组合两个表中的数据,结果是一个新的临时表。连接是基于称为谓词的东西执行的,谓词指定了用于执行连接的条件。内连接和外连接之间的区别在于内连接将仅返回基于连接谓词实际匹配的行。 让我们考虑员工和位置表:

enter image description here

内部加入: - 内连接通过基于连接谓词组合两个表( Employee Location )的列值来创建新的结果表。查询将 Employee 的每一行与 Location 的每一行进行比较,以查找满足join-predicate的所有行对。当通过匹配非NULL值来满足连接谓词时, Employee Location 的每对匹配行的列值将合并到结果行中。 以下是内部联接的SQL的样子:

select  * from employee inner join location on employee.empID = location.empID
OR
select  * from employee, location where employee.empID = location.empID

现在,运行SQL的结果如下: enter image description here enter image description here

外部加入: - 外连接不要求两个连接表中的每个记录都具有匹配的记录。即使没有其他匹配记录,联接表也会保留每条记录。外连接进一步细分为左外连接和右外连接,具体取决于保留哪个表的行(左或右)。

左外连接: - Employee Location 的左外连接(或简称左连接)的结果始终包含“左”表的所有记录( Employee ),即使连接条件在“右”表( Location )中找不到任何匹配的记录。 下面是使用上表中的左外连接的SQL:

select  * from employee left outer join location on employee.empID = location.empID;
//Use of outer keyword is optional

现在,运行此SQL的结果如下: enter image description here enter image description here

正确的外部加入: - 右外连接(或右连接)非常类似于左外连接,除了对表的处理进行了反转。 “右”表(位置)中的每一行都将至少出现在连接表中一次。如果“左”表( Employee )中没有匹配的行,则 Employee 中的列将显示为 Location 。 这就是SQL的样子:

select * from employee right outer join location  on employee.empID = location.empID;
//Use of outer keyword is optional

使用上面的表格,我们可以显示右外连接的结果集是什么样的:

enter image description here enter image description here

完整的外部联接: - 完全外连接或完全连接是通过在连接的结果中包含不匹配的行来保留不匹配的信息,使用完全外连接。它包括来自两个表的所有行,无论另一个表是否具有匹配值。 enter image description here

Image Source

MySQL 8.0 Reference Manual - Join Syntax

Oracle Join operations

答案 3 :(得分:121)

内部加入

仅检索匹配的行,即A intersect B

Enter image description here

SELECT *
FROM dbo.Students S
INNER JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

左外连接

从第一个表中选择所有记录,在第二个表中选择所有记录 与连接键匹配的表。

Enter image description here

SELECT *
FROM dbo.Students S
LEFT JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

完全外部加入

从第二个表中选择所有记录,并在第一个表中选择所有记录 与连接键匹配的表。

Enter image description here

SELECT *
FROM dbo.Students S
FULL JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

参考

答案 4 :(得分:106)

简单来说:

内部联接仅检索匹配的行。

外部联接从一个表和其他表中的所有行中检索匹配的行....结果取决于您使用的是哪一行:

  • :右表中匹配的行和左表中的所有行

  • 正确:左表中的匹配行和右表中的所有行或

  • 完整:所有表格中的所有行。

  • 是否匹配并不重要

答案 5 :(得分:98)

如果在连接的另一侧(右侧)有匹配的记录,则内部联接仅显示行。

(左)外连接显示左侧每条记录的行,即使连接的另一侧(右侧)没有匹配的行。如果没有匹配的行,则另一侧(右侧)的列将显示NULL。

答案 6 :(得分:74)

内部联接要求联接表中存在具有相关ID的记录。

即使右侧没有任何内容,外连接也会返回左侧的记录。

例如,您有一个Orders和一个OrderDetails表。它们与“OrderID”相关联。

订单

  • 订单ID
  • 客户名称

<强>订单明细

  • OrderDetailID
  • 订单ID
  • 产品名称
  • 数量
  • 价格

请求

SELECT Orders.OrderID, Orders.CustomerName
  FROM Orders 
 INNER JOIN OrderDetails
    ON Orders.OrderID = OrderDetails.OrderID

只返回在OrderDetails表中也有内容的订单。

如果您将其更改为OUTER LEFT JOIN

SELECT Orders.OrderID, Orders.CustomerName
  FROM Orders 
  LEFT JOIN OrderDetails
    ON Orders.OrderID = OrderDetails.OrderID

然后它将返回Orders表中的记录,即使它们没有OrderDetails记录。

您可以通过添加类似WHERE OrderDetails.OrderID IS NULL的where子句来查找没有任何指示可能的孤立订单的OrderDetails的订单。

答案 7 :(得分:62)

简单来说:

内部联接 - &gt;从父表和子表中获取常用记录WHERE主表的主键与子表中的外键匹配。

左连接 - &gt;

伪代码

1.Take All records from left Table
2.for(each record in right table,) {
    if(Records from left & right table matching on primary & foreign key){
       use their values as it is as result of join at the right side for 2nd table.
    } else {
       put value NULL values in that particular record as result of join at the right side for 2nd table.
    }
  }

右连接:与左连接完全相反。将表的名称放在右连接右侧的LEFT JOIN中,得到与LEFT JOIN相同的输出。

外部联接:显示两个表No matter what中的所有记录。如果Left表中的记录与Primary,Forieign键的右表不匹配,则使用NULL值作为join的结果。

示例:

Example

现在让我们假设2个表

1.employees , 2.phone_numbers_employees

employees : id , name 

phone_numbers_employees : id , phone_num , emp_id   

这里,employees表是Master表,phone_numbers_employees是子表(它包含emp_id作为外键,连接employee.id所以它的子表。)

内部联接

获取2个表的记录仅因为员工表的主键(其ID)与子表phone_numbers_employees(emp_id)的外键匹配

所以查询将是:

SELECT e.id , e.name , p.phone_num FROM employees AS e INNER JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

这里只采用主键=外键上的匹配行,如上所述。作为连接结果,主键=外键上的非匹配行被跳过。

左连接

左连接保留左表的所有行,无论是否在右表上都有匹配的行。

SELECT e.id , e.name , p.phone_num FROM employees AS e LEFT JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

外部联接

SELECT e.id , e.name , p.phone_num FROM employees AS e OUTER JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

直观地看起来像是:

Diagram

答案 8 :(得分:55)

您使用 INNER JOIN 返回匹配的两个表中的所有行。即在结果表中,所有行和列都将具有值。

OUTER JOIN 中,生成的表可能包含空列。外联接可以是LEFTRIGHT

LEFT OUTER JOIN 会返回第一个表中的所有行,即使第二个表中没有匹配项也是如此。

RIGHT OUTER JOIN 会返回第二个表中的所有行,即使第一个表中没有匹配项也是如此。

答案 9 :(得分:54)

This is a good explanation for joins

这是所有类型连接的一个很好的图解说明

来源:http://ssiddique.info/understanding-sql-joins-in-easy-way.html

答案 10 :(得分:51)

INNER JOIN要求在比较两个表时至少存在匹配。例如,表A和表B表示A 8 B(A交点B)。

LEFT OUTER JOINLEFT JOIN是相同的。它给出了两个表中匹配的所有记录以及左表的所有可能性。

同样,RIGHT OUTER JOINRIGHT JOIN是相同的。它给出了两个表中匹配的所有记录以及右表的所有可能性。

FULL JOINLEFT OUTER JOINRIGHT OUTER JOIN的组合,没有重复。

答案 11 :(得分:39)

答案在于每个人的意思,所以在结果中。

  

注意:
  在SQLite中,没有RIGHT OUTER JOINFULL OUTER JOIN   在MySQL中也没有FULL OUTER JOIN

我的回答基于注意

当您有两个这样的表时:

--[table1]               --[table2]
id | name                id | name
---+-------              ---+-------
1  | a1                  1  | a2
2  | b1                  3  | b2

CROSS JOIN / OUTER JOIN:
您可以将所有这些表格数据设为CROSS JOIN,或仅使用,,如下所示:

SELECT * FROM table1, table2
--[OR]
SELECT * FROM table1 CROSS JOIN table2

--[Results:]
id | name | id | name 
---+------+----+------
1  | a1   | 1  | a2
1  | a1   | 3  | b2
2  | b1   | 1  | a2
2  | b1   | 3  | b2

INNER JOIN:
如果您想根据table1.id = table2.id之类的关系向上述结果添加过滤器,可以使用INNER JOIN

SELECT * FROM table1, table2 WHERE table1.id = table2.id
--[OR]
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id

--[Results:]
id | name | id | name 
---+------+----+------
1  | a1   | 1  | a2

LEFT [OUTER] JOIN:
如果您希望在上述结果中包含其中一个表的所有行 - 具有相同的关系 - 您可以使用LEFT JOIN
(对于 RIGHT JOIN 只需更改表格的位置)

SELECT * FROM table1, table2 WHERE table1.id = table2.id 
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
--[OR]
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id

--[Results:]
id | name | id   | name 
---+------+------+------
1  | a1   | 1    | a2
2  | b1   | Null | Null

FULL OUTER JOIN:
如果您还希望在结果中包含其他表格的所有行,则可以使用FULL OUTER JOIN

SELECT * FROM table1, table2 WHERE table1.id = table2.id
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
UNION ALL
SELECT Null, Null, * FROM table2 WHERE Not table2.id In (SELECT id FROM table1)
--[OR] (recommended for SQLite)
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
UNION ALL
SELECT * FROM table2 LEFT JOIN table1 ON table2.id = table1.id
WHERE table1.id IS NULL
--[OR]
SELECT * FROM table1 FULL OUTER JOIN table2 On table1.id = table2.id

--[Results:]
id   | name | id   | name 
-----+------+------+------
1    | a1   | 1    | a2
2    | b1   | Null | Null
Null | Null | 3    | b2

嗯,根据您的需要,您可以选择满足您需求的每一个;)。

答案 12 :(得分:31)

内部联接。

联接正在组合两个表中的行。 内部联接尝试根据您在查询中指定的条件匹配两个表,并仅返回匹配的行。如果连接中第一个表中的一行与第二个表中的两个行匹配,则结果中将返回两行。如果第一个表中的某行与第二个表中的行不匹配,则不会返回该行;同样,如果第二个表中的某行与第一个表中的行不匹配,则不会返回。

外部加入。

左连接尝试查找第一个表中的行与第二个表中的行的匹配。如果找不到匹配项,它将返回第一个表中的列,并将第二个表中的列留空(null)。

答案 13 :(得分:25)

在其他答案中,我没有看到关于性能和优化器的更多细节。

有时很高兴知道只有INNER JOIN是关联的,这意味着优化器最有可能使用它。它可以重新排序连接顺序,以便更快地保持相同的结果。优化器可以使用最多的连接模式。

通常,尝试使用INNER JOIN代替不同类型的连接是一种好习惯。 (当然,如果可以考虑预期的结果集。)

这里有一些关于这种奇怪的联想行为的好例子和解释:

答案 14 :(得分:22)

INNER JOINLEFT/RIGHT OUTER JOIN的精确算法如下:

  1. 从第一张表中获取每一行:a
  2. 考虑旁边第二个表格中的所有行:(a, b[i])
  3. 针对每对评估ON ...子句:ON( a, b[i] ) = true/false?
    • 当条件评估为true时,返回合并的行(a, b[i])
    • 当没有任何匹配到达第二个表的末尾时,这是Outer Join,然后使用Null为其他表的所有列返回(虚拟)对:{ {1}}用于LEFT外连接,(a, Null)用于RIGHT外连接。这是为了确保第一个表的所有行都存在于最终结果中。
  4. 注意: (Null, b)子句中指定的条件可以是任何内容,不需要使用主键(并且您不需要始终参考两个表中的列)!例如:

    Inner Join vs. Left Outer Join

    enter image description here

    注意:左连接=左外连接,右连接=右外连接。

答案 15 :(得分:20)

批评了备受喜爱的红色阴影维恩图,我认为发布自己的尝试是公平的。

尽管@Martin Smith的答案在很长一段时间内是最好的,但他只显示每个表中的键列,而我认为理想情况下也应该显示非键列。

在半小时内我能做的最好的事情,我仍然认为它没有充分显示由于TableB中缺少关键值或OUTER JOIN是空的,因此存在空值实际上是一个联盟而不是一个联盟:

enter image description here

答案 16 :(得分:19)

enter image description here

  • INNER JOIN两个或更多表的最典型连接。 它返回表ON主键和forignkey关系的数据匹配。
  • OUTER JOININNER JOIN相同,但它还包含有关ResultSet的NULL数据。
    • LEFT JOIN = INNER JOIN + 表格中无法匹配的数据与Null匹配在右表中。
    • RIGHT JOIN = INNER JOIN + 表格中无法匹配的数据,左表格中的Null匹配。
    • FULL JOIN = INNER JOIN + 右侧和左侧表中的Null匹配的数据不匹配。
  • 当表引用数据本身知道为自联接时,自联接不是SQL中的关键字。使用INNER JOINOUTER JOIN,我们可以编写自联接查询。

例如:

SELECT * 
FROM   tablea a 
       INNER JOIN tableb b 
               ON a.primary_key = b.foreign_key 
       INNER JOIN tablec c 
               ON b.primary_key = c.foreign_key 

答案 17 :(得分:17)

最简单的定义

内部联接:从两个表中返回匹配的记录

完全外部联接:从两个表中返回匹配的和不匹配的记录,对于来自两个表的不匹配记录,返回null。

左外连接:仅从左侧上的表格返回匹配和不匹配的记录。

右外连接:仅从右侧上的表格返回匹配和不匹配的记录。

在-短

匹配+左侧不匹配+右侧不匹配= 完全外部加入

匹配+左不匹配= 左外连接

匹配+右无匹配= 右外连接

匹配= 内部加入

答案 18 :(得分:6)

总体思路

请参阅answerMartin Smith,以更好地说明和解释不同的连接,包括尤其是FULL OUTER JOINRIGHT OUTER JOINLEFT OUTER JOIN之间的区别

这两个表格构成了以下JOIN的表示形式的基础:

Basis

交叉加入

CrossJoin

SELECT *
  FROM citizen
 CROSS JOIN postalcode

结果将是所有组合的笛卡尔乘积。不需要JOIN条件:

CrossJoinResult

内部加入

INNER JOIN与简单的含义相同:JOIN

InnerJoin

SELECT *
  FROM citizen    c
  JOIN postalcode p ON c.postal = p.postal

结果将是满足要求的JOIN条件的组合:

InnerJoinResult

左外联接

LEFT OUTER JOINLEFT JOIN

LeftJoin

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON c.postal = p.postal

即使citizen中没有匹配项,结果也将是postalcode中的所有内容。再次需要一个JOIN条件:

LeftJoinResult

播放数据

所有示例均已在Oracle 18c上运行。可在dbfiddle.uk上获得它们,这也是表格屏幕截图的来源。

CREATE TABLE citizen (id      NUMBER,
                      name    VARCHAR2(20),
                      postal  NUMBER,  -- <-- could do with a redesign to postalcode.id instead.
                      leader  NUMBER);

CREATE TABLE postalcode (id      NUMBER,
                         postal  NUMBER,
                         city    VARCHAR2(20),
                         area    VARCHAR2(20));

INSERT INTO citizen (id, name, postal, leader)
              SELECT 1, 'Smith', 2200,  null FROM DUAL
        UNION SELECT 2, 'Green', 31006, 1    FROM DUAL
        UNION SELECT 3, 'Jensen', 623,  1    FROM DUAL;

INSERT INTO postalcode (id, postal, city, area)
                 SELECT 1, 2200,     'BigCity',         'Geancy'  FROM DUAL
           UNION SELECT 2, 31006,    'SmallTown',       'Snizkim' FROM DUAL
           UNION SELECT 3, 31006,    'Settlement',      'Moon'    FROM DUAL  -- <-- Uuh-uhh.
           UNION SELECT 4, 78567390, 'LookoutTowerX89', 'Space'   FROM DUAL;

在玩JOINWHERE时的模糊边界

交叉加入

CROSS JOIN产生的行是The General Idea / INNER JOIN

SELECT *
  FROM citizen          c
  CROSS JOIN postalcode p
 WHERE c.postal = p.postal -- < -- The WHERE condition is limiting the resulting rows

使用CROSS JOIN获取LEFT OUTER JOIN的结果需要一些技巧,例如添加NULL行。省略了。

内部加入

INNER JOIN成为笛卡尔积。与一般想法/ CROSS JOIN相同:

SELECT *
  FROM citizen    c
  JOIN postalcode p ON 1 = 1  -- < -- The ON condition makes it a CROSS JOIN

在这里,内部联接实际上可以看作是交叉联接,其结果与除去的条件不匹配。这里没有任何结果行被删除。

使用INNER JOIN获取LEFT OUTER JOIN的结果也需要技巧。省略了。

左外联接

LEFT JOIN在行中显示为一般想法/ CROSS JOIN

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON 1 = 1 -- < -- The ON condition makes it a CROSS JOIN

LEFT JOIN在行中显示为The General Idea / INNER JOIN

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON c.postal = p.postal
 WHERE p.postal IS NOT NULL -- < -- removed the row where there's no mathcing result from postalcode

维恩图的麻烦

在“ sql join cross inner external”上的图像互联网搜索将显示大量的维恩图。我以前在桌子上有一个印刷版。但是表示存在问题。

Venn图对于集合论非常有用,其中一个元素可以在一个或两个集合中。但是对于数据库来说,在我看来,一个“集合”中的一个元素似乎是表中的一行,因此在其他任何表中也不存在。多个表中不存在一行。该表唯一的一行。

自连接是一种极端情况,其中两个元素中的每个元素实际上都相同。但是它仍然不能解决以下任何问题。

下面的集合A代表左侧的集合(citizen表,下面的集合B是右边的集合(postalcode表)讨论。

交叉加入

两个集合中的每个元素都与另一个集合中的每个元素匹配,这意味着我们需要每个A个元素B个数量和每个B个元素A个数量以正确表示该笛卡尔积。集合论不是针对集合中的多个相同元素建立的,因此我发现维恩图正确地表示它是不切实际/不可能的。似乎UNION完全不合适。

行是不同的。 UNION总共有7行。但是它们与常见的SQL结果集不兼容。这根本不是CROSS JOIN的工作方式:

CrossJoinUnion1

试图这样表示:

CrossJoinUnion2Crossing

..但是现在看起来像INTERSECTION,肯定是不是。此外,INTERSECTION中实际上没有两个不同集合中的任何元素。但是,它看起来非常像与此类似的可搜索结果:

CrossJoinUnionUnion3

作为参考,可以在Tutorialgateway看到CROSS JOIN的一个可搜索结果。 INTERSECTION就是空的。

内部加入

元素的值取决于JOIN条件。可以在每一行对该条件唯一的条件下表示这种情况。含义id=x仅对一个行有效。在A条件下,表citizenB)中的行与表postalcodeJOIN)中的多行匹配后,结果与以下问题相同CROSS JOIN:该行需要多次表示,而集合理论并没有真正做到这一点。在唯一性的条件下,该图可以工作,但是要记住JOIN条件决定了元素在图中的位置。仅查看JOIN条件的值,其余的行就顺其自然:

InnerJoinIntersection - Filled

当使用具有INNER JOIN条件的ON 1 = 1使其成为CROSS JOIN时,此表示形式完全崩溃。

使用自JOIN,行实际上是两个表中的标识元素,但是将表分别表示为AB并不是很合适。例如,使JOIN中的元素与B中的不同元素相匹配的常见自A条件是ON A.parent = B.child,从{{ 1}}至A在单独的元素上。在示例中,像这样的B

SQL

SelfJoinResult

意思是史密斯是格林和詹森的领导人。

外部加入

同样,当一行与另一张表中的行有多个匹配项时,麻烦就开始了。这更加复杂,因为SELECT * FROM citizen c1 JOIN citizen c2 ON c1.id = c2.leader 可以与空集匹配。但是在集合论中,任何集合OUTER JOIN与一个空集合的并集始终只是C。空集不添加任何内容。该C的表示形式通常只是显示LEFT OUTER JOIN的全部,以说明A中的行被选中,而不管A是否匹配。然而,“匹配元件”具有与以上图示相同的问题。它们取决于条件。空集似乎已经漂移到B

LeftJoinIntersection - Filled

WHERE子句-有意义

用史密斯和邮政编码在月球上找到A中的所有行:

CROSS JOIN

Where - result

现在,维恩图不再用于反映SELECT * FROM citizen c CROSS JOIN postalcode p WHERE c.name = 'Smith' AND p.area = 'Moon'; JOIN子句仅用于

Where

..这很有意义。

当INTERSECT和UNION有意义时

相交

正如所解释的,WHERE实际上不是INNER JOIN。但是INTERSECT可以用于单独查询的结果。这里的维恩图很有意义,因为来自单独查询的元素实际上是仅属于结果之一或两者都属于的行。显然,相交只会返回两个查询中都存在该行的结果。 INTERSECT的行与SQL上方的行相同,维恩图也将相同:

WHERE

UNION

SELECT * FROM citizen c CROSS JOIN postalcode p WHERE c.name = 'Smith' INTERSECT SELECT * FROM citizen c CROSS JOIN postalcode p WHERE p.area = 'Moon'; 不是OUTER JOIN。但是UNION在与UNION相同的条件下工作,导致返回所有结合了两个INTERSECT的结果:

SELECT

等效于:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
UNION
SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE p.area = 'Moon';

..并给出结果:

Union - Result

在这里维恩图也很有意义:

UNION

不适用时

重要说明是,只有当两个SELECT的结果的结构相同时才可以进行比较或并集,它们才起作用。这两个的结果将无法实现:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
   OR p.area = 'Moon';
SELECT *
  FROM citizen
 WHERE name = 'Smith'

..尝试将结果与SELECT * FROM postalcode WHERE area = 'Moon'; 合并会给出

UNION

有关更多信息,请阅读Say NO to Venn Diagrams When Explaining JOINssql joins as venn diagram。两者都覆盖ORA-01790: expression must have same datatype as corresponding expression

答案 19 :(得分:5)

简单来说,

1. INNER JOIN或EQUI JOIN:返回仅匹配两个表中条件的结果集。

2. OUTER JOIN:即使条件匹配与否,也返回两个表中所有值的结果集。

3. LEFT JOIN:返回左表中所有值的结果集,只返回与右表中的条件匹配的行。

4. RIGHT JOIN:返回右表中所有值的结果集,只返回与左表中的条件匹配的行。

5. 完全加入:完全加入和全外加入相同。

答案 20 :(得分:5)

SQL中主要有两种主要的JOIN类型:[INNER和OUTER]


示例

假设您有两个表,每个表都有一个列,数据如下:

A    B
-    -
1    3
2    4
3    5
4    6
7
8

请注意,(1,2,7,8)对于A是唯一的,(3,4)是常见的,而(5,6)对于B是唯一的。



  • (内部)加入

只要条件满足,INNER JOIN关键字就会从两个表中选择所有行。此关键字将通过组合两个表中满足条件的表中的所有行来创建结果集,即公共字段的值将相同。

INNER JOIN

select * from a INNER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b;

结果:

a | b
--+--
3 | 3
4 | 4


  • 左(外)联接

此联接返回联接左侧的表的所有行,以及联接右侧的表的匹配行。右侧没有匹配行的行,结果集将包含null。左联接也称为LEFT OUTER JOIN

LEFT JOIN / LEFT OUTER JOIN

select * from a LEFT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b(+);

结果:

a |  b
--+-----
1 | null
2 | null
3 |    3
4 |    4
7 | null
8 | null


  • 右(外)联接:从右表返回所有记录,并从左表返回匹配的记录

RIGHT JOIN / RIGHT OUTER JOIN

select * from a RIGHT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a(+) = b.b;

结果:

a    |  b
-----+----
3    |  3
4    |  4
null |  5
null |  6


  • 完全(外部)加入

    FULL JOIN通过组合LEFT JOIN和RIGHT JOIN的结果来创建结果集。结果集将包含两个表中的所有行。没有匹配的行,结果集将包含NULL值。

FULL JOIN / FULL OUTER JOIN

select * from a FULL OUTER JOIN b on a.a = b.b;

结果:

 a   |  b
-----+-----
   1 | null
   2 | null
   3 |    3
   4 |    4
null |    6
null |    5
   7 | null
   8 | null

答案 21 :(得分:4)

1. 内部加入:也称为加入。它返回Left表中的行,右表只返回,如果匹配。否则,它返回零记录。

示例:

SELECT
  e1.emp_name,
  e2.emp_salary    
FROM emp1 e1
INNER JOIN emp2 e2
  ON e1.emp_id = e2.emp_id

output1

2. 完全外部加入:也称为完全加入。它返回Left表和右表中的所有行

示例:

SELECT
  e1.emp_name,
  e2.emp_salary    
FROM emp1 e1
FULL OUTER JOIN emp2 e2
  ON e1.emp_id = e2.emp_id

output2

3. 左外连接:或简称为左连接。它返回Left表中存在的所有行以及右表中的匹配行(如果有)。

4. 右外连接:也称为右连接。它返回左表中的匹配行(如果有),以及Right表中的所有行。

joins

加入的优势

  1. 执行得更快。

答案 22 :(得分:3)

  • 内部联接 - 使用任意等效查询的内部联接会给出两个的交集,即两个他们有共同的行。

  • 左外连接 - 左外连接将提供A中的所有行以及B中的所有常见行。

  • 全外连接 - 完整外连接将为您提供A和B的并集,即A中的所有行和B中的所有行如果A中的某些东西在B中没有相应的数据,则B部分为空,反之亦然

答案 23 :(得分:3)

left join on(又名left outer join on)返回inner join onunion all无效的左表行,由空值扩展。

right join (on又名right outer join on)返回inner join onunion all无效的右表行,由空值扩展。

full join on(又名full outer join on)返回inner join onunion all不匹配的左表行,由空值union all扩展为空的无法匹配的右表行。

(SQL Standard 2006 SQL / Foundation 7.7语法规则1,一般规则1b,3 c&amp; d,5 b。)

所以不要outer join,直到你知道inner join所涉及的是什么。

找出what rows inner join returns

阅读我的评论那里有许多困惑和放大答案很差。

然后在这里阅读我的评论了很多困惑&amp;答案很差。

答案 24 :(得分:2)

使用示例更容易解释联接:

enter image description here

要模拟存储在单独表格中的人员和电子邮件,

表A和表B由Table_A连接。 id = Table_B。名称ID

内部加入

enter image description here

仅显示匹配ID的行。

外部联接

enter image description here

显示

表A 的匹配ID和不匹配的行。

enter image description here

显示

表B 的匹配ID和不匹配的行。

enter image description here 显示两个表中匹配的ID和不匹配的行。

注意:完全外部联接在MySQL上不可用

答案 25 :(得分:1)

内连接和外连接之间的区别如下:

  1. 内连接是基于匹配元组组合表的连接,而外连接是基于匹配和不匹配元组组合表的连接。
  2. 内部联接合并来自两个表的匹配行,其中省略了不匹配的行,而外部联接合并来自两个表的行,不匹配的行填充空值。
  3. 内连接就像交叉操作,而外连接就像一个联合操作。
  4. 内部联接是两种类型,而外部联接是三种类型。
  5. 内连接较慢,而外连接比内连接快。

答案 26 :(得分:0)

请考虑以下2个表格:

EMP

empid   name    dept_id salary
1       Rob     1       100
2       Mark    1       300
3       John    2       100
4       Mary    2       300
5       Bill    3       700
6       Jose    6       400

部门

deptid  name
1       IT
2       Accounts
3       Security
4       HR
5       R&D

内部加入:

在SQL查询中通常只写为 JOIN 。它仅返回表之间的匹配记录。

找出所有员工及其部门名称:

Select a.empid, a.name, b.name as dept_name
FROM emp a
JOIN department b
ON a.dept_id = b.deptid
;

empid   name    dept_name
1       Rob     IT
2       Mark    IT
3       John    Accounts
4       Mary    Accounts
5       Bill    Security

如上所见,由于输出的dept_id Jose在Department表中找不到匹配项,因此不会从输出的 EMP 中打印6。同样,部门表中不会打印HRR&D行,因为它们在Emp表中找不到匹配项。

因此,INNER JOIN或仅JOIN只返回匹配的行。

左加入:

这将返回LEFT表中的所有记录,并且仅返回RIGHT表中的匹配记录。

Select a.empid, a.name, b.name as dept_name
FROM emp a
LEFT JOIN department b
ON a.dept_id = b.deptid
;

empid   name    dept_name
1       Rob     IT
2       Mark    IT
3       John    Accounts
4       Mary    Accounts
5       Bill    Security
6       Jose    

因此,如果您观察到以上输出,则将打印LEFT表(Emp)中的所有记录,并仅打印RIGHT表中的匹配记录。

HRR&D行不会从部门表中打印出来,因为它们在dept_id的Emp表中找不到匹配项。

因此,LEFT JOIN返回Left表中的所有行,而仅返回Right表中的匹配行。

还可以检查DEMO here

答案 27 :(得分:-1)

演示

设置

跳入 psql 并创建一个包含猫和人类的小型数据库。 您可以直接复制粘贴整个部分。

CREATE DATABASE catdb;
\c catdb;
\pset null '[NULL]' -- how to display null values

CREATE TABLE humans (
  name text primary key
);
CREATE TABLE cats (
  human_name text references humans(name),
  name text
);

INSERT INTO humans (name)
VALUES ('Abe'), ('Ann'), ('Ben'), ('Jen');

INSERT INTO cats (human_name, name)
VALUES
('Abe', 'Axel'),
(NULL, 'Bitty'),
('Jen', 'Jellybean'),
('Jen', 'Juniper');

查询

这是一个我们将多次运行的查询,将 [SOMETHING JOIN] 更改为各种类型以查看结果。

SELECT
humans.name AS human_name,
cats.name AS cat_name
FROM humans
[SOMETHING JOIN] cats ON humans.name = cats.human_name
ORDER BY humans.name;

INNER JOIN 返回所有人猫对。 任何没有猫的人或没有人的猫都被排除在外。

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Jen        | Jellybean
 Jen        | Juniper

A FULL OUTER JOIN 返回所有人类和所有猫,如果两边都没有匹配项,则返回 NULL

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Ann        | [NULL]
 Ben        | [NULL]
 Jen        | Jellybean
 Jen        | Juniper
 [NULL]     | Bitty

A LEFT OUTER JOIN 返回所有人类(左表)。 任何没有猫的人都会在 NULL 列中得到 cat_name。 任何没有人类的猫都被排除在外。

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Ann        | [NULL]
 Ben        | [NULL]
 Jen        | Jellybean
 Jen        | Juniper

A RIGHT OUTER JOIN 返回所有猫(右表)。 任何没有人类的猫都会在 NULL 列中获得 human_name。 任何没有猫的人都被排除在外。

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Jen        | Jellybean
 Jen        | Juniper
 [NULL]     | Bitty

内部与外部

您可以看到,虽然 INNER JOIN 仅获取匹配对,但每种 OUTER 连接都包含一些不匹配的项目。

但是,实际的词 INNEROUTER 不需要出现在查询中:

  • JOIN 本身意味着 INNER
  • LEFT JOINRIGHT JOINOUTER JOIN 都表示 OUTER

答案 28 :(得分:-2)

这里有很多非常正确的relational algebra示例答案。这是一个非常简化的答案,可能对具有SQL编码难题的业余或新手编码员有所帮助。

基本上,查询JOIN通常可以归结为两种情况:

对于数据SELECT的{​​{1}}子集:

  • 根据数据库设计,当您要查找的必须相关数据A存在时,请使用INNER JOIN
  • 根据数据库设计,当您要查找的 MIGHT MIGHT NOT 相关数据B时使用LEFT JOIN