在上篇博文中介绍了T-SQL查询的基础知识,本篇主要介绍稍微复杂的查询形式。

表运算符

表运算符的作用是把为其提供的表作为输入,经过逻辑查询处理,返回一个表结果。SQL Server支持四个表运算符:JOIN、APPLY、PIVOT、UNPIVOT,其中JOIN是标准SQL中的运算符,APPLY、PIVOT和UNPIVOT是T-SQL的扩展。

JOIN:联接查询时使用

APPLY:用于FROM子句中,分为CROSS APPLYOUTER APPLY两种形式

PIVOT:用于行转列

UNPIVOT:用于列传行

联接查询

联接查询分为外联接、内联接、交叉联接,三者的区别在于如何应用逻辑查询处理阶段:

  • 交叉联接仅应用一个阶段——笛卡尔乘积;
  • 内联接应用两个阶段——笛卡尔乘积和基于谓词ON的筛选;
  • 外联结应用三个极端——笛卡尔乘积,基于谓词ON的筛选,添加外部行;

内部行 & 外部行

内部行指的是基于谓词ON与另一侧匹配的行,外部行则是未匹配的行,外部行用NULL进行填充。内联接结果集仅保留内部行,外联接结果集返回内部行和外部行。

笛卡尔乘积

将一个输入表的每一行与另一个表的所有行匹配,即,如果一张表有m行a列,另一张表n行b列,笛卡尔乘积后得到的表有mn行,a+b列*。由此可以看出,对于数据量较大的表进行关联的话,会得到一张数据量更大的表,会有可能造成内存溢出的。

以下是网络上关于笛卡尔乘积的解释:

在数学中,两个集合X和Y的笛卡儿积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。假设集合A=a, b,集合B=0, 1, 2,则两个集合的笛卡尔积为(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)。类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。A表示所有声母的集合,B表示所有韵母的集合,那么A和B的笛卡尔积就为所有可能的汉字全拼。

举例如下:

USE WJChi;

SELECT * FROM dbo.UserInfo;
SELECT * FROM dbo.UAddress; SELECT *
FROM dbo.UserInfo
CROSS JOIN dbo.UAddress;

得到结果集如下:

 

交叉联接

SQL中使用CROSS JOIN语句进行交叉联接查询,在逻辑处理上,交叉联接是最为简单的联接类型,它只获取表的笛卡尔乘积。

交叉联接两种写法:

USE WJChi;

-- 使用CROSS JOIN,推荐使用这种方式
SELECT *
FROM dbo.UserInfo
CROSS JOIN dbo.UAddress; -- 不使用CROSS JOIN
SELECT *
FROM dbo.UserInfo,dbo.UAddress;

内联接

SQL中使用INNER JOIN...ON...语句进行内联接查询,INNER关键字可选。内联接的逻辑处理分为两步:

  • 生成笛卡尔乘积
  • 根据谓词ON对笛卡尔乘积进行筛选

与交叉联接一样,内联接有两种写法:

USE WJChi;

-- 使用JOIN,推荐使用这种方式
SELECT *
FROM dbo.UAddress
JOIN dbo.UserInfo
ON UserInfo.UAddressId = UAddress.Id; -- 不使用JOIN,与交叉联接类似,但比交叉联接多了WHERE条件
SELECT *
FROM dbo.UAddress,dbo.UserInfo
WHERE UserInfo.UAddressId = UAddress.Id;

外联接

外联接分为左外联接:LEFT OUT JOIN、右外联接:RIGHT OUT JOIN和全联接:FULL OUT JOIN,其中,OUT关键字是可选的。相比于交叉联接和内联接,外联接则最为复杂。外联接逻辑处理分为三步:

  1. 获取表的笛卡尔乘积
  2. 根据谓词ON对笛卡尔乘积进行筛选
  3. 添加外部行数据到结果集中
LEFT JOIN & RIGHT JOIN

LEFT JOIN获取的结果集中保留了左表(LEFT JOIN左侧的表)中的所有数据,及右表中满足筛选条件的数据。右表中不满足筛选条件的空行(外部行)则用NULL值填充。

