MySQL浅谈 LEFT JOIN

On条件(在“A left join b on conditional_expr”)决定如何从table B 中检索数据行(Matching-State);

如果B中没有行匹配On 条件,额外的B的所有数据列被设为null;
    如果Matching-Stage阶段,where语句的任何限制条件都不会使用,只有Match-Stage阶段之后,where语句的条件才回被使用,它会过滤从matching-stage阶段检索出的数据行。

mysql> show create table product\G;
*************************** 1. row ***************************
       Table: product
Create Table: CREATE TABLE `product` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `amount` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> show create table product_details\G;
*************************** 1. row ***************************
       Table: product_details
Create Table: CREATE TABLE `product_details` (
  `id` int(10) unsigned NOT NULL,
  `weight` int(10) unsigned DEFAULT NULL,
  `exist` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> select * from product\G;
*************************** 1. row ***************************
    id: 1
amount: 100
*************************** 2. row ***************************
    id: 2
amount: 200
*************************** 3. row ***************************
    id: 3
amount: 300
*************************** 4. row ***************************
    id: 4
amount: 400
4 rows in set (0.00 sec)
mysql> select * from product_details\G;
*************************** 1. row ***************************
    id: 2
weight: 22
 exist: 0
*************************** 2. row ***************************
    id: 4
weight: 44
 exist: 1
*************************** 3. row ***************************
    id: 5
weight: 55
 exist: 0
*************************** 4. row ***************************
    id: 6
weight: 66
 exist: 1
4 rows in set (0.00 sec)
mysql> select * from product left join product_details
    -> on product.id = product_details.id;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  2 |    200 |    2 |     22 |     0 |
|  4 |    400 |    4 |     44 |     1 |
|  1 |    100 | NULL |   NULL |  NULL |
|  3 |    300 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.00 sec)

on条件语句和where条件语句有区别吗?

A question: 下面两条查询语句结果集有区别吗?

mysql> select * from product left join product_details
    ->   on product.id = product_details.id
    ->     and product_details.id = 2;
mysql> select * from product left join product_details
    ->   on product.id = product_details.id
    ->        where product_details.id = 2;

<===================================================================>

答案:

mysql> select * from product left join product_details
    ->   on product.id = product_details.id
    ->     and product_details.id = 2;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 |    2 |     22 |     0 |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.01 sec)
mysql> select * from product left join product_details        ->    on product.id = product_details.id           ->        where product_details.id = 2;
+----+--------+----+--------+-------+
| id | amount | id | weight | exist |
+----+--------+----+--------+-------+
|  2 |    200 |  2 |     22 |     0 |
+----+--------+----+--------+-------+
1 row in set (0.00 sec)

第一条查询检索出product表的所有行,并用on condition来决定 做左连接的product_details表那些行被检索。

第二条查询做一样的left-JOIN,它用where语句条件过滤掉不匹配的行。

mysql> select * from product left join product_details
    ->   on product.id = product_details.id
    ->      and product.amount = 100;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 | NULL |   NULL |  NULL |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.03 sec)

product表的所有行都被检索,然而,在product_details表中没找到匹配(没有行匹配该条件product_id = product_details.id and product.amounbt =100);

mysql> select * from product left join product_details
    ->   on product.id = product_details.id
    ->       and product.amount = 200;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  2 |    200 |    2 |     22 |     0 |
|  1 |    100 | NULL |   NULL |  NULL |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.00 sec)

只有一行在product_details中匹配

left join with where ... is null clause:

where-condition阶段在matching-stage阶段之后发生,这意味这where is null 语句会从matching-stage阶段产生的结果过滤那些行不满足 matching-condition(on ...and)

如果你使用超过一个条件在on 语句中(and....and...),这时会变的困惑。
    一个简单的方法理解复杂的matching-condition 搭配where ... is null 语句:

1: 把 is null 语句看作matching-condition的否定;

2:用逻辑规则: !(A and B) == !A or !B

下面列子:

mysql> select a.* from product a left join product_details b
    ->    on a.id = b.id and b.weight != 44 and b.exist = 0
    ->       where b.id is null;
+----+--------+
| id | amount |
+----+--------+
|  1 |    100 |
|  3 |    300 |
|  4 |    400 |
+----+--------+
3 rows in set (0.00 sec)

检验下matching clause(on clause):

on a.id = b.id and b.weight != 44 and b.exist = 0

记住我们认为is null 语句作为 matching-condition的否定.

