mysql学+练

从开始到放弃!

开始

mysql -uroot -p123456

退出命令

exit 或者 quit

注释

# show databases; 单行注释
-- show databases; 单行注释
/*
多行注释
show databases;
*/

DDL操作数据库

创建

/*
方式1 直接指定数据库名进行创建
*/
CREATE DATABASE db1;
/*
方式2 指定数据库名称,指定数据库的字符集
一般都指定为 utf8
*/
CREATE DATABASE db1_1 CHARACTER SET utf8;
mysql> create database db1;
Query OK, 1 row affected (0.00 sec)

mysql> create database db1_1 character set utf8;
Query OK, 1 row affected (0.00 sec)

查看/选择数据库

命令 说明
use 数据库 切换数据库
select database(); 查看当前正在使用的数据库
show databases; 查看Mysql中 都有哪些数据库
show create database 数据库名; 查看一个数据库的定义信息

-- 切换数据库 从db1 切换到 db1_1
USE db1_1;
-- 查看当前正在使用的数据库
SELECT DATABASE();
-- 查看Mysql中有哪些数据库
SHOW DATABASES;
-- 查看一个数据库的定义信息
SHOW CREATE DATABASE db1_1;
mysql> use db1_1;
Database changed
mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| db1_1      |
+------------+
1 row in set (0.00 sec)

mysql> show create database db1_1;
+----------+----------------------------------------------------------------+
| Database | Create Database                                                |
+----------+----------------------------------------------------------------+
| db1_1    | CREATE DATABASE `db1_1` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+----------------------------------------------------------------+
1 row in set (0.00 sec)

修改数据库

