【H2O2|全栈】MySQL的基本操作(三)

目录

前言

开篇语

准备工作

案例准备

多表查询

笛卡尔积

等值连接

外连接

内连接

自连接

子查询

存在和所有

含于

分页查询

建表语句

结束语


前言

开篇语

本篇继续讲解MySQL的一些基础的操作------数据字段的查询中的多表查询和分页查询,与单表查询相比,这些在面试时会更加常用。

准备工作

软件:【参考版本】Navicat Premium 16 / SQLyog - 32 bit

**语言:**MySQL

**版本信息:**MySQL5.7

案例准备

本次的案例为四张表,创建的语句比较长,放在本章的最后,请自行跳转至对应位置复制创建。

参考库结构------

dept部门表结构(4行3列)------

emp员工表结构(14行8列)------

多表查询

笛卡尔积

概念

笛卡尔积查询的结果是两张被查询的表的列数相加行数相乘

比如说一张三列四行的表和一张四列六行的表查询,在不进行过滤去重的条件下,查询的结果就是一张七列二十四行的新表,相同的列不会合并。

案例

1.员工表emp和部门表dept的笛卡尔积

select emp.*,dept.*

from emp,dept

可以看到,多表查询的from语句里不止有一张表。查询的结果是11*56,相同的列deptno(部门编号并未被合并)。

等值连接

概念

过滤条件中涉及到两张表的某一条件对应相同(=)时,就可以使用等值连接查询。

而其余的情况就是非等值连接,比如使用>=,<=,<>,betwen and等作为过滤条件。

关键字

=

案例

1.使用等值连接,显示员工的编号,姓名,部门编号,部门名

select empno, ename, e.deptno, dname

from emp e, dept d where e.deptno = d.deptno

order by e.deptno

由于部门编号实际上在两张表中都有,所以我们可以将该列作为等值连接的过滤条件。

注意,由于这里有两张表,所以要指定使用哪一张表的部门编号,否则会提醒你不知道要找的是哪一张表的这一列------

外连接

概念

外连接实际上分为左外连接和右外连接两种,一般来说,以左表作为基准就是左外连接,反之就是右外连接。

那么,什么是以左表为基准呢?实际上就是左表中有的条件,右表中可能是没有的,但是我们需要把右表强行对应拼到左表中,如果拼接位置找不到对应的数据,则结果里的该位置处为NULL

以谁为基准,就应当保证结果中有谁的全部数据,而不保证另一侧。

关键字

LEFT JOIN

ON

RIGHT JOIN

ON

案例

1.外连接 查询 员工编号 员工姓名 部门编号 部门名称

这里以左外连接为例------

select empno, ename, e.deptno, d.dname

from emp e left join dept d

on e.deptno = d.deptno order by e.deptno

可以看到,外连接和笛卡尔积查询的结果非常相似,只是把并列的两张表变成了外连接,然后把过滤条件放到ON中了。

实质上,笛卡尔积查询和外连接查询可以相互转化

内连接

概念

当数据项既满足左外连接,又满足右外连接,即为两表**有关联(不会补NULL)**的数据项时,就是内连接了。

在数学上,我们也可以把内连接的结果看做是两表的交集

关键字

INNER JOIN

ON

案例

1.内连接 查询 员工编号 员工姓名 部门编号 部门名称

select empno,ename,e.deptno, d.dname

from emp e inner join dept d on e.deptno = d.deptno order by e.deptno

自连接

概念

自连接实际上就是相当于将自身复制一份,然后让自身和复制表之间实现连接。

案例

1.使用自连接,显示"XXX的上级是XXX"这种格式,对于没有上级的,显示为"无"

select concat(u.ename, '的上级是', ifnull(boss.ename, "无")) 附属关系

from emp u

left join emp boss

on u.mgr = boss.empno;

实际上,这里就是将一张表作为员工表,取的是员工姓名;

而部分员工是有下属的,所以员工表也可以作为上级表使用,两表的连接条件就是员工表的mgr编号与上级表的empno编号一致。

而部分员工可能没有上级,比如说KING的mgr为NULL,说明员工表实际上是外连接中的基准表。

使用**IFNULL()**来处理NULL的问题,否则整个varchar的值在拼接后会变为NULL。

子查询

概念

子查询的作用是,查询条件未知的事物,将查询的结果作为父查询的条件使用。

一般来说,子查询有下面的要点------

  1. 子查询与父查询可以针对不同的表,也可以针对同一张表

  2. 子查询与父查询在传参时,参数数量、类型和含义要相同

说白了,子查询可以看做一个(组)参数,或代表一张表。

但是子查询的效率是很低的,应当尽量少用。

案例

1.查询出高于10号部门的平均工资的员工信息

select *

from emp

where sal > (select avg(sal) from emp where deptno = 10)

实际上,我们需要做两次查表的操作,第一次是查询所有员工的信息(父查询),第二次是查询10号部门的平均工资(子查询)。

然后,将子查询的结果(avg(sal))作为父查询的过滤条件,完成查询需求。

2.查询出有哪些部门的平均工资高于30号部门的平均工资,部门编号 部门名称 平均工资

select e.deptno, dname, avg(sal)

