关于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 ...
随机推荐
- C#导出带有格式的Excel(列宽,合并单元格,显示边框线,加背景颜色等)
源地址:http://blog.sina.com.cn/s/blog_74f702e60101au55.html 导出excel相关设置:http://blog.csdn.net/wanmingtom ...
- [ActionScript 3.0] AS3 时间格式化方法
/** * 格式化时间,格式 00:00:00 * @param total 总时间(毫秒) */ function getFormatTime(total:uint):String { if (to ...
- 第一个jave程序-helloworld
1.打开myeclipse,其中有个select a workspase的过程,即选择工作空间,这里需要更换空间,不要放C盘,防止项目越来越大占用C盘的空间 2.创建java工程 3.取工程名,填写自 ...
- Ibatis 异常:Unable to open connection to "oledb , provider V2.0.0.0 in framework .NET V2.0".
在实际项目中使用了ibatis,然后在开发过程中遇到一些问题,最严重的就是这个“Unable to open connection to "Microsoft SQL Server, pro ...
- Oracle 10046 event详解-转载
0046事件概述Oracle的10046事件,可以跟踪应用程序所执行的SQL语句,并且得到其解析次数.执行次数,CPU使用时间等信息.这对我们分析.定位数据库性能问题是非常有用的. 10046 eve ...
- Caught exception while loading file struts-default.xml 错误
严重: Exception starting filter struts2 Caught exception while loading file struts-default.xml - [unkn ...
- cocos2d3.0跑酷代码讲解和源码
最近在网上看到一个跑酷代码的例子,写的很不错,连接如下 http://www.waitingfy.com/archives/783 现在我把他精简了一下,去除了一些比较简单的特效,着重保留了主角的跳跃 ...
- 基础字符串处理_C++
C++中,有 char [ ] 和 string 两种方式处理字符串 char 数组是最原始的,string 是带迭代器的 正是这种 string 带了迭代器,它会使我们处理字符串很方便,但也十分慢 ...
- <关于数据仓库>基于docker的Mysql与Hadoop/Hive之间的数据转移 (使用Apache Sqoop™)
原创博客,转载请联系博主! 摘要:本文介绍了如何使用docker快速搭建一个可以从外部访问的mysql服务容器,和由docker搭建的分布式Hadoop文件系统,并且使用ApacheSqoop完成将m ...
- Flex 4 不同主题下容器子元素的管理方法
Flex 下,容器主要分两类:Spark容器, Halo容器. Spark容器 Halo容器 说明 numElements numChildern 容器的子元素数量. addElement( ) ad ...