命令 说明
alter database 数据库名 character set 字符集 数据库的字符集修改操作
-- 将数据库db1 的字符集 修改为 utf8
ALTER DATABASE db1 CHARACTER SET utf8;
-- 查看当前数据库的基本信息,发现编码已更改
SHOW CREATE DATABASE db1;
mysql> alter database db1 character set utf8;
Query OK, 1 row affected (0.00 sec
mysql> show create database db1;
+----------+--------------------------------------------------------------+
| Database | Create Database                                              |
+----------+--------------------------------------------------------------+
| db1      | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+--------------------------------------------------------------+
1 row in set (0.00 sec)

删库跑路

-- 删除某个数据库
DROP DATABASE db1_1;
mysql> drop database db1_1;
Query OK, 0 rows affected (0.01 sec)

DDL操作数据表

常用的数据类型:
类型 描述
int 整型
double 浮点型
varchar 字符串型
date 日期类型,给是为 yyyy-MM-dd ,只有年月日,没有时分秒

注意:MySql中的 char类型与 varchar类型,区别在于:
char类型是固定长度的: 根据定义的字符串长度分配足够的空间。
varchar类型是可变长度的: 只使用字符串长度所需的空间

x char(10) 占用10个字节
y varchar(10) 占用3个字节

适用场景:
char类型适合存储 固定长度的字符串,比如 密码 ,性别一类
varchar类型适合存储 在一定范围内,有长度变化的字符串
存储空间 查询效率
char 耗费空间 高
varchar 节省空间 不高

创建表

语法

CREATE TABLE 表名(
字段名称1 字段类型(长度),
字段名称2 字段类型 注意 最后一列不要加逗号
)
mysql> create table category(
    -> cid int,
    -> cname varchar(20)
    -> );
Query OK, 0 rows affected (0.01 sec)

快速创建一个表结构相同的表(复制表结构)`

create table 新表名 like 旧表名;
mysql> create table test2 like test1;
Query OK, 0 rows affected (0.01 sec)

查看表

命令 说明
show tables; 查看当前数据库中的所有表名
desc 表名; 查看数据表的结构

mysql> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| category      |
| test1         |
| test2         |
+---------------+
3 rows in set (0.00 sec)
mysql> desc category;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| cid   | int(11)     | YES  |     | NULL    |       |
| cname | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> show create table category;
+----------+---------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                    |
+----------+---------------------------------------------------------------------------------------------------------------------------------+
| category | CREATE TABLE `category` (
  `cid` int(11) DEFAULT NULL,
  `cname` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+---------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

删除表

命令 说明
drop table 表名; 删除表(从数据库中永久删除某一张表)
drop table if exists 表名; 判断表是否存在, 存在的话就删除,不存在就不执行删除

mysql> drop table test1;
Query OK, 0 rows affected (0.00 sec)
mysql> drop table if exists test2;
Query OK, 0 rows affected (0.00 sec)
mysql> rename table category1 to category;
Query OK, 0 rows affected (0.01 sec)

mysql> alter table category add cdesc varchar(20);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table category modify cdesc varchar(50);
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

整体作业练习

mysql> create database test charset='utf8';
Query OK, 1 row affected (0.01 sec)

mysql> use test;
Database changed
mysql> create table goods(
    -> id int auto_increment primary key not null,
    -> name varchar(50) not null
    -> );
Query OK, 0 rows affected (0.04 sec)

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| goods          |
+----------------+
1 row in set (0.00 sec)

mysql> insert into goods values(0,'大豆'),(0,'玉米'),(0,'花生'),(0,'小麦');;             -> insert into goods values(0,'大豆'),(0,'玉米'),(0,'花生'),(0,'小麦');
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ';;
insert into goods values(0,'大豆'),(0,'玉米'),(0,'花生'),(0,'小麦' at line 1
mysql> insert into goods values(0,'大豆'),(0,'玉米'),(0,'花生'),(0,'小麦');         Query OK, 4 rows affected (0.03 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from goods;
+----+--------+
| id | name   |
+----+--------+
|  1 | 大豆   |
|  2 | 玉米   |
|  3 | 花生   |
|  4 | 小麦   |
+----+--------+
4 rows in set (0.00 sec)

mysql> update goods set name='紫薯' where id=4;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from goods;
+----+--------+
| id | name   |
+----+--------+
|  1 | 大豆   |
|  2 | 玉米   |
|  3 | 花生   |
|  4 | 紫薯   |
+----+--------+
4 rows in set (0.00 sec)

mysql> delete from goods where id=4;
Query OK, 1 row affected (0.00 sec)

mysql> select *  from goods where id=4;
Empty set (0.00 sec)

DQL 查询表中数据

简单查询

准备数据
创建员工表

CREATE TABLE emp(
eid INT,
ename VARCHAR(20),
sex CHAR(1),
salary DOUBLE,
hire_date DATE,
dept_name VARCHAR(20)
);
#添加数据
INSERT INTO emp VALUES(1,'孙悟空','男',7200,'2013-02-04','教学部');
INSERT INTO emp VALUES(2,'猪八戒','男',3600,'2010-12-02','教学部');
INSERT INTO emp VALUES(3,'唐僧','男',9000,'2008-08-08','教学部');
INSERT INTO emp VALUES(4,'白骨精','女',5000,'2015-10-07','市场部');
INSERT INTO emp VALUES(5,'蜘蛛精','女',5000,'2011-03-14','市场部');
INSERT INTO emp VALUES(6,'玉兔精','女',200,'2000-03-14','市场部');
INSERT INTO emp VALUES(7,'林黛玉','女',10000,'2019-10-07','财务部');
INSERT INTO emp VALUES(8,'黄蓉','女',3500,'2011-09-14','财务部');
INSERT INTO emp VALUES(9,'吴承恩','男',20000,'2000-03-14',NULL);
INSERT INTO emp VALUES(10,'孙悟饭','男', 10,'2020-03-14','财务部');
  1. 执行顺序

FROM --> WHERE --> GROUP BY --> HAVING --> SELECT --> ORDER BY

  1. 查询

select * from 表名

别名查询,使用关键字 as

mysql> select 
    -> eid as '编码',
    -> ename as '姓名',
    -> sex as '性别',
    -> salary as '薪资',
    -> hire_date '入职时间',
    -> dept_name '部门名称'
    -> from emp;
+--------+-----------+--------+--------+--------------+--------------+
| 编码   | 姓名      | 性别   | 薪资   | 入职时间     | 部门名称     |
+--------+-----------+--------+--------+--------------+--------------+
|      1 | 孙悟空    ||   7200 | 2013-02-04   | 教学部       |
|      2 | 猪八戒    ||   3600 | 2010-12-02   | 教学部       |
|      3 | 唐僧      ||   9000 | 2008-08-08   | 教学部       |
|      4 | 白骨精    ||   5000 | 2015-10-07   | 市场部       |
|      5 | 蜘蛛精    ||   5000 | 2011-03-14   | 市场部       |
|      6 | 玉兔精    ||    200 | 2000-03-14   | 市场部       |
|      7 | 林黛玉    ||  10000 | 2019-10-07   | 财务部       |
|      8 | 黄蓉      ||   3500 | 2011-09-14   | 财务部       |
|      9 | 吴承恩    ||  20000 | 2000-03-14   | NULL         |
|     10 | 孙悟饭    ||     10 | 2020-03-14   | 财务部       |
+--------+-----------+--------+--------+--------------+--------------+
10 rows in set (0.00 sec)
  1. 使用去重关键字 distinct
mysql> select distinct dept_name from emp;
+-----------+
| dept_name |
+-----------+
| 教学部    |
| 市场部    |
| 财务部    |
| NULL      |
+-----------+
4 rows in set (0.01 sec)
  1. 将所有员工的工资 +1000 元进行显示
    运算查询 (查询结果参与运算)
mysql> select ename,salary +1000 from emp;
+-----------+--------------+
| ename     | salary +1000 |
+-----------+--------------+
| 孙悟空    |         8200 |
| 猪八戒    |         4600 |
| 唐僧      |        10000 |
| 白骨精    |         6000 |
| 蜘蛛精    |         6000 |
| 玉兔精    |         1200 |
| 林黛玉    |        11000 |
| 黄蓉      |         4500 |
| 吴承恩    |        21000 |
| 孙悟饭    |         1010 |
+-----------+--------------+
10 rows in set (0.00 sec)
  1. 条件查询
    如果查询语句中没有设置条件,就会查询所有的行信息,在实际应用中,一定要指定查询条件,对记
    录进行过滤
select 列名 from 表名 where 条件表达式

运算符 说明

< <= >= = <> != 大于、小于、小于(大于)等于、等于、不等于
BETWEEN …AND…
显示在某一区间的值
例如: 2000-10000之间: Between 2000 and 10000
IN(集合)
集合表示多个值,使用逗号分隔,例如: name in (悟空,八戒)
in中的每个数据都会作为一次条件,只要满足条件就会显示
LIKE ‘%张%’ 模糊查询
IS NULL 查询某一列为NULL的值, 注: 不能写 = NULL
运算符 说明
And && 多个条件同时成立
Or || 多个条件任一成立
Not 不成立,取反。

  1. 需求
# 查询员工姓名为黄蓉的员工信息
# 查询薪水价格为5000的员工信息
# 查询薪水价格不是5000的所有员工信息
# 查询薪水价格大于6000元的所有员工信息
# 查询薪水价格在5000到10000之间所有员工信息
# 查询薪水价格是3600或7200或者20000的所有员工信息
mysql> select * from emp where ename='黄蓉';
+------+--------+------+--------+------------+-----------+
| eid  | ename  | sex  | salary | hire_date  | dept_name |
+------+--------+------+--------+------------+-----------+
|    8 | 黄蓉   ||   3500 | 2011-09-14 | 财务部    |
+------+--------+------+--------+------------+-----------+
1 row in set (0.00 sec)

mysql> select * from emp where salary=5000;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
+------+-----------+------+--------+------------+-----------+
2 rows in set (0.00 sec)

mysql> select * from emp where salary!=5000;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    2 | 猪八戒    ||   3600 | 2010-12-02 | 教学部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    6 | 玉兔精    ||    200 | 2000-03-14 | 市场部    |
|    7 | 林黛玉    ||  10000 | 2019-10-07 | 财务部    |
|    8 | 黄蓉      ||   3500 | 2011-09-14 | 财务部    |
|    9 | 吴承恩    ||  20000 | 2000-03-14 | NULL      |
|   10 | 孙悟饭    ||     10 | 2020-03-14 | 财务部    |
+------+-----------+------+--------+------------+-----------+
8 rows in set (0.00 sec)

mysql> select * from emp where salary>6000;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    7 | 林黛玉    ||  10000 | 2019-10-07 | 财务部    |
|    9 | 吴承恩    ||  20000 | 2000-03-14 | NULL      |
+------+-----------+------+--------+------------+-----------+
4 rows in set (0.00 sec)

mysql> select * from emp where salary between 5000 and 10000;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
|    7 | 林黛玉    ||  10000 | 2019-10-07 | 财务部    |
+------+-----------+------+--------+------------+-----------+
5 rows in set (0.00 sec)

mysql> select * from emp where salary=3600 or salary=7200 or 20000;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    2 | 猪八戒    ||   3600 | 2010-12-02 | 教学部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
|    6 | 玉兔精    ||    200 | 2000-03-14 | 市场部    |
|    7 | 林黛玉    ||  10000 | 2019-10-07 | 财务部    |
|    8 | 黄蓉      ||   3500 | 2011-09-14 | 财务部    |
|    9 | 吴承恩    ||  20000 | 2000-03-14 | NULL      |
|   10 | 孙悟饭    ||     10 | 2020-03-14 | 财务部    |
+------+-----------+------+--------+------------+-----------+
10 rows in set (0.00 sec)

# 查询薪水价格是3600或7200或者20000的所有员工信息
-- 方式1: or
SELECT * FROM emp WHERE salary = 3600 OR salary = 7200 OR salary = 20000;
-- 方式2: in() 匹配括号中指定的参数
SELECT * FROM emp WHERE salary IN(3600,7200,20000);

需求2

# 查询含有'精'字的所有员工信息
# 查询以'孙'开头的所有员工信息
# 查询第二个字为'兔'的所有员工信息
# 查询没有部门的员工信息
# 查询有部门的员工信息

模糊查询 通配符
通配符 说明
% 表示匹配任意多个字符串,
_ 表示匹配 一个字符

mysql> select * from emp where ename like '%精%';
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
|    6 | 玉兔精    ||    200 | 2000-03-14 | 市场部    |
+------+-----------+------+--------+------------+-----------+
3 rows in set (0.00 sec)
mysql> select * from emp where ename like '孙%';
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|   10 | 孙悟饭    ||     10 | 2020-03-14 | 财务部    |
+------+-----------+------+--------+------------+-----------+
2 rows in set (0.01 sec)

mysql> select * from emp where ename like '_兔%';
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    6 | 玉兔精    ||    200 | 2000-03-14 | 市场部    |
+------+-----------+------+--------+------------+-----------+
1 row in set (0.00 sec)

mysql> select * from emp where dept_name is null;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    9 | 吴承恩    ||  20000 | 2000-03-14 | NULL      |
+------+-----------+------+--------+------------+-----------+
1 row in set (0.00 sec)
mysql> select * from emp where dept_name is not null;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    2 | 猪八戒    ||   3600 | 2010-12-02 | 教学部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
|    6 | 玉兔精    ||    200 | 2000-03-14 | 市场部    |
|    7 | 林黛玉    ||  10000 | 2019-10-07 | 财务部    |
|    8 | 黄蓉      ||   3500 | 2011-09-14 | 财务部    |
|   10 | 孙悟饭    ||     10 | 2020-03-14 | 财务部    |
+------+-----------+------+--------+------------+-----------+
9 rows in set (0.00 sec)

第二部分 MySQL核心查询

排序 分组 聚合 多表查询 合并查询 子查询
第1节 单表查询

1.1 排序

通过 ORDER BY 子句,可以将查询出的结果进行排序(排序只是显示效果,不会影响真实数据)
语法结构

SELECT 字段名 FROM 表名 [WHERE 字段 = 值] ORDER BY 字段名 [ASC / DESC]

ASC 表示升序排序(默认)
DESC 表示降序排序

1.1.1 单列排序
只按照某一个字段进行排序, 就是单列排序
需求1:
使用 salary 字段,对emp 表数据进行排序 (升序/降序)

mysql> select * from emp order by salary desc,eid desc;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    9 | 吴承恩    ||  20000 | 2000-03-14 | NULL      |
|    7 | 林黛玉    ||  10000 | 2019-10-07 | 财务部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    2 | 猪八戒    ||   3600 | 2010-12-02 | 教学部    |
|    8 | 黄蓉      ||   3500 | 2011-09-14 | 财务部    |
|    6 | 玉兔精    ||    200 | 2000-03-14 | 市场部    |
|   10 | 孙悟饭    ||     10 | 2020-03-14 | 财务部    |
+------+-----------+------+--------+------------+-----------+
10 rows in set (0.00 sec)

1.2 聚合函数

干嘛的?求员工最高工资/平均工资/工资总和,都是聚合函数来做的
之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断,而使用聚合函数查

询是纵向查询,它是对某一列的值进行计算,然后返回一个单一的值(另外聚合函数会忽略null空
值。);
聚合,也称为聚合统计或者聚合查询,就需要使用select关键字,有select 就得有from xxx
语法结构

SELECT 聚合函数(字段名) FROM 表名;

聚合函数 作用
count(字段) 统计指定列不为NULL的记录行数
sum(字段) 计算指定列的数值和
max(字段) 计算指定列的最大值
min(字段) 计算指定列的最小值
avg(字段) 计算指定列的平均值

需求1

#1 查询员工的总数
#2 查看员工总薪水、最高薪水、最小薪水、薪水的平均值
#3 查询薪水大于4000员工的个数
#4 查询部门为'教学部'的所有员工的个数
#5 查询部门为'市场部'所有员工的平均薪水
#1 查询员工的总数
-- 统计表中的记录条数 使用 count()
SELECT COUNT(eid) FROM emp; -- 使用某一个字段
SELECT COUNT(*) FROM emp; -- 使用 *
SELECT COUNT(1) FROM emp; -- 使用 1,* 效果一样
-- 下面这条SQL 得到的总条数不准确,因为count函数忽略了空值
-- 所以使用时注意不要使用带有null的列进行统计
SELECT COUNT(dept_name) FROM emp;
#2 查看员工总薪水、最高薪水、最小薪水、薪水的平均值
-- sum函数求和, max函数求最大, min函数求最小, avg函数求平均值
SELECT
SUM(salary) AS '总薪水',
MAX(salary) AS '最高薪水',
MIN(salary) AS '最低薪水',
AVG(salary) AS '平均薪水'
FROM emp;
#3 查询薪水大于4000员工的个数
SELECT COUNT(*) FROM emp WHERE salary > 4000;
#4 查询部门为'教学部'的所有员工的个数
SELECT COUNT(*) FROM emp WHERE dept_name = '教学部';
#5 查询部门为'市场部'所有员工的平均薪水
SELECT
AVG(salary) AS '市场部平均薪资'
FROM emp
WHERE dept_name = '市场部';

1.3 分组

分组往往和聚合函数一起时候,对数据进行分组,分完组之后在各个组内进行聚合统计分析
比如:求各个部门的员工数~
分组查询指的是使用 GROUP BY 语句,对查询的信息进行分组,相同数据作为一组
语法格式

SELECT 分组字段/聚合函数 FROM 表名 GROUP BY 分组字段 [HAVING 条件];
  • 分组时可以查询要分组的字段, 或者使用聚合函数进行统计操作.不然就没有意义
  • 查询其他字段没有意义
  • 记住:
    –group by的字段必须出现在前面select的位置
    —前面select的位置,除了group by的字段、聚合函数,不能出现其他字段

where 与 having的区别 重点注意!!!!!!!!面试必问

过滤方式 特点

where
where 进行分组前的过滤
where 后面不能写 聚合函数
having
having 是分组后的过滤
having 后面可以写 聚合函数

limit 关键字的作用

limit是限制的意思,用于限制返回的查询结果的行数 (可以通过limit指定查询多少行数据)
limit 语法是 MySql的方言,用来完成分页

SELECT 字段1,字段2... FROM 表名 LIMIT offset , length;

需求1

# 查询emp表中的前 5条数据
# 查询emp表中 从第4条开始,查询6条

limit offset , length; 关键字可以接受一个 或者两个 为0 或者正整数的参数
offset 起始行数, 从0开始记数, 如果省略 则默认为 0.
length 返回的行数

# 查询emp表中的前 5条数据
-- 参数1 起始值,默认是0 , 参数2 要查询的条数
SELECT * FROM emp LIMIT 5;
SELECT * FROM emp LIMIT 0 , 5;
+------+-----------+------+--------+------------+-----------+
| eid  | ename     | sex  | salary | hire_date  | dept_name |
+------+-----------+------+--------+------------+-----------+
|    1 | 孙悟空    ||   7200 | 2013-02-04 | 教学部    |
|    2 | 猪八戒    ||   3600 | 2010-12-02 | 教学部    |
|    3 | 唐僧      ||   9000 | 2008-08-08 | 教学部    |
|    4 | 白骨精    ||   5000 | 2015-10-07 | 市场部    |
|    5 | 蜘蛛精    ||   5000 | 2011-03-14 | 市场部    |
+------+-----------+------+--------+------------+-----------+
5 rows in set (0.00 sec)

# 查询emp表中 从第4条开始,查询6条
-- 起始值默认是从0开始的.
SELECT * FROM emp LIMIT 3 , 6;

需求2: 分页操作 每页显示3条数据

-- 分页操作 每页显示3条数据
SELECT * FROM emp LIMIT 0,3; -- 第1页
SELECT * FROM emp LIMIT 3,3; -- 第2页 2-1=1 1*3=3
SELECT * FROM emp LIMIT 6,3; -- 第三页
-- 分页公式 起始索引 = (当前页 - 1) * 每页条数
-- limit是MySql中的方言

**

第2节 SQL约束

SQL语句来创建数据库约束
1)约束的作用:
对表中的数据进行进一步的限制,从而保证数据的正确性、有效性、完整性.
违反约束的不正确数据,将无法插入到表中
注意:约束是针对字段的
2)常见的约束
约束名 : 约束关键字
主键 : primary key
唯一 : unique
非空 : not null
外键 : foreign key
2.1 主键约束
特点: 不可重复 唯一 非空
作用 :用来表示数据库中的每一条记录(用来唯一标识数据表中的一条记录)
3) 哪些字段可以作为主键 ?
通常针对业务去设计主键,往往每张表都设计一个主键
主键是给数据库和程序使用的,跟最终的客户无关,所以主键没有意义没有关系,只要能够保证
不重复就好
比如 身份证号列就可以作为主键.
另外,如果没有和业务关联太大的可以设计为主键的列的话,我们在进行数据库设计的时
候往往人为加一列作为主键列,习惯上起名为id,rid等
2.1.2 删除主键约束
删除 表中的主键约束 (了解)

-- 使用DDL语句 删除表中的主键
ALTER TABLE emp2 DROP PRIMARY KEY;
DESC emp2;

2.1.3 主键的自增
注: 主键如果让我们自己添加很有可能重复,我们通常希望在每次插入新记录时,数据库自动生成
主键字段的值.

-- 创建主键自增的表
CREATE TABLE emp2(
-- 关键字 AUTO_INCREMENT,主键类型必须是整数类型
eid INT PRIMARY KEY AUTO_INCREMENT,
ename VARCHAR(20),
sex CHAR(1)
);
INSERT INTO emp2(ename,sex) VALUES('张三','男');
INSERT INTO emp2(ename,sex) VALUES('李四','男');
INSERT INTO emp2 VALUES(NULL,'翠花','女');
INSERT INTO emp2 VALUES(NULL,'艳秋','女');

2.1.4 修改主键自增的起始值
默认地 AUTO_INCREMENT 的开始值是 1,如果希望修改起始值,请使用下面的方式

-- 创建主键自增的表,自定义自增其实值
CREATE TABLE emp2(
eid INT PRIMARY KEY AUTO_INCREMENT,
ename VARCHAR(20),
sex CHAR(1)
)AUTO_INCREMENT=100;
-- 插入数据,观察主键的起始值
INSERT INTO emp2(ename,sex) VALUES('张百万','男');
INSERT INTO emp2(ename,sex) VALUES('艳秋','女');

2.1.5 DELETE和TRUNCATE对自增长的影响
删除表中所有数据有两种方式

清空表数据的方式 特点
DELETE :只是删除表中所有数据,对自增没有影响
TRUNCATE
truncate: 是将整个表删除掉,然后创建一个新的表
自增的主键,重新从 1开始

2.2 非空约束

特点:某⼀列不允许为空
需求1: 为 ename 字段添加非空约束

mysql> create table emp2_3(
    -> eid int primary key auto_increment,
    -> ename varchar(20) not null,
    -> sex char(1)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> desc emp2_3;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| eid   | int(11)     | NO   | PRI | NULL    | auto_increment |
| ename | varchar(20) | NO   |     | NULL    |                |
| sex   | char(1)     | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

2.3 唯一约束

唯一约束的特点: 表中的某一列的值不能重复( 对null不做唯一的判断 )
语法格式

字段名 字段值 unique
#创建emp3表 为ename 字段添加唯一约束
CREATE TABLE emp3(
eid INT PRIMARY KEY AUTO_INCREMENT,
ename VARCHAR(20) UNIQUE,
sex CHAR(1)
);

-- 测试唯一约束 添加一条数据
INSERT INTO emp3 (ename,sex) VALUES('张百万','男');
-- 添加一条 ename重复的 数据
-- Duplicate entry '张百万' for key 'ename' ename不能重复
INSERT INTO emp3 (ename,sex) VALUES('张百万','女');

mysql> INSERT INTO emp3 (ename,sex) VALUES('张百万','男');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO emp3 (ename,sex) VALUES('张百万','女');
ERROR 1062 (23000): Duplicate entry '张百万' for key 'ename'
mysql> 

主键约束与唯一约束的区别:

  1. 主键约束 唯一且不能够为空(主键约束=非空约束+唯一约束)
  2. 唯一约束,唯一 但是可以为空
  3. 一个表中只能有一个主键 , 但是可以有多个唯一约束

2.4 外键约束

FOREIGN KEY 表示外键约束,将在多表中学习。

2.5 默认值

默认值约束 用来指定某列的默认值
语法格式

字段名 字段类型 DEFAULT 默认值
  1. 创建emp4表, 性别字段默认 女
-- 创建带有默认值的表
CREATE TABLE emp4(
 eid INT PRIMARY KEY AUTO_INCREMENT,
 -- 为ename 字段添加默认值
 ename VARCHAR(20) DEFAULT '女', 
 sex CHAR(1)
);
  1. 测试 添加数据使用默认值
-- 添加数据 使用默认值
INSERT INTO emp4(ename,sex) VALUES(DEFAULT,'男');
INSERT INTO emp4(sex) VALUES('女');
-- 不使用默认值
INSERT INTO emp4(ename,sex) VALUES('艳秋','女');

第3节 多表查询

3.1 外键约束

主键:数据表A中有一列,这一列可以唯一的标识一条记录
外键:数据表A中有一列,这一列指向了另外一张数据表B的主键

3.1.1 什么是外键

  • 外键指的是在 从表 中 与 主表 的主键对应的那个字段,比如员工表的 dept_id,就是外键

  • 使用外键约束可以让两张表之间产生一个对应关系,从而保证主从表的引用的完整性

多表关系中的主表和从表
主表: 主键id所在的表, 约束别人的表
从表: 外键所在的表多, 被约束的表

3.1.2 创建外键约束

语法格式:

  1. 新建表时添加外键
[CONSTRAINT] [外键约束名称] FOREIGN KEY(外键字段名) REFERENCES 主表名(主键字
段名)
  1. 已有表添加外键
ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称] FOREIGN KEY (外键字段名)
REFERENCES 主表(主 键字段名);

-- 重新创建 employee表,添加外键约束
CREATE TABLE employee(
eid INT PRIMARY KEY AUTO_INCREMENT,
ename VARCHAR(20),
age INT,
dept_id INT, -- 外键字段类型要和主表的主键字段类型保持一致
-- 添加外键约束
CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id)
);

3.1.3 删除外键约束

添加/删除外键针对的都是从表
语法格式

alter table 从表 drop foreign key 外键约束名称
  1. 删除 外键约束
1) 删除 外键约束
2) 再将外键 添加回来

  1. 再将外键 添加回来
    语法格式
ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称] FOREIGN KEY (外键字段名)
REFERENCES 主表(主 键字段名);
-- 可以省略外键名称, 系统会自动生成一个
ALTER TABLE employee ADD FOREIGN KEY (dept_id) REFERENCES department (id);

3.1.4 外键约束的注意事项

  1. 从表外键类型必须与主表主键类型一致 否则创建失败
  2. 添加数据时, 应该先添加主表中的数据.
-- 添加一个新的部门
INSERT INTO department(dep_name,dep_location) VALUES('市场部','北京');
-- 添加一个属于市场部的员工
INSERT INTO employee(ename,age,dept_id) VALUES('老胡',24,3);
  1. 删除数据时,应该先删除从表中的数据.
-- 删除数据时 应该先删除从表中的数据
-- 报错 Cannot delete or update a parent row: a foreign key constraint
fails
-- 报错原因 不能删除主表的这条数据,因为在从表中有对这条数据的引用
DELETE FROM department WHERE id = 3;

-- 先删除从表的关联数据
DELETE FROM employee WHERE dept_id = 3;
-- 再删除主表的数据
DELETE FROM department WHERE id = 3;

3.2 什么是多表查询

  • DQL: 查询多张表(至少涉及2张表),获取到需要的数据
  • 比如 我们要查询家**电分类下 都有哪些商品,**那么我们就
  •  分类表+商品表
    

3.3 数据准备

  1. 创建db3_2 数据库
-- 创建 db3_2 数据库,指定编码
CREATE DATABASE db3_2 CHARACTER SET utf8;
  1. 创建分类表与商品表
#分类表 (一方 主表)
CREATE TABLE category (
cid VARCHAR(32) PRIMARY KEY ,
cname VARCHAR(50)
);
#商品表 (多方 从表)
CREATE TABLE products(
pid VARCHAR(32) PRIMARY KEY ,
pname VARCHAR(50),
#分类表 (一方 主表)
CREATE TABLE category (
cid VARCHAR(32) PRIMARY KEY ,
cname VARCHAR(50)
);
#商品表 (多方 从表)
CREATE TABLE products(
pid VARCHAR(32) PRIMARY KEY ,
pname VARCHAR(50),

3.插入数据

#分类数据
INSERT INTO category(cid,cname) VALUES('c001','家电');
INSERT INTO category(cid,cname) VALUES('c002','鞋服');
INSERT INTO category(cid,cname) VALUES('c003','化妆品');
INSERT INTO category(cid,cname) VALUES('c004','汽车');
#商品数据
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p001','小
米电视机',5000,'1','c001');
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p002','格
力空调',3000,'1','c001');
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p003','美
的冰箱',4500,'1','c001');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p004','篮
球鞋',800,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p005','运
动裤',200,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p006','T
恤',300,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p007','冲
锋衣',2000,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p008','神
仙水',800,'1','c003');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p009','大
宝',200,'1','c003');

3.4 笛卡尔积
交叉连接查询,因为会产生笛卡尔积,所以 基本不会使用

  1. 语法格式
SELECT 字段名 FROM 表1, 表2;
  1. 使用交叉连接查询 商品表与分类表
SELECT * FROM category , products;

  1. 观察查询结果,产生了笛卡尔积 (得到的结果是无法使用的)

3.5 多表查询的分类

3.5.1 内连接查询
内连接的特点:
通过指定的条件去匹配两张表中的数据, 匹配上就显示,匹配不上就不显示
比如通过: 从表的外键 = 主表的主键 方式去匹配

  1. 隐式内链接
    form子句 后面直接写 多个表名 使用where指定连接条件的 这种连接方式是 隐式内连接.
    使用where条件过滤无用的数据

    语法格式
SELECT 字段名 FROM 左表, 右表 WHERE 连接条件;
  1. 查询所有商品信息和对应的分类信息
# 隐式内连接
mysql> select * from products,category where category_id =cid;
+------+------------------+-------+------+-------------+------+-----------+
| pid  | pname            | price | flag | category_id | cid  | cname     |
+------+------------------+-------+------+-------------+------+-----------+
| p001 | 小
米电视机      |  5000 | 1    | c001        | c001 | 家电      |
| p002 | 格
力空调        |  3000 | 1    | c001        | c001 | 家电      |
| p003 | 美
的冰箱        |  4500 | 1    | c001        | c001 | 家电      |
| p004 | 篮
球鞋          |   800 | 1    | c002        | c002 | 鞋服      |
| p005 | 运
动裤          |   200 | 1    | c002        | c002 | 鞋服      |
| p006 | T
恤             |   300 | 1    | c002        | c002 | 鞋服      |
| p007 | 冲
锋衣          |  2000 | 1    | c002        | c002 | 鞋服      |
| p008 | 神
仙水          |   800 | 1    | c003        | c003 | 化妆品    |
| p009 | 大
宝            |   200 | 1    | c003        | c003 | 化妆品    |
+------+------------------+-------+------+-------------+------+-----------+
9 rows in set (0.00 sec)
  1. 查询商品表的商品名称 和 价格,以及商品的分类信息
    可以通过给表起别名的方式, 方便我们的查询(有提示)
mysql> select pname,price,cname from products,category where category_id=cid;
+------------------+-------+-----------+
| pname            | price | cname     |
+------------------+-------+-----------+
| 小
米电视机      |  5000 | 家电      |
| 格
力空调        |  3000 | 家电      |
| 美
的冰箱        |  4500 | 家电      |
| 篮
球鞋          |   800 | 鞋服      |
| 运
动裤          |   200 | 鞋服      |
| T
恤             |   300 | 鞋服      |
| 冲
锋衣          |  2000 | 鞋服      |
| 神
仙水          |   800 | 化妆品    |
| 大
宝            |   200 | 化妆品    |
+------------------+-------+-----------+
9 rows in set (0.00 sec)


  1. 查询 格力空调是属于哪一分类下的商品
mysql> select p.pname,c.cname from products p,category c where category_id=c.cid and p.pid='p002';
+---------------+--------+
| pname         | cname  |
+---------------+--------+
| 格
力空调     | 家电   |
+---------------+--------+
1 row in set (0.00 sec)

2) 显式内连接

使用 inner join …on 这种方式, 就是显式内连接
语法格式

  1. 查询所有商品信息和对应的分类信息
# 显式内连接查询
SELECT * FROM products p INNER JOIN category c ON p.category_id = c.cid;
  1. 查询鞋服分类下,价格大于500的商品名称和价格
# 查询鞋服分类下,价格大于500的商品名称和价格
-- 我们需要确定的几件事
-- 1.查询几张表 products & category
-- 2.表的连接条件 从表.外键 = 主表的主键
-- 3.查询的条件 cname = '鞋服' and price > 500
-- 4.要查询的字段 pname price

mysql> select pname,price from products,category where category_id=cid and cname='鞋服'and price>500;
+------------+-------+
| pname      | price |
+------------+-------+
| 篮
球鞋    |   800 |
| 冲
锋衣    |  2000 |
+------------+-------+
2 rows in set (0.00 sec)

mysql> SELECT
    -> p.pname,
    -> p.price
    -> FROM products p INNER JOIN category c ON p.category_id = c.cid
    -> WHERE p.price > 500 AND cname = '鞋服';
+------------+-------+
| pname      | price |
+------------+-------+
| 篮
球鞋    |   800 |
| 冲
锋衣    |  2000 |
+------------+-------+
2 rows in set (0.00 sec)

3.5.2 外连接查询

  1. 左外连接
    左外连接 , 使用 LEFT OUTER JOIN , OUTER 可以省略
    左外连接的特点
    以左表为基准, 匹配右边表中的数据,如果匹配的上,就展示匹配到的数据
    如果匹配不到, 左表中的数据正常展示, 右边的展示为null.
SELECT 字段名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 条件

-- 左外连接查询
SELECT * FROM category c LEFT JOIN products p ON c.`cid`=
p.`category_id`;
# 查询每个分类下的商品个数
/*
1.连接条件: 主表.主键 = 从表.外键
2.查询条件: 每个分类 需要分组
3.要查询的字段: 分类名称, 分类下商品个数
*/
mysql> select cname '分类',count(pid)'商品个数' from category left join products on cid=category_id group by cname;
+-----------+--------------+
| 分类      | 商品个数     |
+-----------+--------------+
| 化妆品    |            2 |
| 家电      |            3 |
| 汽车      |            0 |
| 鞋服      |            4 |
+-----------+--------------+
4 rows in set (0.00 sec)

2) 右外连接

右外连接 , 使用 RIGHT OUTER JOIN , OUTER 可以省略
右外连接的特点
以右表为基准,匹配左边表中的数据,如果能匹配到,展示匹配到的数据
如果匹配不到,右表中的数据正常展示, 左边展示为null

#语法格式
SELECT 字段名 FROM 左表 RIGHT [OUTER ]JOIN 右表 ON 条件

-- 右外连接查询
SELECT * FROM products p RIGHT JOIN category c ON p.`category_id` =
c.`cid`;

3.5.3 各种连接方式的总结
mysql学+练_第1张图片

  1. 内连接: inner join , 只获取两张表中 交集部分的数据.
  2. 左外连接: left join , 以左表为基准,查询左表的所有数据, 以及与右表有交集的部分
  3. 右外连接: right join , 以右表为基准,查询右表的所有的数据,以及与左表有交集的部分
    内连接和左外连接使用居多

第4节 合并查询

4.1 UNION

UNION 操作符用于合并两个或多个 SELECT 语句的结果集,并消除重复行。
注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
UNION 子句的基本语法如下所示:

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]
UNION
SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

建表

CREATE TABLE Customers(
Id INT PRIMARY KEY AUTO_INCREMENT,
Name VARCHAR(20),
Sex VARCHAR(20),
Address VARCHAR(20),
Salary INT
);
CREATE TABLE Orders(
Oid INT PRIMARY KEY AUTO_INCREMENT,
Date VARCHAR(20),
Customers_Id VARCHAR(20),
Amount INT
);

插入数据

INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('孙悟空', '男',
'花果山',2000);
INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('猪八戒', '男',
'高老庄',1500);
INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('唐僧', '男',
'东土大唐',3000);
INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('沙僧', '男',
'流沙河',2500);
INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('女儿国王',
'女', '女儿国',10000);
INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('黄蓉', '女',
'桃花岛',7500);
INSERT INTO Customers (Name, Sex, Address, Salary) VALUES ('郭静', '男',
'牛家村',6000);
INSERT INTO Orders (Oid, Date, Customers_Id, Amount) VALUES (102, '2019-
12-08 00:00:00', 3, 2000);
INSERT INTO Orders (Oid, Date, Customers_Id, Amount) VALUES (100, '2019-
10-06 00:00:00', 3, 1500);
INSERT INTO Orders (Oid, Date, Customers_Id, Amount) VALUES (101, '2019-
09-20 00:00:00', 6, 3000);
INSERT INTO Orders (Oid, Date, Customers_Id, Amount) VALUES (103, '2020-
05-20 00:00:00', 5, 5000);

用 SELECT 语句将这两张表连接起来:

SELECT Id,NAME,Amount,Date
FROM customers
LEFT JOIN orders
on customers.Id = orders.Customers_Id
UNION
SELECT Id,NAME,Amount,Date
from customers
RIGHT JOIN orders
on customers.Id = orders.Customers_Id;
结果如下所示:
+------+----------+--------+---------------------+
| ID | NAME | AMOUNT | DATE |
+------+----------+--------+---------------------+
| 3 | 唐僧 | 1500 | 2019-10-06 00:00:00 |
| 6 | 黄蓉 | 3000 | 2019-09-20 00:00:00 |
| 3 | 唐僧 | 2000 | 2019-12-08 00:00:00 |
| 5 | 女儿国王 | 5000 | 2020-05-20 00:00:00 |
| 1 | 孙悟空 | NULL | NULL |
| 2 | 猪八戒 | NULL | NULL |
| 4 | 沙僧 | NULL | NULL |
| 7 | 郭静 | NULL | NULL |

小结:

  1. 选择的列数必须相同;
  2. 所选列的数据类型必须在相同的数据类型组中(如数字或字符)
  3. 列的名称不必相同
  4. 在重复检查期间,NULL值不会被忽略

4.2 UNION ALL

UNION ALL 运算符用于将两个 SELECT 语句的结果组合在一起,重复行也包含在内。
UNION ALL 运算符所遵从的规则与 UNION 一致。
语法:
UNION ALL的基本语法如下:

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

UNION ALL

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

现在,让我们用 SELECT 语句将Customers、Orders两张表连接起来:

SELECT Id,NAME,Amount,Date
FROM customers
LEFT JOIN orders
on customers.Id = orders.Customers_Id
UNION ALL
SELECT Id,NAME,Amount,Date
from customers
RIGHT JOIN orders
on customers.Id = orders.Customers_Id;
+------+----------+--------+---------------------+
| ID | NAME | AMOUNT | DATE |
+------+----------+--------+---------------------+
| 3 | 唐僧 | 1500 | 2019-10-06 00:00:00 |
| 6 | 黄蓉 | 3000 | 2019-09-20 00:00:00 |
| 3 | 唐僧 | 2000 | 2019-12-08 00:00:00 |
| 5 | 女儿国王 | 5000 | 2020-05-20 00:00:00 |
| 1 | 孙悟空 | NULL | NULL |
| 2 | 猪八戒 | NULL | NULL |
| 4 | 沙僧 | NULL | NULL |
| 7 | 郭静 | NULL | NULL |
| 3 | 唐僧 | 1500 | 2019-10-06 00:00:00 |
| 6 | 黄蓉 | 3000 | 2019-09-20 00:00:00 |
| 3 | 唐僧 | 2000 | 2019-12-08 00:00:00 |
| 5 | 女儿国王 | 5000 | 2020-05-20 00:00:00 |
+------+----------+--------+---------------------+

总结:
UNION和UNION ALL关键字都是将两个结果集合并为一个,也有区别。
1、重复值:UNION在进行表连接后会筛选掉重复的记录,而Union All不会去除重复记录。
2、UNION ALL只是简单的将两个结果合并后就返回。
3、在执行效率上,UNION ALL 要比UNION快很多,因此,若可以确认合并的两个结果集中不
包含重复数据,那么就使用UNION ALL。

第5节 子查询

5.1 什么是子查询
子查询概念
一条select 查询语句的结果, 作为另一条 select 语句的一部分
子查询的特点
子查询必须放在小括号中
子查询的场景中还会有另外一个特点,整个sql至少会有两个select关键字
子查询常见分类
where型 子查询: 将子查询的结果, 作为父查询的比较条件 =
from型 子查询 : 将子查询的结果, 作为 一张表,提供给父层查询使用
exists型 子查询: 子查询的结果是单列多行, 类似一个数组, 父层查询使用 IN 函数 ,包含子查询的结果

5.2 子查询的结果作为查询条件

SELECT 查询字段 FROM 表 WHERE 字段=(子查询);
  1. 通过子查询的方式, 查询价格最高的商品信息
# 通过子查询的方式, 查询价格最高的商品信息
-- 1.先查询出最高价格
SELECT MAX(price) FROM products;
-- 2.将最高价格作为条件,获取商品信息
SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products);

  1. 查询化妆品分类下的 商品名称 商品价格
#查询化妆品分类下的 商品名称 商品价格
-- 先查出化妆品分类的 id
SELECT cid FROM category WHERE cname = '化妆品';
-- 根据分类id ,去商品表中查询对应的商品信息
SELECT
p.`pname`,
p.`price`
FROM products p
WHERE p.`category_id` = (SELECT cid FROM category WHERE cname = '化妆品');
  1. 查询小于平均价格的商品信息
-- 1.查询平均价格
SELECT AVG(price) FROM products; -- 1866
-- 2.查询小于平均价格的商品
SELECT * FROM products
WHERE price < (SELECT AVG(price) FROM products);
mysql> select avg(price) from products;
+------------+
| avg(price) |
+------------+
|  1866.6667 |
+------------+
1 row in set (0.00 sec)

mysql> select * from products where price<(select avg(price) from products);
+------+------------+-------+------+-------------+
| pid  | pname      | price | flag | category_id |
+------+------------+-------+------+-------------+
| p004 | 篮
球鞋    |   800 | 1    | c002        |
| p005 | 运
动裤    |   200 | 1    | c002        |
| p006 | T
恤       |   300 | 1    | c002        |
| p008 | 神
仙水    |   800 | 1    | c003        |
| p009 | 大
宝      |   200 | 1    | c003        |
+------+------------+-------+------+-------------+
5 rows in set (0.00 sec)

5.3 子查询的结果作为一张表

  1. 查询商品中,价格大于500的商品信息,包括 商品名称 商品价格 商品所属分类名称
mysql> select pname,price,cname from products p
    -> inner join(select * from category)c
    -> on p.category_id=c.cid where p.price >500;
+------------------+-------+-----------+
| pname            | price | cname     |
+------------------+-------+-----------+
| 小
米电视机      |  5000 | 家电      |
| 格
力空调        |  3000 | 家电      |
| 美
的冰箱        |  4500 | 家电      |
| 篮
球鞋          |   800 | 鞋服      |
| 冲
锋衣          |  2000 | 鞋服      |
| 神
仙水          |   800 | 化妆品    |
+------------------+-------+-----------+
6 rows in set (0.00 sec)

注意: 当子查询作为一张表的时候,需要起别名,否则无法访问表中的字段。

5.4 子查询结果是单列多行
子查询的结果类似一个数组, 父层查询使用 IN 函数 ,包含子查询的结果
语法格式

SELECT 查询字段 FROM 表 WHERE 字段 IN (子查询);
  1. 查询价格小于两千的商品,来自于哪些分类(名称)
# 查询价格小于两千的商品,来自于哪些分类(名称)
-- 先查询价格小于2000 的商品的,分类ID
SELECT DISTINCT category_id FROM products WHERE price < 2000;
-- 在根据分类的id信息,查询分类名称
-- 报错: Subquery returns more than 1 row
-- 子查询的结果 大于一行
SELECT * FROM category
WHERE cid = (SELECT DISTINCT category_id FROM products WHERE price <
2000);

使用in函数, in( c002, c003 )

-- 子查询获取的是单列多行数据
SELECT * FROM category
WHERE cid IN (SELECT DISTINCT category_id FROM products WHERE price <
2000);
  1. 查询家电类 与 鞋服类下面的全部商品信息
# 查询家电类 与 鞋服类下面的全部商品信息
-- 先查询出家电与鞋服类的 分类ID
SELECT cid FROM category WHERE cname IN ('家电','鞋服');
-- 根据cid 查询分类下的商品信息
SELECT * FROM products
WHERE category_id IN (SELECT cid FROM category WHERE cname IN ('家电','鞋
服'));

5.5 子查询总结

  1. 子查询如果查出的是一个字段(单列), 那就在where后面作为条件使用.
    单列单行 =
    单列多行 in
  2. 子查询如果查询出的是多个字段(多列), 就当做一张表使用(要起别名).

你可能感兴趣的:(mysql,数据库,sql)