引言

  平时开发时,经常会使用数据库进行增删改查,免不了会涉及多表联接。今天就简单的记录下T-SQL下的联接操作。

联接类型及其介绍

  在T-SQL中联接操作使用的是JOIN表运算符。联接有三种基本的类型,分别是:交叉联接、内联接和外联接。这三种联接的区别在于它们的逻辑查询处理步骤不同。每一种联接都有一套不同的步骤。

  交叉连接:

  只有一个步骤:笛卡尔积

  内连接:

  两个步骤:笛卡尔积、使用ON关键字进行过滤

  外连接:

  三个步骤:笛卡尔积、ON关键字过滤、添加外部行

  强调的一点:

  联接查询的逻辑步骤是需要比对两张表的数据的,听起来好像比较低效,但这是逻辑上的步骤。在实际的查询中RDBMS引擎去负责数据的查询,RDBMS在实际查询时会走"捷径",只要保证实际查询的结果和逻辑上获取的结果保持一致即可。所以说,我们SQL上写法是逻辑步骤的描述过程,但实际的执行引擎通过优化,会走很多的捷径来加快数据的检索。

交叉联接

  交叉联接在逻辑上是最简单的一种联接操作。他只有一个步骤就是笛卡尔积。假设表A存在m行数据,表B存在n行数据,对A,B两张表进行交叉联接会得到m*n行数据。T-SQL 92的语法如下:

 select E1.empid,E2.empid from HR.Employees as E1
cross join HR.Employees as E2

  在HR.Employee表中我们存放有9条数据。通过对同一张表进行交叉联接,我们会得到81行数据。E2表中的每一行都会映射到E1表的全部数据行。

内联接

  内联接有两个步骤:笛卡尔积和ON关键字过滤。内联接使用须在两个表名之间使用INNER JOIN关键字(INNER关键字是可选的,T-SQL使用JOIN时,默认就是使用内联接)。用于对行进行过滤的条件是在ON子句中指定的(ON也称为联接条件)。

  我们来看一个例子。Employee表中保存雇员的信息。Orders表存放客户下过的订单,每一个订单都有一名雇员来处理,这时会使用empid来标记该订单是哪一位雇员来处理的。通过内联结我们可以获取所有雇员处理过的订单数据。例如:

 select E.empid,E.firstname,E.lastname,O.orderid
from HR.Employees as E
inner join Sales.Orders as O
on E.empid=O.empid

  我们理解上面查询的逻辑步骤可以采用以下简单的方法来描述。我们可以认为将Employees表中的每一行数据与Orders表中的所有行进行比较。如果雇员的ID(Orders表中的雇员ID)与Employees表中的这一行雇员ID相同,则匹配成功。这是理解内联结的一种简单方法。其实,我们应该从逻辑处理步骤上来进行思考。内联结的第一步是笛卡尔积。雇员表是9行数据,订单表是830行数据。笛卡尔积一共是9*830=7470行数据。然后根据ON关键字来筛选。选择其中E.empid=O.empid的行,返回830行。

  注意:SQL使用的是三值谓词逻辑。与HAVING和WHERE子句类似,ON子句也是使用的三值逻辑。ON子句自会返回让谓词逻辑为TRUE的行,所有FALSE和UNKNOW的行都会被过滤掉。

外联结

  外联结与相比较其他两种联结,其逻辑步骤又多了一步,添加外部行。在外联结中,需要把一个表标记为"保留表",可以在表名之间使用LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN。LEFT关键字表示左表是保留表,RIGHT关键字表示右表是保留表,FULL关键字则表示左右两张表都是保留表。外联结的第三个步骤其实就是找出保留表中按照ON条件在另一个表中找不到与之匹配的那些行,然后把它们添加到结果集中。

  下面我们还是通过一个例子来了解:

  表Customers存放的是客户信息,Orders表存在是订单信息。现在需要查询客户和他们的订单的信息(没下过订单的客户也需要在结果集中)。这时我们可以将Customers表作为左表。请看例子:

 select C.custid,companyname,orderid
from Sales.Customers as C
left outer join Sales.Orders as O
on C.custid=O.custid

  Customers表中有两个客户没有下过订单,但是他们也出现在结果集中。从逻辑上讲这两个客户由于在Orders表中匹配不到数据,应该被过滤掉了(的确,他们在ON关键字这一步的确被过滤了)。但是外联结的第三步添加外部行又将他们加入进来了。

  上述查询结果如下(部分):

  

  从外联结保留表的角度看,可以认为外联结结果中的数据包含两种。内部行和外部行。内部行是那些ON关键字可以在两表之间匹配到的行。外部行则是找不到匹配的那些行。内联结只返回内部行。而外联结返回内部行和外部行。

  注意

  使用外联接时经常就使用ON还是WHERE作为过滤条件而迷惑。从外联结保留表中的行角度看,ON关键字的过滤条件不是最终的。换句话说ON关键字并不能决定保留表中的部分行是否会被添加到结果集中,而只是判断是否匹配另一个表中的某些行。所有,当需要表达一个非最终的条件时(即这个条件只决定哪些行可以匹配非保留表),就在ON条件中指定。当在生成外部行以后,需要应用过滤器,并且希望过滤条件是最终的,就需要在WHERE子句中指定条件。

  请看例子:

  假设现在需要返回没有下过订单的客户信息(只需要返回外部行)。语句如下:

 select C.custid,companyname,orderid
