SQL SERVER技术内幕之3 联接查询

    JOIN表运算符对两个输入表进行操作。联接有三种基本类型:交叉联接、内联接和外联接。这三种联接的区别是它们采用的逻辑查询处理步骤各不相同,每种联接都有一套不同的步骤。交叉联接只有一个步骤----笛卡尔积;内联接有两个步骤----笛卡尔积、过滤;外联接有三个步骤----笛卡尔积、过滤、添加外部行。

3.1 交叉联接

SQL SERVER支持交叉联接的两种标准语法:ANSI SQL-92和ANSI SQL-89,推荐使用SQL-92的语法。

3.1.1 ANSI SQL-92语法

SELECT C.custid, E.empid
FROM Sales.Customers AS C
  CROSS JOIN HR.Employees AS E;

使用ANSI SQL-92语法,要在参与联接的两个表之间使用"CROSS JOIN"关键字

3.1.2 ANSI SQL-89语法

SELECT C.custid, E.empid
FROM Sales.Customers AS C, HR.Employees AS E;

在这种语法中,只要简单地在表名之间加个逗号。

3.2 内联接

3.2.1 ANSI SQL-92

SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
  JOIN Sales.Orders AS O
    ON E.empid = O.empid;

使用ANSI SQL-92语法,须在两个表名之间指定INNER JOIN关键字,INNER关键字是可选的,因为内联接是默认的联接方式。ON子句用于对行进行过滤,只返回计算结果为True的行,而不会返回令计算结果为False或UnKnown的行。

3.2.2 ANSI SQL-89

SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O
WHERE E.empid = O.empid;

内联接也可以用ANSI SQL-89语法来表达,可以像交叉联接那样在表名之间放一个逗号,然后用WHERE子句定义联接条件。

3.2.3 为什么推荐使用ANSI SQL-92语法

    1.假如你想写一条内联接查询,但不小心忘记指定联接条件,如果这时使用的是ANSI SQL-89语法,那么运行时不会出现异常信息,但执行的却是一个交叉查询。但如果此时使用的是ANSI SQL-92语法,那么语法分析器会报错。

    2.假如你想写一条交叉联接查询,如果这时使用的是ANSI SQL-89语法,之后其他开发人员在查看或维护你的代码时,那么他们怎么会知道你想写的是一条交叉联接语句还是想写一条内联接语句,但却忘记了指定联接条件呢。但是如果你使用ANSI SQL-92语法,显示使用CROSS JOIN关键字,那么就可以显式的表达你想执行的是一条交叉联接。

3.3 外联接

    外联接会应用内联接所应用的两个逻辑处理步骤(笛卡尔积和ON过滤),此外还多加一个外联接特有的第三步:添加外部行。在外联接中,要把一个表标记为"保留的表",可以在表名之间使用关键字 LEFT OUTER JOIN 、RIGHT OUTER JOIN 以及FULL OUTER JOIN,其中OUTER关键字是可选的。LEFT关键字表示左边表的行是保留的,RIGHT表示右边表的行是保留的,而FULL则表示左右两边表的行都是保留的。

    外联接的第三个步骤就是要识别保留表中按照ON条件在另一个表找不到与之匹配的那些行,再把这些行添加到联接的前两个步骤生成的结果表中,对于来自联接的非保留表的那些列,追加的外部行中这些列则用NULL作为占位符。

    以下的查询根据客户表的客户ID和订单表的客户ID对Customer表和Orders表进行联接,并返回客户和他们的订单信息。查询语句使用的联接类型是左外联接,所以查询结果也会返回那些没有发出任何订单的客户。

SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid;

    假如现在只需要返回没有下任何订单的客户,或者用更技术性的话来讲,只需要返回外部行。则可以用下面的查询进行处理

SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid 
WHERE O.orderid IS NULL;

    返回外部行时,选择哪个列作为过滤器也很重要。应该选择只在外部行才取值为NULL,而在其他行取值不为NULL的某个列。有三种情形可以考虑安全地使用:主键列、联接列以及定义为NOT NULL的列。主键的列值不能为NULL,因此如果这样的列上出现了NULL,就意味着该行为外部行。如果某行的联接列为NULL值,则该行在联接的第二步就会被过滤掉,所以如果某行的联接列的值为NULL,则说明该行为外部行。同理,定义为NOT NULL的列上出现了NULL值,则该行明显也为外部行。

原文地址:https://www.cnblogs.com/JustYong/p/4451832.html