这意味着我们检索下面这些行:

! ( exist(b.id that equals to a.id)  AND  b.weight !=44  AND  b.exist=0 ) ! exist(b.id that equals to a.id) || ! (b.weight !=44) || ! (b.exist=0)
! exist(b.id that equals to a.id) ||  b.weight =44  ||  b.exist=1

像在C语言中,&&,||逻辑与,或操作符从左到右计算一样,如果一个操作符的结果足以决定最终结果,第二个操作开始不会计算(短路操作)。

在我们这种情况下,意味着,我们检索与A中所有行不匹配的b表中的id ,如果匹配,再检索b.weight = 44 或者b.exist =1.

mysql> select a.* from product a left join product_details b
    ->    on a.id = b.id and b.weight != 44 and b.exist = 1
    ->       where b.id is null;
+----+--------+
| id | amount |
+----+--------+
|  1 |    100 |
|  2 |    200 |
|  3 |    300 |
|  4 |    400 |
+----+--------+
4 rows in set (0.00 sec)
! ( exist(bid that equals to aid) AND b.weight !=44 AND b.exist=1 )
!exist(bid that equals to aid) || !(b.weight !=44) || !(b.exist=1)
!exist(bid that equals to aid) || b.weight =44 || b.exist=0

THE BATTLE BETWEEN THE MATCHING-CONDITIONS AND THE WHERE-CONDITIONS

            你可以获得一样的结果(A.*)如果你把基本的匹配条件放在on语句中,而剩余的条件的否定放在where子句中,例如:

 

mysql> select a.* from product a left join product_details b
    ->    on a.id = b.id and b.weight != 44 and b.exist = 0
    ->       where b.id is null;
+----+--------+
| id | amount |
+----+--------+
|  1 |    100 |
|  3 |    300 |
|  4 |    400 |
+----+--------+
3 rows in set (0.00 sec)

同样的结果,不同的写法:

mysql> select a.* from product a left join product_details b
    ->    on a.id = b.id
    ->       where b.id is null or b.weight = 44 or b.exist = 1;
+----+--------+
| id | amount |
+----+--------+
|  4 |    400 |
|  1 |    100 |
|  3 |    300 |
+----+--------+
3 rows in set (0.00 sec)
mysql> select a.* from product a left join product_details b
    ->    on a.id = b.id and b.weight != 44 and b.exist != 0
    ->      where b.id is null;
+----+--------+
| id | amount |
+----+--------+
|  1 |    100 |
|  2 |    200 |
|  3 |    300 |
|  4 |    400 |
+----+--------+
4 rows in set (0.00 sec)

mysql>  select a.* from product a left join product_details b
    ->   on a.id = b.id
    ->     where b.id is  null or b.weight = 44 or b.exist = 0;
+----+--------+
| id | amount |
+----+--------+
|  2 |    200 |
|  4 |    400 |
|  1 |    100 |
|  3 |    300 |
+----+--------+
4 rows in set (0.00 sec)

这两种查询真的一样吗?

这两种检索一样的结果集如果你只需要第一个表中的结果(e.g. A.*),但是当你在连接表中检索数据时,返回的结果集就跟之前不一样的了,where语句会过滤matching-state返回的数据行;

mysql> select * from product a left join product_details b              on a.id = b.id                    where b.id is null or b.weight = 44 or b.exist = 1;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  4 |    400 |    4 |     44 |     1 |
|  1 |    100 | NULL |   NULL |  NULL |
|  3 |    300 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
3 rows in set (0.00 sec)

mysql> select * from product a left join product_details b              on a.id = b.id and b.weight != 44 and b.exist != 0                   where b.id is null;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 | NULL |   NULL |  NULL |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
4 rows in set (0.00 sec)

如果你用left join来找出那些不存在别的表中的数据行时,在where 语句中的col_name is null部分,col_name对应的列必须被修饰为not null;

时间: 2024-10-29 22:37:45

MySQL浅谈 LEFT JOIN的相关文章

MYSQL 浅谈MyISAM 存储引擎

思维导图 介绍 mysql中用的最多存储引擎就是innodb和myisam.做为Mysql的默认存储引擎,myisam值得我们学习一下,以下是我对<高性能MYSQL>书中提到的myisam的理解,请大家多多指教. 特点 > 不支持事务 证明如下: >> 表记录:t2表的engine是myisam. >> 操作 注意:如果你在数据库进行事务操作,但是事务无法成功,你就要看你的表引擎了,看这种引擎是否支持事务. >> 下面请看innodb中的事务操作 &g

