MySQL查询分为内连接查询和外连接查询,他们的区别在于:内连接查询的两个表示对等关系,根据条件进行匹配;外连接是以某一个表为主,两一个表根据条件进行关联。外连接分为左外连接、右外连接和全外连接。本文重点介绍各外连接的思想,以及如何实现全外连接,并举例。

左外连接

左外连接以左边表为基础,根据条件,将右边表附属到左边表,语法:SELECT * FROM A LEFT JOIN B ON condition。几何图形关系如下图,即查询结果集除了A表所有数据外,还包含满足条件的B表数据:

右外连接

右外连接以右边表为基础,根据条件,将左边表附属到右边表,语法:SELECT * FROM A RIGHT JOIN B ON condition。几何图形关系如下图,即查询结果集除了B表所有数据外,还包含满足条件的A表数据:

全外连接

全外连接是除了能够根据条件匹配得到的数据,还包含左右两表中都不匹配的数据(默认应为null),应用全外连接的情况一般都有一个联系左右两表的主线。几何关系如下图所示,对应A和B的并集(去重):

但不幸的是MySQL不支持全外连接,那在需要全外连接查询的情况下,如何实现呢?最常见的是左连接与右连接合并。

实例

项目中存在这样的场景:某项任务task具有2种不同的状态todo和done,分别存储在todolist和donelist表中,任务存储在task表中,现在需要统计每个task的已处理和未处理情况。首先先到了全外连接,那么如何实现呢?

举例实现表结构如下:

实现四种方法:

1、左连接,右连接,合并;(需保持两个结果集结构一致)首先是左连接:SELECT

A.id AS Aid,

B.id AS Bid,

A.taskid tid

FROM

