关于SQL表联接
以SQL2008为例,Microsoft SQL Server 2008支持四种表运算符-JOIN,APPLY,PIVOT,UNPIVOT.JOIN表运算符是ANSI标准,而其他三种是T-SQL对标准的扩展。今天主要是了解有关JOIN表的操作。
JOIN表运算符对两个输入表进行操作。联接有三种基本类型:交叉联接,内联接和外联结。这三种联接的区别是它们采用的逻辑查询处理步骤各不相同,每种联接都有一套不同的步骤。交叉联接只有一个步骤-笛卡尔积;内联接有两个步骤-笛卡尔积,过滤;外联结有三个步骤-笛卡尔积,过滤,添加外部行。
学习使用的数据库是T-SQLFundamentals2008数据库,数据库创建代码分享:http://pan.baidu.com/s/1jGLBxm2
1.交叉联接
逻辑上,交叉联接是最简单的联接。交叉联接只实现一个逻辑查询步骤(笛卡尔积)。这一步是对输入的两个表进行操作, 把它们联接起来,生成二者的笛卡尔积。也就是将一个输入表的每行与另一个表的所有行进行匹配。如果一个表有m行,另一个表有n行,将得到m*n行的结果集。
SQL-Server支持交叉联接的两种标准语法-ANSI SQL-92和ANSI SQL-89语法。这里推荐使用ANSI SQL-92,具体原因稍后解释。
在下载数据库代码后创建T-SQLFundametals2008数据库后,下面的例子对数据库中的Customers表和Employees表进行交叉联接查询(使用ANSI SQL-92语法),返回集合中的custid和empid:
-- ANSI SQL-92语法
USE TSQLFundamentals2008;
SELECT C.custid, E.empid
FROM Sales.Customers AS C
CROSS JOIN HR.Employees AS E;
-- ANSI SQL-89语法
SELECT C.custid, E.empid
FROM Sales.Customers AS C, HR.Employees AS E;
这两种语法在逻辑和性能上没有区别,它们都是最新的SQL标准中不可缺少的一部分,而且SQL Server的最新版本也完全支持这两种语法。之所以推荐使用ANSI SQL-92语法,在解释完内联接后将会变的很清楚。
自交叉联接:对同一个表的多个实例也可以进行联接,这种功能就是所谓的自联接(self-join),所有基本联接类型(交叉联接,内联接,外联接)都支持自联接。
例:该查询生成员工配对的所有可能组合。
-- Self Cross-Join
SELECT
E1.empid, E1.firstname, E1.lastname,
E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
CROSS JOIN HR.Employees AS E2;
在自联接中,必须为表起别名。如果不为表指定别名,联接结果中的列名就会有歧义。
2.内联接
内联接要应用两个逻辑查询处理步骤:它首先像交叉联接一样,对两个输入表进行笛卡尔积运算:然后根据用户指定的谓词对结果进行过滤。和交叉联接一样,内联接也有两种标准语法:ANSI SQL-92和ANSI SQL-89。
2.1:ANSI SQL-92语法
使用ANSI SQL-92语法,需在两个表名之间指定 INNER JOIN关键字。INNER关键字是可选的,因为内联接是默认的联接方式,所以可以只单独指定JOIN关键字,但是 还是建议全部指定。用于进行过滤的谓词是一个称为ON子句的特别设定的语句中指定的,该谓词也称之为联接条件。
例:对TSQLFundamentals2008数据库中Employees表和Orders表执行内联接运算,根据谓词条件 E.empid=O.empid对雇员和订单记录进行匹配:
-- ANSI SQL-92
USE TSQLFundamentals2008;
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
JOIN Sales.Orders AS O
ON E.empid = O.empid;
因为SQL使用三值谓词逻辑(true,false,unknown),ON子句也只返回谓词结果为true的行,而不会返回谓词结果为false或者unknown的行,如果雇员没有相关的订单,则在过滤处理阶段会将这些与雇员相关的行过滤掉。
2.2:ANSI SQL-89语法
和交叉联接类似,内联接也可以使用ANSI SQL-89语法来表达。可以像交叉联接那样在表名之间放一个逗号,在查询的WHERE子句中定义条件,如:
-- 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-89语法没有ON子句
2.3:更安全的内联接
强烈推荐使用ANSI SQL-92的联接语法,因为他在某些方面用起来更安全。假如你想写一条内联接查询,但不小心忘记指定联接条件。如果这时候使用的是ANSI SQL-92语法,查询语句将是无效的,如:
-- Inner Join Safety
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
JOIN Sales.Orders AS O;
然而,如果使用ANSI SQL-89语法,忘了指定联接条件,那么这个查询仍然是有效的,但执行的确是一个交叉查询:
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O;
因为查询没有失败,所以可能一时无法发现语句中隐藏的逻辑错误,最终导致用户在使用应用程序时得到的是错误的结果。对于简短的查询语句来说,程序员还不太可能忘记指定联接条件;但大多数的产品应用中的查询语句要比这复杂的多,会涉及多个表,过滤条件,以及其他查询元素。在这些复杂条件下,忘记指定联接条件的可能性也随之增加。
3.外联接
3.1:外联结基础
与内联接和交叉联接不同,外联结是在ANSI SQL-92中才被引入的,因此它只有一种标准语法----在表名中间指定JOIN关键字,在ON子句中指定联接条件。外联结会应用内联接所应用的两个逻辑步骤:(笛卡尔积和ON过滤),此外还多了一个外联结特有的第三步:添加外部行。
在外联结中,要把一个表标记为“保留的”表,可以在表名之间使用关键字LEFT OUTER JOIN,RIGHT OUTER JOIN,以及FULL OUTER JOIN,其中OUTER关键字是可选的。LEFT表示左边的表是保留的,RIGHT表示右边的表是保留的,FULL表示关键字左右两个表都是保留的。外联结的第三个步骤就是要识别保留表中按照ON条件在另一个表中找不到匹配的那些行,再把这些行添加到联接的前两个步骤所生成的结果集中;对于来自联接的非保留表的那些列,追加的外部行中的这些列则用NULL作为占位符。
通过例子来理解是个好办法。以下查询根据客户ID和订单的客户ID 对Customers表和Orders表进行联接,并返回客户和他们的订单信息。该查询语句使用的联接类型是左外联接,所以查询结果也会返回那些没有发出任何订单的客户:
-- Customers and their orders, including customers with no orders
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid;
从外联结保留表的角度看,可以认为外联结结果中的数据行包括两种:内部行和外部行。内部行指的是按照ON子句中能在联接的另一个表中找到匹配的那些行;外部行就是找不到匹配的那些行。使用外联结时,经常会为到底是查询的ON子句中,还是在where子句中指定联接条件而感到困惑。从外联结的保留表中的行来考虑这个问题,ON子句中的过滤条件不是最终的。换句话说,ON子句中的条件并不能最终决定保留表中部分行是否会在结果中出现,而只是判断是否能够匹配到另一边表中的某些行。所以,当需要表达一个非最终的条件时,就在ON子句中指定联接条件。当在生成外部行以后,要应用过滤器,而且希望过滤条件是最终的,就应该在where中指定条件。
同样通过例子理解是个好办法:
在上面介绍外联时以下查询结果中:
-- Customers and their orders, including customers with no orders
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid;
我们发现结果中当custid为22时,对应的orderid为null,那么再添加一个条件,外联结查询且custid不为22的结果。
如果我们在ON中指定条件
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid AND C.custid<>22;
发现结果和上面的结果一样,同样会出现custid=22的那条数据,如果在where子句中添加条件
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid
WHERE C.custid<>22;
你就会发现custid=22的那条数据被过滤掉了,所以在外联结查询中添加条件是视情况而选择在ON子句中添加还是在WHERE子句中添加,所以建议在ON子句中只放关于两个表联接所需要的条件,如果要实现对结果集的再次过滤,请使用where子句。
摘自sql server2008技术内幕
虽然以前学习过SQL,但是还是感觉学习的不是很透彻,这里推荐一本书:microsoft sql server 2008技术内幕 t-sql语言基础!!!分享地址http://pan.baidu.com/s/1hqtplqO
看完之后又会发现自己学到好多东西!大神绕路,新人共勉!
关于SQL表联接的更多相关文章
- sql表联接
1.join: 表:erp_orders和erp_orders_products SELECT * FROM erp_orders_products AS products, erp_orders A ...
- SQL语句汇总(终篇)—— 表联接与联接查询
上一篇博文说到相关子查询效率低下,那我们怎么能将不同表的信息一起查询出来呢?这就需要用到表联接. 和之前的UNION组合查询不同,UNION是将不同的表组合起来,也就是纵向联接,说白了就是竖着拼起来. ...
- SQL语句汇总(终篇)—— 表联接与联接查询
既然是最后一篇那就不能只列出些干枯的标准语句,更何况表联接也是SQL中较难的部分,所以此次搭配题目来详细阐述表联接. 上一篇博文说到相关子查询效率低下,那我们怎么能将不同表的信息一起查询出来呢?这就需 ...
- 完整SQL分页存储过程(支持多表联接)
http://www.cnblogs.com/andiki/archive/2009/03/24/1420289.html Code/********************************* ...
- sql表连接left join,right join,inner join三者之间的区别
sql表连接left join,right join,inner join区别 left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 (以左表数据为基准,不足补为NULL) ...
- T-SQL表联接查询
由于实践不足,总是忘记SQL Server 联接表查询的细节,在这里记录以便查询. 一.交叉联接 交叉联接仅执行一个罗辑查询处理阶段——笛卡尔积.也就是说,将一个输入表的每一行与另一个表的所有行匹配. ...
- SQL2005分页存储过程(支持多表联接)
Code /********************************************************* * 作 用:数据分页(完整SQL分页存储过程(支持多表联接)) ...
- sql表和字段的别名
1. sql表和字段的别名通过关键字 AS 来指定. 2.通常,定义字段别名的 AS 关键字可以省略,但我们建议不要省略 AS 关键字.别名(alias)是 SQL 的标准语法,几乎所有的数据库系统都 ...
- SQL表连接查询(inner join、full join、left join、right join)
SQL表连接查询(inner join.full join.left join.right join) 前提条件:假设有两个表,一个是学生表,一个是学生成绩表. 表的数据有: 一.内连接-inner ...
随机推荐
- 构建高性能可扩展asp.net网站--20130628
构建高可扩展性最经常讨论到的问题: 如何才能让HTML 显示得更快? 缓存的最佳方式是什么? 如何使用IIS 让网站更快? 如何处理会话状态? 如何改进ASP.NET 代码? 我的数据库为什么这么慢? ...
- [POJ 2443] Set Operation (bitset)
题目链接:http://poj.org/problem?id=2443 题目大意:给你N个集合,每个集合里有若干个数.M个查询,每个查询有a,b两个数.问是否存在一个集合同时包含a,b这两个数.若存在 ...
- [HDU 4747] Mex (线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 这道题是我去年刚入校队的时候参加网赛的题目. 一年过去了,我依然还是不会做.. 这是我难题计划的 ...
- iOS 模态视图
模态视图不是专门的某个类,而是通过视图控制器的presentViewController方法弹出的视图,我们称为模态视图. 模态视图出现的场景一般是临时弹出的窗口,譬如:登录窗口: 模态视图弹出时通过 ...
- 项目管理: Maven 让事情变得简单
http://maven.apache.org/, Maven其实就是为java实现的一个构建工具.他比Ant更高端. 目前,绝大多数开发人员都把 Ant 当作 Java 编程项目的标准构建工具.遗 ...
- (整理)C#实现UDP广播
(一) IP地址解析 IP地址的类型:XXX.XXX.XXX.XXXA类: 1.0.0.1--126.255.255.254 最高位是0: 1个字节的网络地址和3个地址的主机地址 测试地址:127.X ...
- jQuery基础---filter()和find()
这是jQuery里常用的2个方法.他们2者功能是完全不同的,而初学者往往会被误导. 首先 我们看.find()方法:现在有一个页面,里面HTML代码为;程序代码 <div class=" ...
- freeglut第一步
#include <GL/freeglut.h> static void RenderSceneCB() { glClear(GL_COLOR_BUFFER_BIT); glutSwapB ...
- 【转】最实用的IT类网站及工具大集合
转自:http://www.cnblogs.com/annie00/p/5753507.html 1.聚合数据 大家在开发过程中,可能会用到各种各样的数据,想找一些接口来提供一些数据.比如天气预报查询 ...
- Oracle密码过期the password has expired
oracle11G新特征,半年会提醒一次修改新密码 正常情况:只要输入原先帐号密码,回车即可. 不正常情况:输入新密码帐号,回车,提示验证错误,这时就需要切换到没过期的管理员用户,高权限也行,输入 ...