前言

本节我们继续讲讲联接类型中的外部联接,本节之后我们将讲述有关联接性能以及更深入的知识,简短内容,深入的理解,Always to review the basics。

外部联接

外部联接又分为左外部联接和右外部联接,使用关键字分别是LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN,在这里OUTER关键字时可选的。LEFT关键字表示保留左侧的行,RIGHT关键字表示保留右侧的行,FULL关键字表示左侧和右侧的行都保留。外部联接的第三个逻辑查询处理阶段识别保留表中基于ON谓词未能与另一个表匹配的行,此阶段添加这些行到前两个联接阶段生成的结果中,在这些外部行中,对于联接非保留侧的属性将使用NULL作为占位符。说了这么多,左外部联接就是以左表为基准,若右表满足条件则返回右侧的行,若不满足则返回NULL而非右侧的实际行数据,右外部联接同理。我们来看如下一个简单的例子

USE TSQL2012
GOSELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid

从上知,Sales.Customers表中的有一个客户没有任何订单,它的订单Id为22,通过左侧客户Id为22而右侧得到订单Id为NULL而得知。

超越外部联接基础知识

通过上述对外部联接的介绍,我们知道通过外部联接能够得到缺失值,也就是不满足条件则返回NULL。这里我们假设有如下一场景,我们需要查询Orders订单表中所有订单,要求确保在范围2006年1月1日至2008年12月31日中每天至少有一行输出,对于范围能具有的订单的日期不做任何操作,但希望输出中包含没有订单的日期,使用NULL标记作为订单属性占位符。我们第一步需要解决的是得到2006年1月1日至2008年12月31日的所有日期,上一篇我们讲过交叉联接,通过交叉联接我们生成了数字表,这个时候就派上用场了。

首先需要得到2006年1月1日至2008年12月31日之间间隔的天数,然后得到此间隔中的所有日期,如下:

USE TSQL2012
GOSELECT DATEADD(DAY, n -1 ,'20060101') AS orderdate
FROM dbo.Nums
WHERE n <= DATEDIFF(DAY, '20060101','20081231') + 1
ORDER BY orderdate

接下来通过上述得到的连续日期与Sales.Orders表中的订单日期进行匹配,从而得到订单所有信息,利用左外部联接不满足条件则返回NULL。

USE TSQL2012
GOSELECT DATEADD(DAY, n -1 ,'20060101') AS orderdate,O.orderid,O.custid, O.empid
FROM dbo.NumsLEFT JOIN Sales.Orders AS OON DATEADD(DAY, dbo.Nums.n - 1, '20060101') = O.orderdate
WHERE dbo.Nums.n <= DATEDIFF(DAY, '20060101','20081231') + 1
ORDER BY orderdate

外部联接注意事项 (1)

(1)WHERE造成外部联接成为逻辑上的内部联接

我们看上述图中在订单日期等于2006-11-09时,此时orderid为NULL,此时我们首先来进行如下查询

USE TSQL2012
GOSELECT orderdate, orderid, custid, empid
FROM Sales.Orders
WHERE orderdate > '20061108'

我们查询Sales.Orders表中订单日期大于2006-11-08订单信息,我们看下返回结果

此时我们发现订单日期为2006-11-09的订单信息没有,为何如此呢,因为利用WHERE子句它会过滤掉UNKNOWN即NULL值,为什么要讲这个呢,因为在外部联接中不满足条件的右表原本会返回NULL,但是若存在WHERE子句时,此时会导致所有外部行会被过滤掉,换句话说就是抵消了外部联接实际上在逻辑上就相当于是一个内部联接,这就在无意中造成了逻辑上的BUG。所以基于此我们可以得出如下结论:

结论:在外部联接中若利用WHERE子句会过滤掉NULL,会导致所有外部行被过滤掉,实际上会抵消外部联接,最终外部联接在逻辑上就成为了一个内部联接。

(2)多表联接造成外部联接成为逻辑上的内部联接

在进行多联接时比如说首先进行两个表的外部联接,紧接着后面跟了一个内部联接的第三个表,如果内部联接中子句的谓词对自外部联接非保留侧的属性和来自第三个表的属性进行比较,此时所有外部行都会被过滤掉。是什么意思呢,当利用外部联接时会可能返回外部行的NULL值,此时再利用内部联接,因为NULL与任何值进行比较都会生成UNKNOWN,所以此时UNKNOWN会被ON筛选过滤掉。同上也就抵消外部联接,造成外部联接成为逻辑上的内部联接。如下

USE TSQL2012
GOSELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON O.custid = C.custidINNER JOIN Sales.OrderDetails AS OD ON OD.orderid = O.orderid

一般来说,无论何种类型的外部联接后跟一个内部联接或是外部联接子查询,外部行都会被过滤掉,当然,这是假设联接条件对来自左侧的NULL标记和右侧的任意值进行比较。为了解决这种问题,我们可以通过如下三种方案来解决。

【1】将第二个内部联接替换为左外部联接。

USE TSQL2012
GOSELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON O.custid = C.custidLEFT JOIN Sales.OrderDetails AS OD ON OD.orderid = O.orderid

【2】首先使用内部联接,然后再使用右外部联接。

SELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Orders AS OLEFT JOIN Sales.OrderDetails AS OD ON OD.orderid = O.orderidINNER JOIN Sales.Customers AS C ON O.custid = C.custid

