Chapter 3 Joins

Cross Joins(交叉联接)就是返回两个表的笛卡尔积(m行的表cross join一个n行的表得到一个m * n行的结果),它有两种标准SQL语法,第一种:

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

第二种:

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

你也可以对同一个表的多个实例进行联接,这种self join对cross joins, inner joins, 和outer join都适用。有这么一个技巧:首先创建一个表Digits,它只有一列digit,值是0到9,然后如果你要输出1到1000,那么可以这样:

SELECT D3.digit * 100 + D2.digit * 10 + D1.digit + 1 AS n
FROM dbo.Digits AS D1
CROSS JOIN dbo.Digits AS D2
CROSS JOIN dbo.Digits AS D3
ORDER BY n;

Inner Joins(内联接)有两个逻辑上的处理阶段:首先算出笛卡尔积,然后根据你指定的谓词对结果的行进行过滤。它同样有两种标准SQL的语法,第一种:

SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
JOIN Sales.Orders AS O --因为inner join是默认,所以INNER可以省略
ON E.empid = O.empid;

对这种一对多的内联接,其实可以想成就是对每一行employee都对应很多行有相同employee ID的orders行。这里的ON与WHERE和HAVING一样,只接受TRUE而不接受FALSE或UNKNOWN。

第二种语法:

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

其实只是把第一种语法的ON移到了WHERE里面去,本质都一样。对于Cross Joins和Inner Joins,作者都建议第一种语法,因为意图更清晰,不容易出错。

连接条件也可以是多个的,例如:

FROM dbo.Table1 AS T1
JOIN dbo.Table2 AS T2
ON T1.col1 = T2.col1
AND T1.col2 = T2.col2

一般运用于这种情况:有个一对多的关系,而“一”的表的主键是基于多个列的,比如(orderid, productid),然后那个“多”的表肯定就要有一个外键来引用这个“一”的表的主键了对吧?(外键也能基于不止一个列)。我的理解是:如果在外键的那个表中如果添加了一行,外键的那两个列(比如就两列)的值必须是主键的那个表中已经存在的任意一行的那两个列的值,所以我推测字段的顺序必须一样,必须:FOREIGN KEY(orderid, productid) REFERENCES Sales.OrderDetails(orderid, productid),而不能FOREIGN KEY(productid, orderid) REFERENCES Sales.OrderDetails(orderid, productid)。所以在联接的时候就要这样:ON OD.orderid = ODA.orderid AND OD.productid = ODA.productid)。

联接条件也可以不是等于号:

SELECT
E1.empid, E1.firstname, E1.lastname,
E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
JOIN HR.Employees AS E2
ON E1.empid < E2.empid;

这样的话会去掉self pairs (for example,1 with 1)和mirrored pairs (for example, 1 with 2 and also 2 with 1),于是得到雇员id之间的唯一的一对一配对。

Outer Joins(外联接)

有三种,虽然后两种都不常用:LEFT OUTER JOIN,RIGHT OUTER JOIN, FULL OUTER JOIN。RIGHT就是保留右边的全部的行,FULL就是左右两边的表都保留,OUTER可以省略。外联接相比内联接又多加了一步的处理,就是在笛卡尔积并且过滤结果后,又把要保留的那个表的一些行加进来了,这些行我们叫它outer row(外部行)。

如果你要在外联接的结果中选出所有外部行,就:

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

注意,这里除了可以选择O.orderid(因为它用作ON上)作为WHERE中的条件,也可以选择在不被保留的表(这里就是Sales.Orders)里面不为NULL的字段,或者主键(因为主键不为NULL)。

打印出介于某两个日期之间的所有日期:

SELECT DATEADD(day, n-1, '20060101') AS orderdate
FROM dbo.Nums
WHERE n <= DATEDIFF(day, '20060101', '20081231') + 1
ORDER BY orderdate;

这里的dbo.Nums是1,2,3,4,5,6……越大越好。

如果想查出Orders表中,对于以上日期的每一天的订单情况(包括没有订单的情况):

SELECT DATEADD(day, Nums.n - 1, '20060101') AS orderdate,
O.orderid, O.custid, O.empid
FROM dbo.Nums
LEFT OUTER JOIN Sales.Orders AS O
ON DATEADD(day, Nums.n - 1, '20060101') = O.orderdate
WHERE Nums.n <= DATEDIFF(day, '20060101', '20081231') + 1
ORDER BY orderdate;

其实这里的日期计算函数只是为了把连续的Nums映射到连续的日期,然后对每一个日期都保留。

关于外联接有个常见的错误,就是如果你在WHERE中用非保留的表中的列作为过滤条件的话,那么就等于内联接,例如:

SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid
WHERE O.orderdate >= '20070101';

这样的话会把所有orderdate为NULL的外部行也过滤掉,那你还不如改成Inner join。

另一种常见错误是:

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

注意,第一次Outer Join之后,可能会有orderid是null的行,结果第二次inner join之后,这些行就绝逼被过滤掉了。解决方法是要么就两次outer join,要么就先inner join后面两个表,然后在right outer join第一个表,或者也可以把“inner join后面两个表”用括号括起来,再用第一个表Left join它们。