RIGHT JOINLEFT JOIN作用相反。

示例代码如下,表UserInfo中有4条数据,表UAddress中有三条数据:

USE WJChi;

SELECT *
FROM dbo.UAddress
LEFT JOIN dbo.UserInfo
ON UserInfo.UAddressId = UAddress.Id; SELECT *
FROM dbo.UAddress
RIGHT JOIN dbo.UserInfo
ON UserInfo.UAddressId = UAddress.Id;

查询结果如下:

 
FULL JOIN

FULL JOIN的结果是取LEFT JOINRIGHT JOIN查询结果集的并集

USE WJChi;

SELECT *
FROM dbo.UAddress
FULL JOIN dbo.UserInfo
ON UserInfo.UAddressId = UAddress.Id;

查询结果如下:

 

ON & WHERE

前面说到:内联接结果集仅保留内部行,外联接结果集返回内部行和外部行。换句话说,外联接中ON子句的作用是进行表之间关联,如果外联接需要对结果集做进一步的筛选的话不能使用ON...AND...语句,而要使用WHERE条件。示例如下:

USE WJChi;

-- 内联接使用ON...AND...筛选数据
SELECT *
FROM dbo.UserInfo AS UI
JOIN dbo.UAddress AS UA
ON UA.Id = UI.UAddressId
-- 获取Name为xfh的数据
AND UI.Name='xfh'; -- 外联接使用ON...AND...筛选数据
SELECT *
FROM dbo.UserInfo AS UI
LEFT JOIN dbo.UAddress AS UA
ON UA.Id = UI.UAddressId
-- 获取Name为xfh的数据,无效
AND UI.Name='xfh'; -- 外联接使用WHERE对结果集进行筛选
SELECT *
FROM dbo.UserInfo AS UI
LEFT JOIN dbo.UAddress AS UA
ON UA.Id = UI.UAddressId
WHERE UI.Name='xfh';

输出结果如下:

 

复合联接

复合联接是指谓词涉及表中多个字段的联接,即,关联条件使用ON...AND...的形式。

自联接

同一张表的多个实例之间相互联接,称为自联接。所有基本联接类型(内联接、外联接、交叉联接)支持。

USE WJChi;

SELECT *
FROM dbo.UserInfo AS U1
CROSS JOIN dbo.UserInfo AS U2;

自联接中要为表名指定别名,否则结果集中的列名都将不明确。

相等联接 & 不等联接

当联接条件使用相等运算符时称为相等联接,否则称为不等联接:

USE WJChi;

-- 相等联接
SELECT *
FROM dbo.UAddress
FULL JOIN dbo.UserInfo
ON UserInfo.UAddressId = UAddress.Id; -- 不等联接
SELECT *
FROM dbo.UAddress
FULL JOIN dbo.UserInfo
ON UserInfo.UAddressId <> UAddress.Id;

多联接查询

超过两张表进行关联查询即为多联接查询。通常,当SQL中出现多个表运算符时,从左到右进行逻辑处理,前一个联接的结果会作为下一个联接的左侧输入。SQL Server也常常出于优化查询的目的,在实际处理查询过程中对联接进行重新排序,但这不会影响到处理结果集的正确性。

不建议超过三张表进行关联,过多的表关联会使SQL变得复杂,难以维护且影响性能

小结

过多的表联接会让SQL逻辑变得复杂,对查询性能产生负面影响,且难以维护。

SQL(任何代码)的书写应将语义清晰作为第一追求,而不是为了“炫技”写一些别人难以理解的代码。

StackOverflow中扣出的一张图片,可以概述外联接和内联接查询:

 

推荐阅读

T-SQL基础(一)之简单查询

What is the difference between “INNER JOIN” and “OUTER JOIN”?