from emp e, dept d

where e.deptno <> 30 and e.deptno = d.deptno

group by e.deptno, dname

having avg(sal) > (select avg(sal) from emp where deptno = 30)

对于多行函数AVG(),该过滤条件需要添加到HAVING分组过滤关键字中。

不要忘记两表公有的列一定要指定是哪一张表的该列。

3.查询各部门中工资比本部门平均工资高的员工的员工号 姓名 工资

select empno, ename, sal

from emp e, (select avg(sal) avsa, deptno from emp group by deptno) f

where e.deptno = f.deptno

and sal > avsa

子查询的结果实际上也可以看成一张表,为了使这张新表 f 能够与员工表 e 有关联,我们可以为新表添加一个公共列deptno。

存在和所有

概念

存在是指,在结果集中至少有一个结果符合条件就符合;

所有是指,结果集的所有结果都符合条件才符合。

关键字

ANY()

ALL()

案例

1.查询出比20号部门任一员工薪资高的员工信息

select *

from emp

where sal > any(select sal from emp where deptno = 30)

这里涉及到员工表和只有30号部门员工的子表,所以用到的是子查询。

而过滤条件里要求查询的工资比任一结果高,即至少有一个符合(最低薪资)即可,所以可以使用ANY关键字。

2.查询出比30号部门任何员工薪资高的员工信息

select *

from emp

where sal > all(select sal from emp where deptno = 30)

这里要求比任何30号部门员工工资都高,所以使用ALL关键字。

实际上,在部分情况下,ANY和ALL与MIN()和MAX()函数的作用是相同。

含于

概念

含于是指某个(些)筛选内容包含在结果集中,筛选内容需要与结果集中内容对应。

关键字

IN()

案例

1.查询工作和工资与MARTIN完全相同的员工信息

select *

from emp

where (job, sal) in(select job, sal from emp where ename = "MARTIN")

我们的子查询查询出了两列的内容,而筛选条件job和sal与这两列一一对应。

分页查询

概念

分页查询是指查询指定表中的某一条至某一条的行。

关键字

LIMIT start, number

其中start为开始的索引值(从0开始),number为查询的条数。

案例

1.查询工资排名第4到8名的员工的信息

select *

from emp

order by sal

limit 3, 5

建表语句

员工表

CREATE TABLE `emp` (
  `empno` INT(4) NOT NULL COMMENT '员工编号',
  `ename` VARCHAR(10) DEFAULT NULL COMMENT '员工姓名',
  `job` VARCHAR(9) DEFAULT NULL COMMENT '员工岗位',
  `mgr` INT(4) DEFAULT NULL COMMENT '领导编号',
  `hiredate` DATE DEFAULT NULL COMMENT '入职时间',
  `sal` DECIMAL(7,2) DEFAULT NULL COMMENT '工资',
  `comm` DECIMAL(7,2) DEFAULT NULL COMMENT '奖金',
  `deptno` INT(2) DEFAULT NULL COMMENT '部门编号',
  PRIMARY KEY (`empno`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

员工表数据

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7369', 'SMITH', 'CLERK', '7902','1980-12-17', '800', NULL, '20');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', NULL, '20');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', NULL, '30');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', NULL, '10');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-06-13', '3000', NULL, '20');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7839', 'KING', 'PRESIDENT', NULL, '1981-11-17', '5000', NULL, '10');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500', '0', '30');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-06-13', '1100', NULL, '20');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', NULL, '30');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', NULL, '20');

INSERT INTO emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', NULL, '10');

部门表

CREATE TABLE dept(
  deptno INT(2) PRIMARY KEY NOT NULL,
  dname  VARCHAR(14),
  loc    VARCHAR(13)
);

部门表数据

INSERT INTO dept (DEPTNO, DNAME, LOC)
VALUES ('10', 'ACCOUNTING', 'NEW YORK');

INSERT INTO dept (DEPTNO, DNAME, LOC)
VALUES ('20', 'RESEARCH', 'DALLAS');

INSERT INTO dept (DEPTNO, DNAME, LOC)
VALUES ('30', 'SALES', 'CHICAGO');

INSERT INTO dept (DEPTNO, DNAME, LOC)
VALUES ('40', 'OPERATIONS', 'BOSTON');

结束语

本期内容到此结束。关于本系列的其他博客,可以查看我的MySQL专栏。

本系列的博客主要是记录学习经历,并总结阶段的知识点。全篇的操作过程由笔者完成并核验,在部分定义上有参考其他的内容。本身也是新手,多多包涵。

==期待与你在下一期博客中再次相遇==

------放了挺久的【H2O2】

相关推荐
月光水岸New25 分钟前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山67526 分钟前
数据库基础1
数据库
我爱松子鱼30 分钟前
mysql之规则优化器RBO
数据库·mysql
chengooooooo1 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser2 小时前
【SQL】多表查询案例
数据库·sql
Galeoto2 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
人间打气筒(Ada)2 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231112 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
喝醉酒的小白2 小时前
PostgreSQL:更新字段慢
数据库·postgresql
敲敲敲-敲代码2 小时前
【SQL实验】触发器
数据库·笔记·sql