《SQL Server 2012 T-SQL基础》读书笔记 - 3.联接查询
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.联接查询的更多相关文章
- SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions
这一章主要是介绍 窗体中的 Aggregate 函数, Rank 函数, Distribution 函数以及 Offset 函数. Window Aggregate 函数 Window Aggrega ...
- SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第1部分)
为了缩小读取操作所涉及范围,本文首先着眼于简单的SELECT查询,然后引入执行更新操作有关的附加过程.最后你会读到,优化性能时SQLServer使用还原工具的相关术语和流程. 关系和存储引擎 如图所示 ...
- SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第2部分)
计划缓存(Plan Cache) 如果SQL Server已经找到一个好的方式去执行一段代码时,应该把它作为随后的请求重用,因为生成执行计划是耗费时间且资源密集的,这样做是有有意义的. 如果没找到被缓 ...
- 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 ...
- sql server 2012 导出sql文件
导出表数据和表结构sql文件 在工作中,经常需要导出某个数据库中,某些表数据:或者,需要对某个表的结构,数据进行修改的时候,就需要在数据库中导出表的sql结构,包括该表的建表语句和数据存储语句!在这个 ...
- SQL Server Window Function 窗体函数读书笔记一 - SQL Windowing
SQL Server 窗体函数主要用来处理由 OVER 子句定义的行集, 主要用来分析和处理 Running totals Moving averages Gaps and islands 先看一个简 ...
- SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第3部分)(完结)
一个简单的更新查询 现在应该知道只读取数据的查询生命周期,下一步来认定当你需要更新数据时会发生什么.这个部分通过看一个简单的UPDATE查询,修改刚才例子里读取的数据,来回答. 庆幸的是,直到存取方法 ...
- SQL Server 2012 - 动态SQL查询
动态SQL的两种执行方式:EXEC @sql 和 EXEC sys.sp_executesql @sql DECLARE @c_ids VARCHAR(200) SET @c_ids ='1,2' - ...
- SQL Server 2012 - 数据库的基础操作
数据库基本操作 --新建数据库卡 use master go create database SchoolDB on ( Name=SchoolDB, FileName='D;\DB\SchoolDB ...
随机推荐
- [知乎]自己真是Know Nothing 历史上有哪些细思恐极的事件?
作者:敖让链接:https://www.zhihu.com/question/38374479/answer/652432284来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- [转帖]解决K8S 安装只有 一直提示:kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1 的方法
Centos7 终端报Message from syslogd :kernel:unregister_netdevice https://www.jianshu.com/p/96d7e2cd9e99 ...
- Windows netcat 的工具的简单使用
1. 下载 https://eternallybored.org/misc/netcat/ 2. 将目录添加到环境变量 C:\Work\netcat 3. 简单实验 4. 查看说明 UPDATE // ...
- 洛谷 P5663 加工零件 & [NOIP2019普及组] (奇偶最短路)
传送门 解题思路 很容易想到用最短路来解决这一道问题(题解法),因为两个点之间可以互相无限走,所以如果到某个点的最短路是x,那么x+2,x+4也一定能够达到. 但是如何保证这是正确的呢?比如说到某个点 ...
- Centos7 yum安装LNMP
1.Centos7系统库中默认是没有nginx的rpn包的,所以我们需要先更新下rpm依赖库 (1):使用yum安装nginx,安装nginx库 rpm -Uvh http://nginx.org/p ...
- 利用CSS的translate属性或利用CSS实现图片居中的效果
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- LeetCode-239-剑指offer-滑动窗口的最大值-队列与栈-python
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值.例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6, ...
- http协议是无状态协议,它的无状态指的是什么,如何解决这种情况
http是无状态的协议,也是不安全的协议, 它的无状态是指对于事务处理没有记忆能力,缺少状态意味着后续的操作需要前面的信息. 解决办法:1,通过cookie解决,2,通过session会话保存.
- Android 开发环境部署
引言 在windows安装Android的开发环境不简单也说不上算复杂,本文写给第一次想在自己Windows上建立Android开发环境投入Android浪潮的朋友们,为了确保大家能顺利完成开发环 ...
- 猿题库 iOS 客户端架构设计(原文地址:http://gracelancy.com/blog/2016/01/06/ape-ios-arch-design/)
猿题库 iOS 客户端架构设计 序 猿题库是一个拥有数千万用户的创业公司,从2013年题库项目起步到2015年,团队保持了极高的生产效率,使我们的产品完成了五个大版本和数十个小版本的高速迭代.在如此快 ...