from Sales.Customers as C
left outer join Sales.Orders as O
on C.custid=O.custid
where orderid is null

  我们看到,只是在WHERE条件中指定了最终的过滤条件即可。切记,选择非保留表中的列作为过滤条件也很重要。应该选择只在外部行才取值为NULL,而在其他行取值不为NULL的某个列。

浅谈T-SQL中的联接查询的更多相关文章

  1. 浅谈oracle树状结构层级查询之start with ....connect by prior、level及order by

    浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...

  2. 浅谈oracle树状结构层级查询测试数据

    浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...

  3. 转: 浅谈C/C++中的指针和数组(二)

    转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...

  4. 转:浅谈C/C++中的指针和数组(一)

    再次读的时候实践了一下代码,结果和原文不一致 error C2372: 'p' : redefinition; different types of indirection 不同类型的间接寻址 /// ...

  5. 转载 浅谈C/C++中的static和extern关键字

    浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T   static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...

  6. 浅谈C语言中的强符号、弱符号、强引用和弱引用

    摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...

  7. 浅谈关于QT中Webkit内核浏览器

    关于QT中Webkit内核浏览器是本文要介绍的内容,主要是来学习QT中webkit中浏览器的使用.提起WebKit,大家自然而然地想到浏览器.作为浏览器内部的主要构件,WebKit的主要工作是渲染.给 ...

  8. 浅谈JAVA GUI中,AWT与Swing的区别、联系及优缺点

    浅谈JAVA GUI中,AWT与Swing的区别.联系及优缺点 A.区别 1.发布的时间 AWT是在JDK 1.0版本时提出的 Swing是在AWT之后提出的(JAVA 2) 2. ”重量” AWT是 ...

  9. 浅谈 Swift 2 中的 Objective-C 指针

    浅谈 Swift 2 中的 Objective-C 指针 2015-09-07  499 文章目录 1. 在 Swift 中读 C 指针 2. 在 Swift 中创建 C 指针 3. 总结 作者:Ja ...

  10. 浅谈人脸识别中的loss 损失函数

    浅谈人脸识别中的loss 损失函数 2019-04-17 17:57:33 liguiyuan112 阅读数 641更多 分类专栏: AI 人脸识别   版权声明:本文为博主原创文章,遵循CC 4.0 ...

随机推荐

  1. 6 this的使用方法

    class Person { String name; void talk() { System.out.println("my name is "+this.name); } } ...

  2. 【caffe】未定义函数或变量caffe_

    @tag: caffe windows10上配置好caffe后(配置了matlab接口),运行caffe-master/matlab/demo/classification_demo.m报错,提示: ...

  3. php热身2:CRUD with Ajax

    这次热身是一个会员管理系统,包括会员注册.登录.资料修改功能,使用ajax技术 1.建表 use common_module; create table if not exists member( u ...

  4. 【bzoj2118】 墨墨的等式

    http://www.lydsy.com/JudgeOnline/problem.php?id=2118 (题目链接) 题意 给出${B}$的取值范围${[Bmin,Bmax]}$,求方程${a_{1 ...

  5. 学习通过Thread+Handler实现非UI线程更新UI组件

    [Android线程机制] 出于性能考虑,Android的UI操作并不是线程安全的,这就意味着如果有多个线程并发操作UI组件,可能导致线程安全问题.为了解决这个问题,Android制定了一条简单的规则 ...

  6. crawler:简要了解一下PhantomJS

    有时,我们需要浏览器处理网页,但并不需要浏览,比如生成网页的截图.抓取网页数据等操作.PhantomJS的功能,就是提供一个浏览器环境的命令行接口,你可以把它看作一个“虚拟浏览器”,除了不能浏览,其他 ...

  7. RBM Formula Deduction

    Energy based Model the probability distribution (softmax function): \[p(x)=\frac{\exp(-E(x))}{\sum\l ...

  8. android toast几种使用方法

    toast经常会用到,今天做个总结,特别是自定义toast的布局,值得一看. 一.默认展示 // 第一个参数:当前的上下文环境.可用getApplicationContext()或this // 第二 ...

  9. 2015年10月份经常使用的linux命令。

    ps -ef |grep  服务名         详细的介绍可以参考此篇博客http://www.cnblogs.com/wangkangluo1/archive/2011/09/23/218593 ...

  10. Matlab小技巧

    记录一些用Matlab的技巧. //imshow全屏 subplot(1,3,3); imshow(topSketMat); hold on; set(gcf, 'units', 'normalize ...