T-SQL基础(二)之关联查询的更多相关文章

  1. [SQL基础教程] 3-4 对查询结果进行排序/ORDER BY

    [SQL基础教程] 3-4 对查询结果进行排序/ORDER BY ORDER BY SELECT <列名1>,<列名2>,<列名2>... FROM ORDER B ...

  2. 数据库学习---SQL基础(二)

    数据库学习---SQL基础(一) 数据库学习---SQL基础(二) 数据库学习---SQL基础(三) 上篇复习的sql的增删改查,and ,or ,>=, <=,!=等逻辑运算符,还有in ...

  3. MyBatis基础:MyBatis关联查询(4)

    1. MyBatis关联查询简介 MyBatis中级联分为3中:association.collection及discriminator. ◊ association:一对一关联 ◊ collecti ...

  4. Oracle SQL——varchar2() 和 char()关联查询 存在空格

    背景 表dbcontinfo 字段loanid,类型为varchar2(60) 表dbloanbal 字段loanid,类型为char(60) loanid字段实际长度为24位 问题 两张表dbloa ...

  5. Mybatis框架基础入门(七)--关联查询

    1.一对一查询 1.1 使用resultType接收查询结果 修改pojo类 public class OrderUser extends order { private String usernam ...

  6. SQL基础二

    一.SQL SELECT 语句 SELECT 语句用于从表中选取数据.结果被存储在一个结果表中(称为结果集). SQL SELECT 语法: SELECT 列名称 FROM 表名称 以及: SELEC ...

  7. 7、SQL基础整理(子查询)

    子查询 (用来进行两个或以上表之间的查询) 1.首先新建一个bumen表和一个haha表,填充数据 2.利用两表进行子查询: --部门人数大于5的部门中最大年龄的人的信息--- select MAX( ...

  8. 1、SQL基础整理(基本查询)

    分离.附加.备份.还原 --去重 select distinct 列名from表名 --更新 update fenshu set name = ‘李四’where code = 9 --更改表名 sp ...

  9. sql语句 两表关联查询计算数量

    select sum(a1.`num`)   from `order_orderlistrow` as a1 INNER JOIN `order_orderlist` as a2 on a1.`ord ...

  10. MYSQL基础操作之数据约束与关联查询

    一.MYSQL约束 1.默认值约束,当字段没有插入值的时候,mysql自动给该字段分配默认值. 默认值的字段允许为空. 对默认值字段也可以插入null. CREATE TABLE STUDENT( I ...

随机推荐

  1. EF学习笔记(十) 处理并发

    总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 上一篇:EF学习笔记(九):异步处理和存储过程 本篇原文链接:Handling Concurrency Concurrency ...

  2. vue watch高级用法

    watch是vue组件最常用,最重要的功能之一,我们都知道它最基本的特性就是监听的data对象里的属性变化了,watch就会自动执行. 那它还有什么骚操作呢?下面我带大家看看,菜鸟一枚,如有错误欢迎指 ...

  3. PopupWindow计算弹出位置

    1.首先自定义PopupWindow    popWindowView= LinearLayout.inflate(context, R.layout.popupWindow,null);    po ...

  4. easyUI分页实现加搜索功能

    前台页面: js代码: ps:pagination为true时会在table下面加上easyUI的分页. load函数会将查询值传给datagrid并传给后台重新加载. DAO.xml为: 后台代码实 ...

  5. MapReduce实例学习

    https://blog.csdn.net/m0_37739193/article/details/77676859

  6. 40个Java多线程面试问题

    1. 多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所以然","会用"只 ...

  7. Linux的用户管理(基础篇)

    用户相关 临时切换用户: su 用户名 完全切换用户: su – 用户名 查看当前登入的用户名: whoami 查看当前用户下的一切环境变量: env 登出当前登入的用户: logout 查看系统的用 ...

  8. SpringBoot整合Mybatis完整版

    喜欢的朋友可以关注下,粉丝也缺. 自从Spring推出Boot,Cloud系列之后,一度成为热门的框架,现在大部分的招聘要求都要有相关的开发经验,借此我在这里就给大家分享一下如何玩转SpringBoo ...

  9. python(leetcode)-1.两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  10. Vue 中是如何解析 template 字符串为 VNode 的?

    在接触 React 时候,我只了解到通过 babel 可以把 JSX 转成 VNode(通过调用 React.createElement 方法),但是对其具体是如何转换的却不了解. 很明显,回答失败. ...