INNER JOIN,左/右外连接

时间:2014-11-14 05:38:33

标签: tsql

提前为长期问题道歉,但这样做只是为了学习: 我是SQL的新手,现在正在研究JOIN。使用INNER和OUTER JOIN时,我得到两种不同的行为。我所知道的是,INNER JOIN给出了一种交集类型的结果,同时只返回表中的公共行,并且(LEFT / RIGHT)OUTER JOIN输出LEFT或RIGHT表中的常用行和剩余行,分别取决于LEFT / RIGHT子句

在使用MS Training Kit并尝试解决此问题时:“练习2:在此练习中,您可以识别出现在一个表中但在另一个表中没有匹配的行。您将获得返回员工ID的任务从2008年2月12日未处理订单的HR.Employees表(在Sales.Orders表中)。使用以下内容编写三种不同的解决方案:连接,子查询和集合 运营商。要验证解决方案的有效性,您应该返回employeeID:1,2,3,5,7和9.“

我成功地使用子查询和设置运算符,但是JOIN返回了一些不期望的东西。我写了以下查询:

USE TSQL2012;
SELECT
    E.empid
FROM
    HR.Employees AS H
    JOIN Sales.Orders AS O
        ON H.empid = O.empid
        AND O.orderdate = '20080212'
    JOIN HR.Employees AS E
        ON E.empid <> H.empid

ORDER BY
    E.empid
;

我期待的结果为:1,2,3,5,7和9(6行) 但我得到的是:1,1,1,2,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8, 9,9,9(24行)

我尝试了一些视频,但无法理解INNER / OUTER JOIN的这一面。如果有人可以帮助JOIN的这一方,我将不胜感激,为什么会这样,在使用JOIN时我应该尝试理解什么。

4 个答案:

答案 0 :(得分:2)

你也可以使用左外连接来获得不匹配的

*** LEFT JOIN关键字返回左表(table1)中的所有行,右表(table2)中的匹配行。当没有匹配时,结果在右侧为NULL。

SELECT
    H.empid
FROM
    HR.Employees AS H
    LEFT OUTER JOIN Sales.Orders AS O
        ON H.empid = O.empid
        AND O.orderdate = '20080212'
 WHERE O.empid IS NULL    

以上脚本将返回未在指定日期处理订单的emp id

答案 1 :(得分:0)

USE TSQL2012;

SELECT
   distinct E.empid
FROM
    HR.Employees AS H
    JOIN Sales.Orders AS O
        ON H.empid = O.empid
        AND O.orderdate = '20080212'
    JOIN HR.Employees AS E
        ON E.empid <> H.empid

ORDER BY
    E.empid
;

答案 2 :(得分:0)

使用SQL JOIN时始终提醒自己的主要事项:

  1. INNER JOIN要求在连接中匹配,以便在INNER JOIN之前生成的结果集行保留在结果集中。如果找不到某一行的匹配项,则会从结果集中删除该行。
  2. 对于馈送到仅与一行匹配的INNER JOIN的行,仅传送送到结果集的该行的一个副本。
  3. 对于馈送到与多行匹配的INNER JOIN的行,该行将被多次传递,对于来自INNER JOIN表的每一行匹配一次。
  4. OUTER JOINs不会丢弃在结果集中输入的行,无论OUTER JOIN是否导致匹配。
  5. 就像INNER JOIN一样,如果OUTER JOIN与多行匹配,它将通过复制等于从OUTER JOIN表中匹配的行数的行来增加结果集中的行数。
  6. 问问自己“如果我在JOIN上没有匹配,我是否要丢弃该行?”如果答案为否,请使用OUTER JOIN。如果答案为是,请使用INNER JOIN。

    如果您不需要引用JOIN表中的任何列,请不要执行JOIN。相反,根据您使用的数据库引擎,使用WHERE EXISTS,WHERE NOT EXISTS,WHERE IN,WHERE NOT IN等等。不要依赖数据库引擎足够聪明,以丢弃结果集中JOIN产生的未引用列。有些数据库可能足够智能,有些则不行。没有理由将列拉入结果集只是为了不引用它们。这样做会增加性能降低的可能性。

    你的加入:

    JOIN HR.Employees AS E
        ON E.empid <> H.empid
    

    ...匹配所有带有DIFFERENT EMPID的Employees行,这些行包含到该连接的所有行。在INNER JOIN上使用NOT EQUAL是非常罕见的事情或需要,特别是如果JOIN谓词仅测试一个条件。这就是你在结果集中获得重复行的原因。

    在DB2上,我们可以执行EXCEPTION JOIN来单独使用JOIN来完成它。通常,在DB2上,我会使用WHERE NOT EXISTS。在SQL Server上,您可以对查询集执行JOIN,其中查询集是指定日期SALES.ORDERS中没有订单的所有员工,但我不知道这是否违反了教程的规则。

    Naveen发布了你的教程正在寻找的解决方案!

答案 3 :(得分:0)

在这里你可以看到所有类型的连接

enter image description here

图取自:http://dsin.wordpress.com/2013/03/16/sql-join-cheat-sheet/

将您的查询调整为此

   USE TSQL2012;
SELECT
    E.empid
FROM
    HR.Employees AS H
    JOIN Sales.Orders AS O
        ON H.empid = O.empid
        where O.orderdate = '2008-02-12' AND O.empid IN null
   ORDER BY
    E.empid
;