数据库外连接及MySQL实现
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实现的更多相关文章
- oracle数据库外连接
外连接作用:(左外连接和右外连接;注:没有全外连接) 希望把某些不成立的记录(40号部门),仍然包含在最后的结果中 左外连接:当where e.deptno=d.deptno不成立的时候,等号左边的表 ...
- 关于不同数据库的连接配置(MySql和Oracle)
mysql: driverClass=com.mysql.jdbc.Driver #在和mysql传递数据的过程中,使用unicode编码格式,并且字符集设置为utf-8,插入数据库防止中文乱码 ur ...
- mysql数据库中的多表查询(内连接,外连接,子查询)
用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). MySQL版 ...
- 图解MySQL 内连接、外连接
2.内连接(INNER JOIN)内连接(INNER JOIN):有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行.(所谓的链接表就是数据库在做查询形成的中间表).例如:下面的语句3 ...
- 图解MySQL 内连接、外连接、左连接、右连接、全连接
用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). MySQL版 ...
- 配置phpmyadmin连接远程 MySQL数据库
引言:1.phpmyadmin程序所在服务器:192.168.1.1,访问地址为:http://192.168.1.1/phpmyadmin2.MySQL数据库所在服务器:192.168.1.2, ...
- MySQL 内连接、外连接、左连接、右连接、全连接……太多了
用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). 主题:内连接 ...
- mysql内连接(inner join 找两个表的交集)、左连接(left join 交集并且左表所有)、右连接(right join 交集并且右表所有)、全连接(mysql不支持)
用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). MySQL版 ...
- Hibernate不同数据库的连接及SQL方言
本文讲述Hibernate不同数据库的连接及SQL方言.Hibernate不同数据库的连接可能会出现错误,有一种情况是由于Hibernate SQL方言设置不正确而导致的. 以下代码展示Hiberna ...
随机推荐
- Android studio 断点技巧
写代码不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug:那么你的调试技术停留在哪一阶段呢?仅仅是下个断点单步执行吗?或者你知道 Evaluate Expression , 知道条件断 ...
- Java线程安全性中的对象发布和逸出
发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...
- 我必须得告诉大家的MySQL优化原理
本文转载自http://www.jianshu.com/p/d7665192aaaf 说起MySQL的查询优化,相信大家积累一堆技巧:不能使用SELECT *.不使用NULL字段.合理创建索引.为字段 ...
- Good Vegetable 4级算法题 分值: [320/3120] 问题: [8/78]
1523 非回文 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 一个字符串是非回文的,当且仅当,他只由前p个小写字母 ...
- IT培训行业揭秘(六)
2017年全国的IT职业培训机构的招生数量相比于去年同期都出现了大规模的下滑,虽然目前大学生毕业之后参加培训班的人数依然没有变化,但是目前中小培训机构像雨后春笋般的纷纷建立,他们纷纷抢占市场,为了招生 ...
- Spark踩坑记——从RDD看集群调度
[TOC] 前言 在Spark的使用中,性能的调优配置过程中,查阅了很多资料,之前自己总结过两篇小博文Spark踩坑记--初试和Spark踩坑记--数据库(Hbase+Mysql),第一篇概况的归纳了 ...
- opencv基础到进阶(2)
本文为系列文章的第2篇,主要讲解对图像的像素的操作方法. 2.1存取像素值 为了存取矩阵元素,需要指定元素所在的行和列,程序会返回相应的元素.单通道图像返回单个数值,多通道图像,返回的则是一组向量(V ...
- python 列表转字典
def func_data(text): data = dict() for kv in text.split(','): k_v = kv.split(':') data[k_v[0]] = k_v ...
- 【JAVAWEB学习笔记】网上商城实战2:异步加载分类、Redis缓存分类和显示商品
网上商城实战2 今日任务 完成分类模块的功能 完成商品模块的功能 1.1 分类模块的功能: 1.1.1 查询分类的功能: 1.1.2 查询分类的代码实现: 1.1.2.1 创建 ...
- 数据库MySQL安装和校验
1.安装MySQL 双击已经下载的安装包: Typical:典型安装,第一次安装建议选择该类安装 Custom:自定义安装,在对数据库熟悉后,知道自己需要哪些组件时,可以选择该类安装(这里选择的是自定 ...