另一个常见错误:

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

还记得COUNT(*)会返回包括NULL的列吗,所以说这里就算有个顾客没有订单,也会算他的订单是一个。所以说记得用COUNT(O.orderid)。

《SQL Server 2012 T-SQL基础》读书笔记 - 3.联接查询的更多相关文章

  1. SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions

    这一章主要是介绍 窗体中的 Aggregate 函数, Rank 函数, Distribution 函数以及 Offset 函数. Window Aggregate 函数 Window Aggrega ...

  2. SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第1部分)

    为了缩小读取操作所涉及范围,本文首先着眼于简单的SELECT查询,然后引入执行更新操作有关的附加过程.最后你会读到,优化性能时SQLServer使用还原工具的相关术语和流程. 关系和存储引擎 如图所示 ...

  3. SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第2部分)

    计划缓存(Plan Cache) 如果SQL Server已经找到一个好的方式去执行一段代码时,应该把它作为随后的请求重用,因为生成执行计划是耗费时间且资源密集的,这样做是有有意义的. 如果没找到被缓 ...

  4. SQL Sever 各版本下载 SQL Server 2012下载SQL Server 2008下载SQL Server 2005

    SQL Server 2012SQL Server 2012 开发版(DVD)(X64,X86)(中文简体)ed2k://|file|cn_sql_server_2012_developer_edit ...

  5. sql server 2012 导出sql文件

    导出表数据和表结构sql文件 在工作中,经常需要导出某个数据库中,某些表数据:或者,需要对某个表的结构,数据进行修改的时候,就需要在数据库中导出表的sql结构,包括该表的建表语句和数据存储语句!在这个 ...

  6. SQL Server Window Function 窗体函数读书笔记一 - SQL Windowing

    SQL Server 窗体函数主要用来处理由 OVER 子句定义的行集, 主要用来分析和处理 Running totals Moving averages Gaps and islands 先看一个简 ...

  7. SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第3部分)(完结)

    一个简单的更新查询 现在应该知道只读取数据的查询生命周期,下一步来认定当你需要更新数据时会发生什么.这个部分通过看一个简单的UPDATE查询,修改刚才例子里读取的数据,来回答. 庆幸的是,直到存取方法 ...

  8. SQL Server 2012 - 动态SQL查询

    动态SQL的两种执行方式:EXEC @sql 和 EXEC sys.sp_executesql @sql DECLARE @c_ids VARCHAR(200) SET @c_ids ='1,2' - ...

  9. SQL Server 2012 - 数据库的基础操作

    数据库基本操作 --新建数据库卡 use master go create database SchoolDB on ( Name=SchoolDB, FileName='D;\DB\SchoolDB ...

随机推荐

  1. [转帖]安全公告【安全公告】CVE-2019-0708远程桌面服务远程代码执行漏洞

    [安全公告]CVE-2019-0708远程桌面服务远程代码执行漏洞 https://www.landui.com/help/nshow-9716.html 漏洞层出不穷 漏洞信息: 2019年5月14 ...

  2. kafka 安装教程

    安装详述: https://www.jianshu.com/p/596f107e901a 3.0:运行:cd 到: D:\Installed_software\Professional\kafka_2 ...

  3. Windows node.js安装运行npm显示类似"ENOENT, stat 'C:\Users\XXXX\AppData\Roaming\npm'错误

    这个错误是在玩一个小的博客的时候,使用到node.js,正好使用的是windows系统就安装了一个windows32的node.js版本 结果一运行npm就出现如上的错误,后来发现,只要在上面提到的目 ...

  4. ES5中的继承

    继承 在面向对象的语言中, 大多语言都支持两种继承方式: 接口继承 和 实现继承, 接口继承 只继承方法签名, 实现继承 才继承实际的方法, ECMAScript 值支持 实现继承, 今天我们来谈谈实 ...

  5. CentOS 8 下 nginx 服务器安装及配置笔记

    参考文档 nginx官方文档 安装 在CentOS下,nginx官方提供了安装包可以安装 首先先安装前置软件 sudo yum install yum-utils 然后将nginx官方源加入到yum源 ...

  6. python爬取b站排行榜

    爬取b站排行榜并存到mysql中 目的 b站是我平时看得最多的一个网站,最近接到了一个爬虫的课设.首先要选择一个网站,并对其进行爬取,最后将该网站的数据存储并使其可视化. 网站的结构 目标网站:bil ...

  7. Coding 地址

    Coding 连接 https://dev.tencent.com/u/leexi

  8. Simpsons’ Hidden Talents

    Homer: Marge, I just figured out a way to discover some of the talents we weren’t aware we had. Marg ...

  9. 同一台电脑管理多个SSH KEY

    同一台电脑关于多个SSH KEY管理 笔者之前为电脑中的homestead虚拟机配置过id_rsa,但现在因为想在github上搭建基于hexo的博客,所以需要配置github的ssh key,因此产 ...

  10. 03: django进阶篇

    1.1 cookie 1.cookie简介 1. cookie实质就是客户端硬盘中存放的键值对,利用这个特性可以用来做用户验证 2. 比如:{“username”: “dachengzi”} #再次访 ...