更多情况下,我们查询的数据来源于多张表,所有有必要了解一下MySQL中的连接查询。

SQL中将连接查询分成四类:交叉连接,内连接,外连接和自然连接。

数据准备

student表

-- ----------------------------
-- Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`age` tinyint(4) DEFAULT NULL,
`classId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', 's1', '20', '1');
INSERT INTO `student` VALUES ('2', 's2', '22', '1');
INSERT INTO `student` VALUES ('3', 's3', '22', '2');
INSERT INTO `student` VALUES ('4', 's4', '22', null);

class表

-- ----------------------------
-- Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of class
-- ----------------------------
INSERT INTO `class` VALUES ('1', '一班');
INSERT INTO `class` VALUES ('2', '二班');
INSERT INTO `class` VALUES ('3', '');

score表

-- ----------------------------
-- Table structure for `score`
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
`id` int(11) DEFAULT NULL,
`name` varchar(10) DEFAULT NULL,
`score` decimal(4,1) DEFAULT NULL,
`studentId` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of score
-- ----------------------------
INSERT INTO `score` VALUES ('1', '语文', '90.0', '1');
INSERT INTO `score` VALUES ('2', '数学', '95.0', '1');
INSERT INTO `score` VALUES ('3', '语文', '92.0', '2');
INSERT INTO `score` VALUES ('4', '数学', '88.0', '2');
INSERT INTO `score` VALUES ('5', '语文', '96.0', '3');
INSERT INTO `score` VALUES ('6', '数学', null, '3');

交叉连接

交叉连接(CROSS JOIN)是用左表中的每一行与右表中的每一行进行连接,不能使用ON关键字。所得到的结果将是这两个表中各行数据的所有组合,即这两个表所有数据的笛卡尔积。如果A表有4条记录,B表有3条,则结果有4*3=12条记录。

mysql> SELECT * FROM student CROSS JOIN class;
+----+------+-----+---------+----+-------+
| id | name | age | classId | id | cname |
+----+------+-----+---------+----+-------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 1 | s1 | 20 | 1 | 2 | 二班 |
| 1 | s1 | 20 | 1 | 3 | |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 2 | 二班 |
| 2 | s2 | 22 | 1 | 3 | |
| 3 | s3 | 22 | 2 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
| 3 | s3 | 22 | 2 | 3 | |
| 4 | s4 | 22 | NULL | 1 | 一班 |
| 4 | s4 | 22 | NULL | 2 | 二班 |
| 4 | s4 | 22 | NULL | 3 | |
+----+------+-----+---------+----+-------+
12 rows in set

如果给交叉连接加上WHERE关键字,此时将返回符合条件的结果集,这时候与内连接的执行结果一样。

mysql> SELECT * FROM student CROSS JOIN class WHERE student.classId = class.id;
+----+------+-----+---------+----+-------+
| id | name | age | classId | id | cname |
+----+------+-----+---------+----+-------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
+----+------+-----+---------+----+-------+
3 rows in set

内连接

内连接(INNER JOIN)是用左表中的每一行与右表中的所有记录进行匹配,查询的结果为两个表经过ON条件过滤后的笛卡尔积

mysql> SELECT * FROM student INNER JOIN class ON student.classId = class.id; -- 推荐写法,INNER可写可不写
+----+------+-----+---------+----+-------+
| id | name | age | classId | id | cname |
+----+------+-----+---------+----+-------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
+----+------+-----+---------+----+-------+
3 rows in set

等价于

mysql> SELECT * FROM student, class WHERE student.classId = class.id;
+----+------+-----+---------+----+------+
| id | name | age | classId | id | name |
+----+------+-----+---------+----+------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
+----+------+-----+---------+----+------+
3 rows in set

可以连接多张表

mysql> SELECT * FROM student
-> JOIN class ON student.classId = class.id
-> JOIN score ON student.id = score.studentId;
+----+------+-----+---------+----+-------+----+------+-------+-----------+
| id | name | age | classId | id | cname | id | name | score | studentId |
+----+------+-----+---------+----+-------+----+------+-------+-----------+
| 1 | s1 | 20 | 1 | 1 | 一班 | 1 | 语文 | 90 | 1 |
| 1 | s1 | 20 | 1 | 1 | 一班 | 2 | 数学 | 95 | 1 |
| 2 | s2 | 22 | 1 | 1 | 一班 | 3 | 语文 | 92 | 2 |
| 2 | s2 | 22 | 1 | 1 | 一班 | 4 | 数学 | 88 | 2 |
| 3 | s3 | 22 | 2 | 2 | 二班 | 5 | 语文 | 96 | 3 |
| 3 | s3 | 22 | 2 | 2 | 二班 | 6 | 数学 | NULL | 3 |
+----+------+-----+---------+----+-------+----+------+-------+-----------+
6 rows in set

外连接

左外连接

左外连接包含LEFT JOIN左表所有行,如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL)。

mysql> SELECT * FROM student LEFT JOIN class ON student.classId = class.id; -- 或者LEFT OUTER JOIN
+----+------+-----+---------+------+-------+
| id | name | age | classId | id | cname |
+----+------+-----+---------+------+-------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
| 4 | s4 | 22 | NULL | NULL | NULL |
+----+------+-----+---------+------+-------+
4 rows in set

右外连接

右外连接包含RIGHT JOIN左表所有行,如果右表中某行在左表没有匹配,则结果中对应行左表的部分全部为空(NULL)。

mysql> SELECT * FROM student RIGHT JOIN class ON student.classId = class.id; -- 或者RIGHT OUTER JOIN
+------+------+------+---------+----+-------+
| id | name | age | classId | id | cname |
+------+------+------+---------+----+-------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
| NULL | NULL | NULL | NULL | 3 | |
+------+------+------+---------+----+-------+
4 rows in set

全外连接

如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL),如果右表中某行在左表没有匹配,则结果中对应行左表的部分全部为空(NULL)。MySQL不支持FULL JOIN,但是我们可以对左连接和右连接的结果做UNION操作来实现

mysql> SELECT * FROM student LEFT JOIN class ON student.classId = class.id
-> UNION
-> SELECT * FROM student RIGHT JOIN class ON student.classId = class.id;
+------+------+------+---------+------+-------+
| id | name | age | classId | id | cname |
+------+------+------+---------+------+-------+
| 1 | s1 | 20 | 1 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 1 | 一班 |
| 3 | s3 | 22 | 2 | 2 | 二班 |
| 4 | s4 | 22 | NULL | NULL | NULL |
| NULL | NULL | NULL | NULL | 3 | |
+------+------+------+---------+------+-------+
5 rows in set

自然连接

自然连接无需指定连接列,SQL会检查两个表中是否有相同名称的列,且相同的列名称只能有一个,自然连接基本不用。

mysql> SELECT * FROM student NATURAL JOIN class;
+----+------+-----+---------+-------+
| id | name | age | classId | cname |
+----+------+-----+---------+-------+
| 1 | s1 | 20 | 1 | 一班 |
| 2 | s2 | 22 | 1 | 二班 |
| 3 | s3 | 22 | 2 | |
+----+------+-----+---------+-------+
3 rows in set

可以看到只有一列id了,因为student与class两张表中相同的id列自动合并了,相当于内连接

SELECT * FROM student INNER JOIN class ON student.id = class.id

如果更改class表的cname字段名称为name会出现什么情况呢?

mysql> ALTER TABLE class CHANGE cname name VARCHAR(10);
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM student NATURAL JOIN class; -- 因为两张表同名字段有两个,所有结果为空
Empty set

由于现在student与class表有两个同名的字段,所有结果为空

MySQL学习(四) SQL连接查询的更多相关文章

  1. MySQL 学习四 SQL优化

    MySQL逻辑架构: 第一层:客户端层,连接处理,授权认证,安全等功能.   第二层:核心层,查询解析,分析,优化,缓存,内置函数(时间,数学,加密),存储过程,触发器,视图   第三层:存储引擎.负 ...

  2. 深入学习之mysql(五)连接查询

    深入学习Mysql(五)连接查询 1.准备数据库: CREATE DATABASE IF NOT EXISTS `db_book2` DEFAULT CHARACTER SET UTF8; USE ` ...

  3. sql连接查询(inner join、full join、left join、 right join)

    sql连接查询(inner join.full join.left join. right join) 一.内连接(inner join) 首先我这有两张表 1.顾客信息表customer 2.消费订 ...

  4. SQLServer SQL连接查询深度探险(摘录

    SQL连接查询深度探险[摘录] 测试环境: Windows XP Profession MySQL 5.0.45 Oracle 9i DB2 UDB 9.1 测试的SQL脚本如下:此脚本适合MySQL ...

  5. MySQL学习(一)——Java连接MySql数据库

    MySQL学习(一)——Java连接MySql数据库 API详解: 获得语句执行 String sql = "Insert into category(cid, cname) values( ...

  6. 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载

    浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...

  7. mysql统计类似SQL语句查询次数

    mysql统计类似SQL语句查询次数 vc-mysql-sniffer 工具抓取的sql分析. 1.先用shell脚本把所有enter符号替换为null,再根据语句前后的字符分隔语句 grep -Ev ...

  8. sql连接查询中的分类

    sql连接查询中的分类 1.内连接(结果不保留表中未对应的数据) 1.1等值连接:关联条件的运算符是用等号来连接的. 1.2不等值连接:连接条件是出等号之外的操作符 1.3自然连接:特殊的等值连接,在 ...

  9. python之MySQL学习——防止SQL注入

    python之MySQL学习——防止SQL注入 学习了:https://www.cnblogs.com/xiaomingzaixian/p/7126840.html https://www.cnblo ...

随机推荐

  1. C++ MFC棋牌类小游戏day3

    今天开始设计小人棋子. 画法跟画虎一样,唯一不一样的是小人在刚开始会有重叠的情况,所以画起来可能比虎的棋子能够难一点. 我打算用Location结构体中的num来标记每个棋盘坐标存在棋子的个数,isH ...

  2. 国网电表dlt645-2007抄表软件

    这个支持公网抄表 在以前局域网的基础上做了修正 使用起来更加便利了

  3. git diff 理解

    0. 理解 git diff 返回信息 1. 命令 $ git diff README.md 2. 返回信息,注解 diff --git a/README.md b/README.md ## 1. 表 ...

  4. 安卓Task和Back Stack

    概述 一个Activity允许用户完成一些操作,甚至,Android中设计Activity为组件的形式,这样,多个Activity--甚至是其它App的Activity可以一起完成一项任务. Task ...

  5. 「WC2018」州区划分(FWT)

    「WC2018」州区划分(FWT) 我去弄了一个升级版的博客主题,比以前好看多了.感谢 @Wider 不过我有阅读模式的话不知为何 \(\text{LATEX}\) 不能用,所以我就把这个功能删掉了. ...

  6. ng 的 ng-repeat(对象) 把对象的 key 和value 都拿出来 循环

    对象的repeat  是这种形式

  7. SSH框架搭建过程详解

    Spring.Struts2.Hibernate框架: 具体三大框架的知识以前的文章写过,在这里整合 Spring框架知识:http://www.cnblogs.com/xuyiqing/catego ...

  8. OpenStack-Ocata版+CentOS7.6 云平台环境搭建 — 3.安装配置OpenStack认证服务(keystone)

    节点配置信息说明: 控制节点:controller: IP:192.168.164.128 hostname&hosts:likeadmin 计算加点:Nova: IP:192.168.164 ...

  9. jsp-EL表达式简介

    表达式语言(Expression Language,EL),EL表达式是用"${}"括起来的脚本,用来更方便的读取对象! EL表达式主要用来读取数据,进行内容的显示! 使用EL表达 ...

  10. Mac下命令行批量重命名

    日常中碰到需要批量修改文件名怎么办?嗯,来终端先 案例:将Users/case目录下所有html文件修改为php文件 步骤: 1.进入目标文件夹 $ cd Users/case 2.执行以下命令 $ ...