浅谈 Fork/Join

fork/join的java7新添加的功能,能够把它理解成一个并发框架. 我们通过fork/join能将一个可分解的大任务.分解成多个子任务同步运行.运行完成后,在将各子任务的结果进行合并,得到终于的结果. 使用fork/join,首先要创建fork/join任务.能够通过继承RecursiveAction或RecursiveTask来实现(ForkJoinTask是它们的父类) RecursiveAction 不返回结果 RecursiveTask 返回结果 经常用法 compute(); 计

浅谈mysql主从复制的高可用解决方案

1.熟悉几个组件(部分摘自网络)1.1.drbd     —— DRBD(Distributed Replicated Block Device),DRBD号称是 "网络 RAID",开源软件,由 LINBIT 公司开发.DRBD 实际上是一种块设备的实现,主要被用于Linux平台下的高可用(HA)方案之中.他是有内核 模块和相关程序而组成,通过网络通信来同步镜像整个设备,有点类似于一个网络RAID的功能.也就是说当你将数据写入本地的DRBD设备上的文件系统 时, 数据会同时被发送到网

浅谈MySQL索引背后的数据结构及算法

摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持 也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree索引,因为这是 平常使用MySQL时主要打交道的索引,至于哈希索引和全文索引本文暂不讨论. 文章主要内容分为四个部分. 第一部分主要从数据结构及算法理论层面讨论MySQL数据库索引的数理基础. 第二部分结合MySQL数据库中

浅谈mysql innodb缓存策略

浅谈mysql innodb缓存策略: The InnoDB Buffer Pool Innodb 持有一个存储区域叫做buffer pool是为了在内存中缓存数据和索引,知道innodb bufferpool怎么工作,和利用它读取频繁访问的数据,是mysql优化重要的方面. 理想状况下,把bufferpool的大小调整到足够大,留下足够的内存空间给其他该服务器上的进程(使其无缺页即可).bufferpool越大,innodb 月表现为内存型数据库,从硬盘上一次读取数据,之后并成了从内存中读取数

浅谈MySQL存储引擎-InnoDB&amp;MyISAM

存储引擎在MySQL的逻辑架构中位于第三层,负责MySQL中的数据的存储和提取.MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式是不同的.每一种存储引擎都有它的优势和劣势,本文只讨论最常见的InnoDB和MyISAM两种存储引擎进行讨论.本文中关于数据存储形式和索引的可以查看图解MySQL索引 MySQL逻辑架构图: InnoDB存储引擎 InnoDB是默认的事务型存储引擎,也是最重要,使用最广泛的存储引擎.在没有特殊情况下,一般优先使用InnoDB存储引擎. 1??.数据存储形式

浅谈Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景

浅谈Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁定一行) |--共享锁(S锁,MyISAM 叫做读锁) |--排他锁(X锁,MyISAM 叫做写锁) |--悲观锁(抽象性,不真实存在这个锁) |--乐观锁(抽象性,不真实存在这个锁) 二.InnoDB与MyISAM Mysql 在5.5之前默认使用 MyISAM 存储引擎,之后使用 InnoDB .查

浅谈数据库框架,见笑,请多指正

浅谈数据库框架,见笑,请多指正 http://weibo.com/p/1001603724746155003486 一友说"插件式存储又割裂了SQL引擎的完整逻辑...总体而言在现有框架下MySQL的优化器没有多大改进的价值". 我们且做个技术分析: 1 插件式框架,可以静态/动态加载组件,方便在同类不同属家的模块间切换,这种设计是良好的. 很多软件的设计都采用了"微内核+插件"这样的方式构筑了强大的应用.如Ecplise生态圈. 2 数据库范围内, MySQL的属

浅谈php web安全

首先,笔记不是web安全的专家,所以这不是web安全方面专家级文章,而是学习笔记.细心总结文章,里面有些是我们phper不易发现或者说不重视的东西.所以笔者写下来方便以后查阅.在大公司肯定有专门的web安全测试员,安全方面不是phper考虑的范围.但是作为一个phper对于安全知识是:“知道有这么一回事,编程时自然有所注意”. 概要: 1.php一些安全配置 (1)关闭php提示错误功能 (2)关闭一些“坏功能” (3)严格配置文件权限. 2.严格的数据验证,你的用户不全是“好”人 2.1为了确