2008技术内幕:T-SQL语言基础 联接查询摘记
续 2008技术内幕:T-SQL语言基础 单表查询摘记
第三章 联接查询
Microsoft SQL Server 2008 支持四种表运算符 join(ANSI标准)、apply(T-SQL扩展)、pivot(T-SQL扩展)、unpivot(T-SQL扩展)。
(ANSI SQL是美国国家标准学会(ANSI) 对SQL进行规范化后的国际标准SQL语言,T-SQL是Microsoft SQL Server基于ANSI SQL做了一些扩展形成的专用SQL语言。)
join表运算符对两个输入表进行操作,有三种基本类型:交叉联接、内联接、外联接。
处理步骤:
交叉联接只有一个步骤--笛卡尔积;
内联接有两个步骤--笛卡尔积、过滤;
外联接有三个步骤--笛卡尔积、过滤、添加外部行。
出于优化的目的,SQL Server关系引擎经常会采用很多处理捷径(数据库引擎并没有严格按照逻辑查询处理步骤),因为他知道这样的处理仍然能够生成正确的结果。
交叉联接:
SQL Server支持交叉联接的两种标准语法--ANSI SQL-92 和 ANSI SQL-89 推荐用ANSI SQL-92(下面有推荐说明)。
--ANSI SQL-92标准 CROSS JOIN 关键字 SELECT c.custid ,e.empid FROM Sales.Customers AS cCROSS JOIN hr.Employees AS e --ANSI SQL-89标准 SELECT c.custid ,e.empid FROM Sales.Customers AS c ,hr.Employees AS e
这两种语法在逻辑上和性能上都没有区别,Customers表有91行而Employees有9行数据,所以上面的查询会生成一个819行数据的结果集。
笛卡尔积:如果一个表有m行,而另个表有n行,将得到m*n行的结果集。
图11
自交叉联接:顾名思义一个表实现自己连接自己。交叉联接、内链接、外连接都支持自联接。上面笛卡尔积图就是一个自交叉联接实例。
SELECT E1.empid ,E1.firstname ,E1.lastname ,E2.empid ,E2.firstname ,E2.lastname FROM hr.Employees AS E1CROSS JOIN hr.Employees AS E2
在自联接中,必须为表起别名,如果不为表指定别名,联接结果中的列名就会有歧义。
--利用自联接生成数字表 DECLARE @table TABLE(digit INT NOT NULL PRIMARY KEY) INSERT INTO @table( digit )VALUES ( 0 ),( 1 ),( 2 ),( 3 ),( 4 ),( 5 ),( 6 ),( 7 ),( 8 ),( 9 )SELECT T1.digit + T2.digit * 10 + T3.digit * 100 + 1 AS d FROM @table AS T1CROSS JOIN @table AS T2CROSS JOIN @table AS T3 ORDER BY d
内联接
两个逻辑步骤:一,对两个输入的表进行笛卡尔积运算,二,过滤。
--ANSI SQL-92标准
两表之间必须指定inner join关键字,inner关键字是可选的,因为内联接是默认的联接方式,可以单独指定join关键字。
SELECT e.empid ,e.firstname ,e.lastname ,o.orderid FROM hr.Employees AS eJOIN Sales.Orders AS o ON e.empid = o.empid
on条件子句和where、having子句一样,只返回结果为true的行,而不会返回谓词计算结果为false、unknow的行
--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-92标准的联接语法,因为在某些方面它用起来更安全。如果你写一条内联接查询但忘记了指定联接条件,如果这时候用的是ANSI SQL-92标准,查询语句将是无效的,语法分析器会报错。即使错误提示信息没有马上指出错误是缺少了联接条件,但最终还是可以想办法找到问题在哪,修改好查询语句。
而ANSI SQL-89语法,如果忘记了指定联接条件,查询仍然是有效的,执行的结果集却是一个交叉查询。
错误例子
SELECT e.empid ,e.firstname ,e.lastname ,o.orderid FROM hr.Employees AS eJOINJOIN Sales.Orders AS o错误:Incorrect syntax near 'o'.
如果使用的是ANSI SQL-89标准语法,忘记了写连接条件,
SELECT e.empid ,e.firstname ,e.lastname ,o.orderid FROM hr.Employees AS e ,Sales.Orders AS o
那么恭喜得了一个大数据的大奖!爽歪歪!逻辑一复杂,错误在哪里也不知。
坚持推荐使用ANSI-92的原因:
1.是保持一致性(都有关键字)
2.减少错误(以防逻辑条件被遗漏)
3.提高维护性(一个写好的存储过程,你也不知道会被后面的人改几次,本来是个交叉联接改来改去成了内联接!这个是你无法预算的,但是这是可避免,直接标明cross join.)
组合联接:就是联接条件涉及两边多个列的查询
SELECT * FROM tabName1 AS AINNER JOIN tabName2 AS B ON A.id1 = B.idAND A.id = B.id2
不等联接:如果联接条件只包含等号运算符,那么这样的联接叫做等值联接,如果联接条件包含除等号以外的其他运算符,那么这样的联接叫做不等联接。
SELECT * FROM tabName1 AS AINNER JOIN tabName2 AS B ON A.id1 > B.id
多表联接
一个联接表运算符只对两个表进行操作,而一条查询语句可以包含多个联接。
通常,当From子句中包含多个表运算符时,表运算符在逻辑上是按从左到右的顺序处理的。
SELECT c.custid ,c.companyname ,o.orderid ,od.productid ,od.qtyFROM Sales.Customers AS cINNER JOIN Sales.Orders AS o ON c.custid = o.custidINNER JOIN Sales.OrderDetails AS od ON o.orderid = od.orderid
外联接
外联接是在ANSI SQL-92中才被引入的,因此它只有一种标准语法。逻辑步骤:笛卡尔积、on过滤、添加外部行。
在外联接中,要把一个表标记为“保留的”表,可以在表名之间使用关键字 left outer join、right outer join、full outer join,其中outer关键字是可选的(left join 、right join、full join )。
left关键字表示左边的表的行是保留的,right关键字表示右边表的行是保留的,full关键字则表示左右两边表的行都是保留的。对于来自联接的非保留表的那些列,追加的外部行中的这些列则用null作为占位符。
SELECT C.custid ,C.companyname ,O.orderid FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid
题目:查询订单表中所有订单,查出从2007年1月1日到2010年12月12日之间的每个日期输订单个数。
DECLARE @table TABLE([num] INT NOT NULL PRIMARY KEY ,[date] DATETIME NOT NULL) SET NOCOUNT ON DECLARE @i INT= 1 BEGIN TRAN WHILE ( @i <= 3000 ) BEGININSERT INTO @table( num, date )VALUES ( @i, -- num - intDATEADD(DAY, @i - 1, '20060101') -- date - datetime ) ;SET @i = @i + 1 ;END COMMIT TRAN SET NOCOUNT OFFSELECT CAST(d.date AS DATE) AS [date] ,COUNT(o.orderid) AS [count] FROM @table AS DLEFT JOIN Sales.Orders AS O ON CAST(d.date AS DATE) = CAST(o.orderdate AS DATE) WHERE CAST(d.date AS DATE) BETWEEN '20070101'AND '20101212' GROUP BY CAST(d.date AS DATE)
思路:
--1 建立一个辅助表,往里面添加数据,从2006年1月1日到2014年03月17日
--2 利用外联接查询
ISNULL()函数
语法
isnull(check_expression,replacement_value) returns int
SELECT [date] ,ISNULL(orderid, 0) AS 'default' ,orderid FROM @table AS DLEFT JOIN Sales.Orders AS O ON CAST(d.date AS DATE) = CAST(o.orderdate AS DATE)
图
外联接的条件过滤
对外联接表中非保留表的列值进行过滤,这通常就是存在错误的一个标志。因为外联接得到的外部行中的值有可能是null,而null<运算符><值>运算,得到的只会是Unknow。
例子
SELECT c.custid ,c.companyname ,o.orderid ,o.orderdate FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid WHERE O.orderdate >= '20070101'
上面这条查询语句是对Customers表和Orders表执行左联接操作,Customers作为保留表,在where条件筛选之前,o.orderdate是有两条为null的值使用O.orderdate >= '20070101'过滤条件后,直接将这两条剔除了,因为null和任何比较都是unknow,而where只支持逻辑值为true的表达式,这样的查询条件会让所有外部行都被过滤掉,效果上相当于抵消了外联接的作用,换句话说,这里就是把外联接当成内联接用了。
练习
1-1.执行以下代码
SET NOCOUNT ON; USE TSQLFundamentals2008; IF OBJECT_ID('dbo.Nums','U') IS NOT NULL DROP TABLE dbo.Nums; CREATE TABLE dbo.Nums(n INT NOT NULLPRIMARY KEY)DECLARE @i INT = 1 ; BEGIN TRAN WHILE ( @i <= 100000 ) BEGININSERT INTO Nums( n )VALUES ( @i -- n - int )SET @i = @i + 1 ; END COMMIT TRAN SET NOCOUNT OFF
1-2 写一条查询语句,把所有雇员记录复制5次。
SELECT empid ,firstname ,lastname ,n FROM HR.Employees AS ECROSS JOIN dbo.Nums AS T WHERE n < = 5
1-3 写一个查询,为每个雇员从2009年06月12日致2009年6月12日范围内的每天返回一行。
SELECT H.empid ,DATEADD(DAY, n - 1, '20090101') AS [date] FROM dbo.Nums AS NCROSS JOIN HR.Employees AS H WHERE DATEADD(DAY, n - 1, '20090101') BETWEEN '20090612'AND '20090616' ORDER BY h.empid
2.返回来自美国的客户,并为每个客户返回其订单总数和商品交易总数量。
SELECT C.custid ,COUNT(DISTINCT O.orderid)AS [count] ,SUM(OD.qty) AS totalqty FROM Sales.Customers AS CINNER JOIN Sales.Orders AS O ON C.custid = O.custidINNER JOIN Sales.OrderDetails AS OD ON O.orderid = OD.orderid WHERE C.country = 'USA' GROUP BY C.custid
3.返回客户及其订单信息,包括没有下过任何订单的客户.
SELECT c.custid ,c.companyname ,o.orderid ,o.orderdate FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid
4.返回在2007年02月12日下过订单的客户,以及他们的订单,同时也返回在2007年2月12日没有下过订单的客户.
SELECT c.custid ,c.companyname ,o.orderid ,o.orderdate FROM Sales.Customers AS CLEFT JOIN ( SELECT custid ,orderid ,orderdateFROM Sales.OrdersWHERE CAST(orderdate AS DATE) = '20070212') AS O ON C.custid = O.custid
图
5.返回所有客户信息,并根据客户是否在2007年2月12日日下过订单,再为每个客户返回一列 Yes/No值。上一题的扩展。用case when
SELECT c.custid ,c.companyname ,CASE WHEN o.orderid IS NULL THEN 'No'ELSE 'Yes'END HasOrderOn20070212 FROM Sales.Customers AS CLEFT JOIN ( SELECT custid ,orderid ,orderdateFROM Sales.OrdersWHERE CAST(orderdate AS DATE) = '20070212') AS O ON C.custid = O.custid
转载于:https://www.cnblogs.com/Jolinson/p/3605753.html
2008技术内幕:T-SQL语言基础 联接查询摘记相关推荐
- 笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-02 单表查询
SELECT子句中的别名 SELECT子句是在FROM.WHERE.GROUP BY,以及HAVING子句后处理的,这意味着对于SELECT子句之前处理的那些子句,在SELECT子句中为表达式分配的别 ...
- 笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-08 数据修改
插入数据 T-SQL提供了几种数据插入的语句:INSERT VALUES.INSERT SELECT.INSERT EXEC.SELECT INTO及BULK INSERT. INSERT VALUE ...
- tsql2008技术内幕:tsql语言基础(第3章)
逻辑错误: 1. 对外联接中非保留表的列值进行where 过滤 (抵消了外联接的作用,所有的外部行就会被过滤掉) 2. 在多联接操作中,任何外联接,如果后面紧跟着一个内联或右外联接,都会抵消掉外联接的 ...
- PL/SQL语言基础
PL/SQL语言基础 /********************************数据类型*************************************/ %rowtype (行对 ...
- SQLServer 2008 技术内幕——T-SQL 查询 笔记
原文:SQLServer 2008 技术内幕--T-SQL 查询 笔记 1.SQL编程有许多独特之处,如:面向集合的思维方式.查询元素的逻辑处理顺序.三值逻辑.如果不掌握这些知识就开始用SQL编程,得 ...
- 实验四 数据库SQL语言基础编程
-- 实验四 数据库SQL语言基础编程 -- 实验目的: -- 掌握数据库查询语句的编写方法 -- 掌握利用查询语言完成基本查询 -- 掌握利用SQL语句完成数据的添加.删除.修改操作 -- 实 ...
- 【数据库学习笔记】Day03 - SQL语言基础及数据库定义功能
[数据库学习笔记]Day03 - SQL语言基础及数据库定义功能 〇.本文所用数据库表格: 一.关系运算: 关系运算,数学名词,基本运算有两类:一类是传统的集合运算(并.差.交等),另一类是专门的关系 ...
- SQL语言基础教学 | Mysql 入门教学
SQL语言基础教学 SQL(Structured Query Language)是一种用于管理关系型数据库的标准语言.本文将介绍SQL语言基础,包括SQL语言的基本语法.数据类型.数据查询.数据更新等 ...
- 最全MySQL8.0实战教程 2 SQL语言基础
最全MySQL8.0实战教程 文章目录 最全MySQL8.0实战教程 2 SQL语言基础 2.1 SQL的概述 2.2 SQL的特点 2.3 SQL语言的组成 2.4 语法特点 [黑马程序员MySQL ...
最新文章
- 互联网企业安全高级指南3.7.1 攻防驱动修改
- CVE-2010-3333
- msf 之 webshell 提权
- centos 6.5 启动时卡在进度条位置无法进入系统解决办法。
- [LeetCode]Single Number II
- flask与js交互的示例代码_dapr实战(1):dapr locally环境的搭建和部署官方的Hello world示例...
- NVIDIA英伟达的Multi-GPU多卡通信框架NCCL
- Tomcat端口号的修改
- 疯传短视频V7.10小程序源码
- 华晨集团债务违约65亿 宝马中国:华晨宝马运营不受影响
- Java后台POST请求以application/x-www-form-urlencoded;charset=utf-8格式
- codeforces 906C
- 系统集成项目管理工程师2022年上半年广东卷下午案例分析题及答案
- 基于Socket实现网络编程
- 洪水攻击程序c语言,洪水攻击原理及代码实现全攻略(附源代码)病毒防范 -电脑资料...
- VirtualBox升级VirtualBox Guest Additions增强功能
- 批量添加联系人的方法
- 短语(直接短语、句柄)以及语法树
- GFP:新一代多业务传输技术(转)
- 金蝶软件系统管理与维护常见问题
热门文章
- python中组合与继承的区别_python类与对象的组合与继承
- case zhen语句_switch case语句,switch case用法详解
- Hive更换TEZ引擎
- mysql 360怎么安装_MySQL安装方法
- linux服务器 远程桌面,Linux 远程桌面的两种方式
- 打开excel文件并写入_双击Excel表格文件时只打开程序不能直接打开文件
- python dlib caffe人脸相似度_基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【一】如何配置caffe属性表...
- pythonandroid自动化测试仪器_使用Python进行Android自动化测试
- 没有什么能难倒伟大的电子工程师,办公室想点蚊香没打火机怎么办?安排!...
- 看漫画,学电子,我居然看懂了!