【3】在原有基础上改变,将内部联接变成一个独立的逻辑阶段

USE TSQL2012
GOSELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS CLEFT JOIN (Sales.Orders AS O INNER JOIN Sales.OrderDetails AS OD ON O.orderid = OD.orderid)ON C.custid = O.custid

外部联接注意事项 (2)

在外部联接中使用COUNT(*)进行聚合时,它会考虑内部行和外部行,因为它会计算行数而不管它们的内容,如下:

USE TSQL2012
GOSELECT C.custid, COUNT(*) AS numorders
FROM Sales.Customers AS CLEFT JOIN  Sales.Orders AS O ON O.custid = C.custid
GROUP BY C.custid

由之前所查得知客户Id为22的orderid为NULL,即没有订单数量,所以这里就产生了BUG,因为COUNT(*)会包括NULL值,所以这里我们需要替换为COUNT(列名)。

USE TSQL2012
GOSELECT C.custid, COUNT(O.orderid) AS numorders
FROM Sales.Customers AS CLEFT JOIN  Sales.Orders AS O ON O.custid = C.custid
GROUP BY C.custid

总结

本节我们重点讲述了外部联接基本知识以及注意事项,我们下节将讲述联接综合知识,简短的内容,深入的理解,我们下节再会,good night。

SQL Server-外部联接基础回顾(十三)相关推荐

  1. 图书推荐:SQL Server 2012 T-SQL基础教程 Itzik Ben-Gan

    经过近三个月的不懈努力,终于翻译完毕了.图书虽然是基础知识,但是,即使你已经使用T-SQL几年,很多地方还是能够弥补你的知识空白.大师级的人物写基础知识,或许你想知道这基础中还有哪些深奥,敬请期待吧. ...

  2. SQL Server更新联接概述

    This article explores the SQL Server Update Join statement in T-SQL for SQL Server. 本文探讨了T-SQL for S ...

  3. SQL Server-外部联接基础

    外部联接 外部联接又分为左外部联接和右外部联接,使用关键字分别是LEFT OUTER JOIN.RIGHT OUTER JOIN.FULL OUTER JOIN,在这里OUTER关键字时可选的.LEF ...

  4. SQL Server内存架构基础

    SQL Server内存架构基础 翻译自: https://mssqlwiki.com/sqlwiki/sql-performance/basics-of-sql-server-memory-arch ...

  5. SQL Server外部链接时报错:Error locating serverInstance specified

    SQL Server外部链接时报错:Error locating server/Instance specified 连接时报错信息: 08001 sql server network interfa ...

  6. MS SQL Server 数据库(基础篇)

    SQL Server数据库 1.0 数据库及数据库系统 1.1数据库是什么 1.2 数据库系统(DBS) 1.3 数据库管理系统(DBMS) 1.4 数据库的作用 1.5 应用程序 1.6 注 2.0 ...

  7. SQL数据恢复总结 - sql server 2012数据库基础-数据恢复-实验报告

    数据恢复是对数据库进行备份和还原,当数据库因为各种原因被损坏或者无法读取的时候,会造成无法估量的后果,这个时候就需要数据库还原工具,进行还原. 数据库故障分为"软故障"和" ...

  8. SQL Server 2008从基础开始学习的历程(1)------创建表与查询

    [by:yy] 无论我们学什么呢,都要讲究一个Why,一个How.那么我们为什么要学SQL呢?无非就那么几点. 1.为了适应其他技术,和其他技术配对而学. 我个人的理解呢,只要在IT行业,无论你学什么 ...

  9. 《SQL Server 2012 T-SQL基础》读书笔记 - 1.背景

    几个缩写的全称:Data Definition Language (DDL), Data Manipulation Language (DML), and Data Control Language ...

最新文章

  1. Linux memcached 安装
  2. python【力扣LeetCode算法题库】面试题40- 最小的k个数
  3. CF1354F. Summoning Minions
  4. jdk8运行jdk7的代码_即使在jdk中也有错误的代码
  5. httpurlconnect设置中文参数_数控三菱CNC机床参数的设置及报警解除!
  6. Android Camera调用流程
  7. 剑指Offer - 面试题33. 二叉搜索树的后序遍历序列(递归)
  8. oracle中block
  9. doubango播放不均匀的问题及改进办法
  10. F2FS文件系统一 设计背景及框架结构
  11. DNS、NS、DDNS
  12. 高德地图JSAPI点位相关操作
  13. 微信小程序商品跳转到第三方
  14. 攻防世界-logmein
  15. wangEditor上传不了图片
  16. 怎样练出完美肌肉:[2]完美背肌
  17. MySQL 插入语句
  18. [原创]我个人整理的AD/2000技巧,各位收藏吧!60多个。
  19. 高位缩量横盘的实战价值
  20. OData介绍 (SAP)

热门文章

  1. Android Studio运行报错:无法访问XXX......请删除该文件或确保该文件位于正确的类路径子目录中
  2. python爬虫06 | 你的第一个爬虫,爬取当当网 Top 500 本五星好评书籍
  3. jms、amqp、mqtt区别与联系
  4. 杭电OJ-1062_Text Reverse
  5. MyEclipse中导入Spring 4.0源码
  6. C# 操作ACCESS数据库
  7. wince驱动异常调试方法(作者:wogoyixikexie@gliet)
  8. 快速了解 MySQL 的性能优化
  9. Spark 资源调度及任务调度
  10. MySQL表完整性约束