(

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A

LEFT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON A.taskid = B.taskid

查询结果:

其次是右连接(注意由于需要合并,故左右连接的结果集结构需一致):SELECT

A.id AS Aid,

B.id AS Bid,

A.taskid tid

FROM

(

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A

RIGHT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON A.taskid = B.taskid

查询结果:

最后进行合并,并与task表进行内连接:SELECT

SUM(IF(Aid IS NOT NULL, 1, 0)) todo,

SUM(IF(Bid IS NOT NULL, 1, 0)) done,

task.name

FROM

(

SELECT

A.id AS Aid,

B.id AS Bid,

A.taskid tid

FROM

(

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A

LEFT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON A.taskid = B.taskid

UNION

SELECT

A.id AS Aid,

B.id AS Bid,

B.taskid tid

FROM

(

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A

RIGHT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON A.taskid = B.taskid

) AS AB

INNER JOIN task ON task.id = AB.tid

GROUP BY

task.name

运行结果如下表,实现全外连接:

2、A+B左连接,B-A去除左连接到A的记录,然后合并两个结果集;(需保持两个结果集结构一致)

这是另一种实现全外连接的方式,即先查询A B的左连接,然后查询B中去除左连接到A的记录,最后合并(A代表todolist,B代表donelist):A+B左连接SELECT

1 AS todo,

CASE

WHEN B.id IS NOT NULL THEN

1

ELSE

0

END AS done,

A.taskid tid

FROM

(

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A

LEFT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON A.taskid = B.taskid

查询结果:

B-A去除左连接到A的记录SELECT

0 AS todo,

1 AS done,

donelist.taskid tid

FROM

donelist

WHERE

donelist.user = '张三'

AND NOT EXISTS (

SELECT

*

FROM

todolist

WHERE

todolist.taskid = donelist.taskid

AND donelist.user = '张三'

AND odolist.user = donelist.user

)

查询结果:

合并SELECT

SUM(AB.todo) todo,

SUM(AB.done) done,

task.name

FROM

(

SELECT

1 AS todo,

CASE

WHEN B.id IS NOT NULL THEN

1

ELSE

0

END AS done,

A.taskid tid

FROM

(

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A

LEFT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON A.taskid = B.taskid

UNION

SELECT

0 AS todo,

1 AS done,

donelist.taskid tid

FROM

donelist

WHERE

donelist.user = '张三'

AND NOT EXISTS (

SELECT

*

FROM

todolist

WHERE

todolist.taskid = donelist.taskid

AND donelist.user = '张三'

AND odolist.user = donelist.user

)

) AB

INNER JOIN task ON task.id = AB.tid

GROUP BY

task.name

结果同上

3、以task表为根本,将A和B表左连接,实现查询;

该方法的思想是,不管A和B表有什么关系,他们都跟作为主线的表task相关,只需要将A和B表与task表进行左连接,得到连接后的数据集,即为最后需要查询的结果集。SQL代码如下:SELECT

SUM(AB.todo) AS todo,

SUM(AB.done) AS done,

task.name

FROM

(

SELECT

task.name,

CASE

WHEN A.id IS NULL THEN

0

ELSE

1

END AS todo,

CASE

WHEN B.id IS NULL THEN

0

ELSE

1

END AS done

FROM

task

LEFT JOIN (

SELECT

*

FROM

todolist

WHERE

todolist.user = '张三'

) A ON A.taskid = task.id

LEFT JOIN (

SELECT

*

FROM

donelist

WHERE

donelist.user = '张三'

) B ON B.taskid = task.id

WHERE

A.id IS NOT NULL

OR B.id IS NOT NULL

) AB

GROUP BY

task.name

查询结果同上,但这种方法存在一定的缺陷,即当主线表(task表)特别大的时候,性能会比较差。

4、A表查a状态,B表查b状态,然后合并;(需保持两个结果集结构一致)

该方法是不管A和B表的关系,现根据条件查询,然后在合并。SQL语句如下:SELECT

SUM(A.todo) todo,

SUM(A.done) done,

task.name

FROM

(

SELECT

1 todo,

0 done,

todolist.taskid tid

FROM

todolist

WHERE

todolist.user = '张三'

UNION ALL

SELECT

0 todo,

1 done,

donelist.taskid tid

FROM

donelist

WHERE

donelist.user = '张三'

) A

INNER JOIN task ON task.id = A.tid

GROUP BY

task.name

查询结果同上。

四种方式只是实现功能,具体性能没有考虑,待后续学习。希望看客们多提意见,共同学习。

总结:理解左连接、右连接和全外连接的思想

四种实现全外连接效果的方法

语法上注意:UNION可以去重,UNION ALL不去重

mysql查询时 全外連接_MySQL数据库左外连接、右外连接、全外连接相关推荐

  1. mysql查询学校开设总课程数_MYSQL数据库课程设计

    <MYSQL数据库>课程设计 一.目的和要求 (1)培养学生运用所学课程<MYSQL数据库>中数据设计方面的理论知识和技能,深入理解数据库设计相关的理论知识,学会分析实际问题的 ...

  2. mysql查询每个用户第一条数据_MySQL数据库订单表按用户邮箱字段分组查询每个用户的第一条记录...

    程序开发或者一些数据统计时,在MySQL中使用GROUP BY分组是很常用的SQL语句.那么,如果如下的简单示例订单数据表,我们现需要使用GROUP BY分组后查询每个用户的第一个订单记录,应该如何实 ...

  3. mysql查询学生表的总人数_mysql数据库查询练习

    创建四张数据表 学生表student:学号,姓名,性别,出生年月日,所在班级 教师表teacher:教师编号,教师名,教师性别,出生年月日,职称,所在部门 课程表course:课程号,课程名,教师编号 ...

  4. mysql查询时,offset过大影响性能的原因与优化方法

    遇到的问题 我们大家都知道,mysql查询使用select命令,配合limit,offset参数可以读取指定范围的记录,但是offset过大影响查询性能的原因及优化方法,这次工作中因为要导出40W的数 ...

  5. MySQL查询时记录行号rownum MySQL查询显示行号MySQL查询显示行号MySQL流水号自MySQL自增行号

    MySQL查询时记录行号rownum MySQL查询显示行号MySQL查询显示行号MySQL流水号自MySQL自增行号 一.前言 Oracle中有rownum,实现查询的时候记录行号,MySQL中没有 ...

  6. mysql大小写区分_详解MySQL查询时区分字符串中字母大小写的方法

    如果你在mysql有唯一约束的列上插入两行值'A'和'a',Mysql会认为它是相同的,而在oracle中就不会.就是mysql默认的字段值不区分大小写?这点是比较令人头痛的事.直接使用客户端用sql ...

  7. MySQL查询时条件的顺序_mysql中查询条件的先后顺序问题?

    听一个讲座,说查询条件的顺序影响查询速度,比如一个先运行一个高门槛的条件,后低门槛,运行速度会相对快,请问有这种事么? 那么我在写thinkphp的查询语句的时候,是不是应该把高门槛的放在前面查询? ...

  8. mysql查询名字相同数据排列出来_mysql 的sql语句来查找重复数据,并让其都显示出来?...

    2017-12-20 回答 一. 简单查询 简单的transact-sql查询只包括选择列表.from子句和where子句.它们分别说明所查询列.查询的表或视图.以及搜索条件等. 例如,下面的语句查询 ...

  9. mysql查询时强制区分大小写

    转载自:http://snowolf.iteye.com/blog/1681944 平时很少会考虑数据存储需要明确字符串类型字段的大小写,MySQL默认的查询也不区分大小写.但作为用户信息,一旦用户名 ...

  10. mysql查询按值多的排序_MySQL查询结果按某值排序

    MySQL查询结果按某值排序 使用MySQL很多时候我们不仅只是查询出结果,还需要对查询结构进行排序,下文对查询结果按某值排序的方法作了详细的介绍,供您参考. AD: MySQL查询结果如何排序呢?这 ...

最新文章

  1. 高通与苹果宣布“复合”,英特尔黯然退场 | 极客头条
  2. vue组件中的样式属性:scoped,解决在父组件中无法修改子组件样式问题
  3. Exception经验之谈,万万没想到被很多团队采纳!
  4. 详细解读css中的浮动以及清除浮动的方法
  5. 这 10 行比较字符串相等的代码给我整懵了,不信你也来看看
  6. vue获取当前月最后一天_只争朝夕,不负韶华——站在2020年第一天,回望2019最后的两个月...
  7. 常见移动机器人轮直径校准
  8. Mysql Cluster集群实现高可用
  9. 【技术专题研究】OSPF的LSA类型
  10. Robocode 超级机器人 “波”统计瞄准算法
  11. Linux下安装Java环境
  12. ca盘显示无证书_ca证书提示没有正确的安装驱动程序
  13. 锐捷文件描述错误linux,ubuntu下使用锐捷客户端连接校园网-郑州大学Ruijieclient for Linux下载及配置指导...
  14. 以阿尔兹海默症为例:深度解析AI+慢病商业模式
  15. 苹果CEO库克亚洲之行总结 未来挑战远大于机遇
  16. 在html中调用QQ,MSN,旺旺,Skype,Email的方法
  17. 【技术】5G技术的应用场景及发展趋势
  18. 微信小程序:获取用户权限
  19. java1000字节是多少汉字_面试官:Java 中有几种基本数据类型是什么?各自占用多少字节?...
  20. xe10 自带DEMO集合

热门文章

  1. 精益创业实战 - 内容简介
  2. 十分钟django后台 simpleui -含自定义后台首页
  3. (解读)什么是渗透测试(Penetration Testing)?
  4. 计算机函数if使用折扣率,excel1-服装采购表题目要求
  5. 创新彰显实力,方正璞华又获一项国家发明专利
  6. 软件开发实训(720科技)――第五课:前端css规范
  7. 性能测试入门指南 (慎入: 6000 字长文)
  8. 个体营业执照与公司营业执照的区别
  9. 阿里云OSS使用Java上传文件
  10. debug and releas 不显示 调试窗口(DOS窗口/控制台)