SQL Server-外部联接基础回顾(十三)

前言

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

外部联接

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

USE TSQL2012
GO

SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
    LEFT 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
GO

SELECT 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
GO

SELECT DATEADD(DAY, n -1 ,‘20060101‘) AS orderdate,O.orderid,
    O.custid, O.empid
FROM dbo.Nums
    LEFT JOIN Sales.Orders AS O
    ON 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
GO

SELECT 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
GO

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

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

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

USE TSQL2012
GO

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

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

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

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

USE TSQL2012
GO

SELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS C
 LEFT 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
GO

SELECT C.custid, COUNT(*) AS numorders
FROM Sales.Customers AS C
 LEFT JOIN  Sales.Orders AS O ON O.custid = C.custid
GROUP BY C.custid

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

USE TSQL2012
GO

SELECT C.custid, COUNT(O.orderid) AS numorders
FROM Sales.Customers AS C
 LEFT JOIN  Sales.Orders AS O ON O.custid = C.custid
GROUP BY C.custid

总结

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

时间: 2024-10-12 03:39:39

SQL Server-外部联接基础回顾(十三)的相关文章

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

[by:yy] 无论我们学什么呢,都要讲究一个Why,一个How.那么我们为什么要学SQL呢?无非就那么几点. 1.为了适应其他技术,和其他技术配对而学. 我个人的理解呢,只要在IT行业,无论你学什么,或者做什么工作.都离不开数据库.而学习数据库呢,又太文字化了,看的心里就烦.我是很抵触文字的.看着一大排一大排的字,就怕.可能是大天朝的教育所致.已经怕了学生生涯了. 2.为了适应社会而学. 随便找个招聘信息,都会有标注需要会SQL语言啊.了解MySql呀.会搞Oracle呀.所以呢,为了能在找工

SQL Server-交叉联接、内部联接基础回顾(十二)

前言 本节开始我们进入联接学习,关于连接这一块涉及的内容比较多,我们一步一步循序渐进学习,简短内容,深入的理解. 交叉联接(CROSS JOIN) 交叉连接是最简单的联接类型.交叉联接仅执行一个逻辑查询处理阶段-笛卡尔乘积.例如对两个输入表进行操作,联接并生成两个表的笛卡尔乘积,也就是说,将一个表的每一行与另一个表的所有行进行匹配.所以,如果一个表有m行,另一个表有n行,得到的结果中则会有m*n行.我们就拿SQL Server 2012教程中的例子说下 SELECT C.custid, E.em

SQL Server 存储过程之基础知识(转)

什么是存储过程呢?存储过程就是作为可执行对象存放在数据库中的一个或多个SQL命令. 通俗来讲:存储过程其实就是能完成一定操作的一组SQL语句. 那为什么要用存储过程呢?1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度.2.当对数据库进行复杂操作时,可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用.3.存储过程可以重复使用,可减少数据库开发人员的工作量.4.安全性高,可设定只有某些用户

SQL Server调优基础系列 - 性能调优介绍

前言 关于SQL Server调优系列是一个庞大的内容体系,非一言两语能够分析清楚,本篇先就在SQL 调优中所最常用的查询计划进行解析,力图做好基础的掌握,夯实基本功!而后再谈谈整体的语句调优. 通过本篇了解如何阅读和理解查询计划.并且列举一系列最常用的查询执行运算符. 技术准备 基于SQL Server2008R2版本,利用微软的一个更简洁的案例库(Northwind)进行解析. 一.区别不同的运算符 在所有T-SQL语句在执行的时候,都会将语句分解为一些基本的结构单元,这些结构单元统称为:运

SQL Server数据仓库的基础架构规划

问题 SQL Server数据仓库具有自己的特征和行为属性,有别去其他.从这个意义上说,数据仓库基础架构规划需要与标准SQL Server OLTP数据库系统的规划不同.在本文中,我们将介绍在计划数据仓库时应该考虑的一些事项. 解决 SQL Server 数据仓库系统参数 数据仓库本身有自己的参数,因此每个数据仓库系统都有自己独特的特性.在决定数据仓库系统的基础结构时,必须评估许多参数.在这些参数中,主要参数是数据量.报告复杂性.用户.系统可用性和ETL. 数据量 正如你可能知道的,数据量是大数

SQL Server 2012 T-SQL基础教程--T-SQL查询和编程的背景

理论背景 1. SQL:Structured Query Language, 是RDBMS(Relational Database Management Systems)的查询和管理数据的标准语言. 2. 理解集合理论和谓词逻辑,RDBMS基于这两个数学分支. 3. SQL语句类别: Data Definition Language, DDL:数据定义语言,处理对象的定义,包括诸如create.alter和drop等语句. Data Manipulation Language,DML:数据操作语

SQL Server(1)数据库基础

一.数据库能够做什么 1.存储大量的数据. 2.保持数据信息的一致.完整. 3.共享和安全. 4.通过组合分析,产生新的有用信息. 二.数据库的基本概念 1.数据库就是"数据"的"仓库". 2.数据库中包含表.关系以及操作对象. 3.数据存放在表中. 三.数据完整性 原文地址:https://www.cnblogs.com/cainiaojinxingshi/p/10051021.html

联接 (SQL Server)

SQL Server 使用内存中的排序和哈希联接技术执行排序.交集.并集.差分等操作. SQL Server 利用这种类型的查询计划支持垂直表分区(有时称为分列存储). SQL Server 使用三种类型的联接操作: 嵌套循环联接 合并联接 哈希联接 联接基础知识 通过联接,可以从两个或多个表中根据各个表之间的逻辑关系来检索数据. 联接指明了 Microsoft SQL Server 应如何使用一个表中的数据来选择另一个表中的行. 联接条件可通过以下方式定义两个表在查询中的关联方式: 指定每个表

管理SQL Server AlwaysOn(1)——基础维护

本文属于管理SQL Server AlwaysOn系列文章 前言: 前面系列已经介绍了SQL Server AlwaysOn的知识点.安装演示及注意事项等.但是这并不是终点,更多的反而是起点.就像不能生了孩子就不管,你还得养(管理).作为DBA,更多的工作内容恰恰就是管理AlwaysOn.所以这里单独列出一个系列介绍SQL Server AlwaysOn的管理.本系列沿用从0开始部署基础的AlwaysOn 的环境. 在这个系列中,准备讲述以下内容: 管理SQL Server AlwaysOn(1