- 一、MySQL 安装
- 二、MySQL常用命令
- 三、条件查询
- 四、排序数据
- 五、常用函数
- 六、分组查询
- 七、连接查询
- 八、子查询
- 九、union合并查询
- 十、limit 的使用
- 十一、表
- 十二、存储引擎(了解)
- 十三、事务
- 十四、索引
- 十五、视图
- 十六、DBA命令
- 十七、数据库设计的三范式
- 十八、题目练习
- 18.1、取得每个部门最高薪水的人员名称
- 18.2、哪些人的薪水在部门的平均薪水之上
- 18.3、取得部门中(所有人的)平均的薪水等级
- 18.4、不用组函数(Max),取得最高薪水
- 18.5、取得平均薪水最高的部门的部门编号
- 18.6 、取得平均薪水最高的部门的部门名称
- 18.7、求平均薪水的等级最低的部门名称
- 18.8、取得比普通员工(员工代码没有在 mgr 字段上出现过的)的最高薪水还要高的领导姓名
- 18.9、取得薪水最高的前五名员工
- 18.10、取得薪水最高的第六名到十名员工
- 18.11、取得最后入职的 5 名员工
- 18.12、取得每个薪水等级有多少员工
- 18.13、面试题
- 18.14、列出所有员工及领导的姓名
- 18.15、列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
- 18.16、列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门.
- 18.17、列出至少有 5 个员工的所有部门
- 18.18、列出薪金比 “SMITH” 多的所有员工信息
- 18.19、列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数.
- 18.20、列出最低薪金大于 1500 的各种工作及从事此工作的全部雇员人数
- 18.21、列出在部门"SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号.
- 18.22、列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,雇员的工资等级.
- 18.23、列出与"SCOTT"从事相同工作的所有员工及部门名称.
- 18.24、列出薪金等于部门30中员工的薪金的其他员工的姓名和薪金.
- 18.25、列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金.部门名称.
- 18.26、列出在每个部门工作的员工数量,平均工资和平均服务期限.
- 18.27、列出所有员工的姓名、部门名称和工资。
- 18.28、列出所有部门的详细信息和人数
- 18.29、列出各种工作的最低工资及从事此工作的雇员姓名
- 18.30、列出各个部门的 MANAGER(领导) 的最低薪资
- 18.31、列出所有员工的年工资,按年薪从低到高排序
- 18.32、求出员工领导的薪水超过3000的员工名称与领导名称
- 18.33、求出部门名称中,带'S'字符的部门员工的工资合计、部门人数.
- 18.34、给任职日期超过30年的员工加薪10%
一、MySQL 安装
MySQL 简介:
MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。
- MySQL 是开源的,目前隶属于 Oracle 旗下产品。
- MySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
- MySQL 使用标准的 SQL 数据语言形式。
- MySQL 可以运行于多个系统上,并且支持多种语言。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby 和 Tcl 等。
- MySQL 对PHP有很好的支持,PHP 是目前最流行的 Web 开发语言。
- MySQL 支持大型数据库,支持 5000 万条记录的数据仓库,32 位系统表文件最大可支持 4GB,64 位系统支持最大的表文件为8TB。
- MySQL 是可以定制的,采用了 GPL 协议,你可以修改源码来开发自己的 MySQL 系统。
什么是数据库?
数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。
每个数据库都有一个或多个不同的 API 用于创建,访问,管理,搜索和复制所保存的数据。
我们也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢。
所以,现在我们使用关系型数据库管理系统(RDBMS)来存储和管理大数据量。所谓的关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。
RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:
- 1.数据以表格的形式出现
- 2.每行为各种记录名称
- 3.每列为记录名称所对应的数据域
- 4.许多的行和列组成一张表单
- 5.若干的表单组成database
RDBMS 术语
在我们开始学习MySQL 数据库前,让我们先了解下RDBMS的一些术语:
- 数据库: 数据库是一些关联表的集合。
- 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
- 列: 一列(数据元素) 包含了相同类型的数据, 例如邮政编码的数据。
- 行:一行(=元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
- 冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。
- 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
- 外键:外键用于关联两个表。
- 复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。
- 索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
- 参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。
MySQL 安装
所有平台的 MySQL 下载地址为: MySQL 下载 。 挑选你需要的 MySQL Community Server 版本及对应的平台。
Linux/UNIX 上安装 MySQL
Linux平台上推荐使用RPM包来安装Mysql,MySQL AB提供了以下RPM包的下载地址:
- MySQL - MySQL服务器。你需要该选项,除非你只想连接运行在另一台机器上的MySQL服务器。
- MySQL-client - MySQL 客户端程序,用于连接并操作Mysql服务器。
- MySQL-devel - 库和包含文件,如果你想要编译其它MySQL客户端,例如Perl模块,则需要安装该RPM包。
- MySQL-shared - 该软件包包含某些语言和应用程序需要动态装载的共享库(libmysqlclient.so*),使用MySQL。
- MySQL-bench - MySQL数据库服务器的基准和性能测试工具
Linux平台上推荐使用RPM包来安装Mysql,MySQL AB提供了以下RPM包的下载地址:
- MySQL - MySQL服务器。你需要该选项,除非你只想连接运行在另一台机器上的MySQL服务器。
- MySQL-client - MySQL 客户端程序,用于连接并操作Mysql服务器。
- MySQL-devel - 库和包含文件,如果你想要编译其它MySQL客户端,例如Perl模块,则需要安装该RPM包。
- MySQL-shared - 该软件包包含某些语言和应用程序需要动态装载的共享库(libmysqlclient.so*),使用MySQL。
- MySQL-bench - MySQL数据库服务器的基准和性能测试工具
安装前,我们可以检测系统是否自带安装 MySQL:
rpm -qa | grep mysql
如果你系统有安装,那可以选择进行卸载:
rpm -e mysql // 普通删除模式
rpm -e --nodeps mysql // 强力删除模式,如果使用上面命令删除时,提示有依赖的其它文件,则用该命令可以对其进行强力删除
安装 MySQL:
接下来我们在 Centos7 系统下使用 yum 命令安装 MySQL,需要注意的是 CentOS 7 版本中 MySQL数据库已从默认的程序列表中移除,所以在安装前我们需要先去官网下载 Yum 资源包,下载地址为:https://dev.mysql.com/downloads/repo/yum/
wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
rpm -ivh mysql-community-release-el7-5.noarch.rpm
yum update
yum install mysql-server
权限设置:
chown mysql:mysql -R /var/lib/mysql
初始化 MySQL:
mysqld --initialize
启动 MySQL:
systemctl start mysqld
查看 MySQL 运行状态:
systemctl status mysqld
验证 MySQL 安装
在成功安装 MySQL 后,一些基础表会表初始化,在服务器启动后,你可以通过简单的测试来验证 MySQL 是否工作正常。
使用 mysqladmin 工具来获取服务器状态:
使用 mysqladmin 命令来检查服务器的版本, 在 linux 上该二进制文件位于 /usr/bin 目录,在 Windows 上该二进制文件位于C:mysqlin 。
[root@host]# mysqladmin --version
linux上该命令将输出以下结果,该结果基于你的系统信息:
mysqladmin Ver 8.23 Distrib 5.0.9-0, for redhat-linux-gnu on i386
如果以上命令执行后未输出任何信息,说明你的Mysql未安装成功。
登录 MySQL
当 MySQL 服务已经运行时, 我们可以通过 MySQL 自带的客户端工具登录到 MySQL 数据库中, 首先打开命令提示符, 输入以下格式的命名:
mysql -h 主机名 -u 用户名 -p
参数说明:
- -h : 指定客户端所要登录的 MySQL 主机名, 登录本机(localhost 或 127.0.0.1)该参数可以省略;
- -u : 登录的用户名;
- -p : 告诉服务器将会使用一个密码来登录, 如果所要登录的用户名密码为空, 可以忽略此选项。
如果我们要登录本机的 MySQL 数据库,只需要输入以下命令即可:
mysql -u root -p
按回车确认, 如果安装正确且 MySQL 正在运行, 会得到以下响应:
Enter password:
若密码存在, 输入密码登录, 不存在则直接按回车登录。登录成功后你将会看到 Welcome to the MySQL monitor... 的提示语。
然后命令提示符会一直以 mysq> 加一个闪烁的光标等待命令的输入, 输入 exit 或 quit 退出登录。
sql、DB、DBMS分别是什么,他们之间的关系?
DB:DateBase(数据库,数据库实际上在硬盘上以文件的形式存在)
DBMS:DataBase Management System (数据库管理系统,常见的有:MySQL Oracle DB2 Sybase SqlServer...)
SQL:结构化查询语言,是一门标准通用的语言。标准的sql适合与所有的产品。SQL属于高级语言。SQL语句在执行的时候,实际上内部也会先进行编译,然后在执行sql。(sql语句的编译由DBMS完成。)
DBMS负责执行sql语句,通过执行sql语句来操作DB当中的数据。
DBMS -(执行)-> SQL -(操作) -> DB
关于SQL语句的分类?
DQL:
数据查询语言(凡是导游 select 关键字的都是查询语句)
DML:
数据操作语言(凡是对表当中的数据进行增删改的都是DML)
insert(增) delete(删) update(改)
DDL:
数据自自定义语言
凡是带有create(新建,等同于增)、drop(删除)、alter(修改)的都是DDL。DDL主要操作的是表的结构。不是表中的数据,和DML不同。
TCL:
事务控制语言包括: commit(事件提交)、rollback(事件回滚)
DCL:
数据控制语言:grant(授权)、revoke(撤销)...
二、MySQL常用命令
2.1 数据准备
学习 MySqL 主要还是学习通用的 SQL 语句,那么 SQL 语句包含增删改查,SQL语句怎么分类呢?
DQL(数据查询语言): 查询语句,凡是select语句都是DQL。
DML(数据操作语言):insert delete update,对表当中的数据进行增删改。
DDL(数据定义语言):create drop alter,对表结构的增删改。
TCL(事务控制语言):commit提交事务,rollback回滚事务。(TCL中的T是Transaction)
DCL(数据控制语言): grant授权、revoke撤销权限等。
导入数据
导入数据(后期大家练习的时候使用这个演示的数据)
第一步:登录mysql数据库管理系统
dos命令窗口:
mysql -uroot -p密码
第二步:查看有哪些数据库
show databases; (这个不是SQL语句,属于MySQL的命令。)
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
第三步:创建属于我们自己的数据库
create database 数据库名称; (这个不是SQL语句,属于MySQL的命令。)
第四步:使用数据
use 数据库名称; (这个不是SQL语句,属于MySQL的命令。)
第五步:查看当前使用的数据库中有哪些表?
show tables; (这个不是SQL语句,属于MySQL的命令。)
第六步:初始化数据
mysql> source 文件路径
注意:数据初始化完成之后,有三张表:
+-----------------------+
| Tables_in_ |dawncoody
+-----------------------+
| dept |
| emp |
| salgrade |
+-----------------------+
查看msyql版本
-
MySQL程序选项具有以下两种通用形式:
– 长选项,由单词之前加两个减号组成
– 短选项,由单个字母之前加一个减号组成
C:UsersAdministrator>mysql --version mysql Ver 8.0.23 for Win64 on x86_64 (MySQL Community Server - GPL) C:UsersAdministrator>mysql -V mysql Ver 8.0.23 for Win64 on x86_64 (MySQL Community Server - GPL)
创建数据库
create database 数据库名称;
删除数据库
drop databse 数据库名称
查看表的结构 desc(describe)
+-----------------------+
| Tables_in_bjpowernode |
+-----------------------+
| dept | (部门表)
| emp | (员工表)
| salgrade | (工资等级表)
+-----------------------+
mysql> desc dept;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| DEPTNO | int(2) | NO | PRI | NULL | | 部门编号
| DNAME | varchar(14) | YES | | NULL | | 部门名称
| LOC | varchar(13) | YES | | NULL | | 部门位置
+--------+-------------+------+-----+---------+-------+
mysql> desc emp;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| EMPNO | int(4) | NO | PRI | NULL | | 员工编号
| ENAME | varchar(10) | YES | | NULL | | 员工姓名
| JOB | varchar(9) | YES | | NULL | | 工作岗位
| MGR | int(4) | YES | | NULL | | 上级领导编号
| HIREDATE | date | YES | | NULL | | 入职日期
| SAL | double(7,2) | YES | | NULL | | 月薪
| COMM | double(7,2) | YES | | NULL | | 补助/津贴
| DEPTNO | int(2) | YES | | NULL | | 部门编号
+----------+-------------+------+-----+---------+-------+
mysql> desc salgrade;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| GRADE | int(11) | YES | | NULL | | 等级
| LOSAL | int(11) | YES | | NULL | | 最低薪资
| HISAL | int(11) | YES | | NULL | | 最高薪资
+-------+---------+------+-----+---------+-------+
查询当前使用数据库
# 查询当前所用 sql
mysql> select database();
+------------+
| database() |
+------------+
| dawncoody |
+------------+
1 row in set (0.00 sec)
# 查询当前数据库所用版本
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.23 |
+-----------+
1 row in set (0.00 sec)
终止一条语句
如果想要终止一条语句,可键入 c。
退出 mysql
可以使用 q、QUIT 或 EXIT
查看其他库中的表
show tables from<database name>;
查看创建表的语句:
show create table 表名称;
2.2 简单的查询
简单查询语句(DQL)
语法格式:
select 字段名1,字段名2, .... from 表名;
字段可以参与数学运算:
mysql> select ename,sal * 12 from emp;
+--------+----------+
| ename | sal * 12 |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
14 rows in set (0.00 sec)
给查询结果的列重命名:
mysql> select ename,sal * 12 as yearsal from emp; # as 关键字可以省略
+--------+----------+
| ename | yearsal |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
14 rows in set (0.00 sec)
注意: 只是将显示的查询结果列名取别名,表的列名还是原来的。
假设起别名的时候,别名里面有空格可以用引号括起来(别名是中文也要用单引号括起来)
mysql> select ename,sal * 12 as 'year sal' from emp; # 双引号也可以
+--------+----------+
| ename | year sal |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
14 rows in set (0.00 sec)
查询所有字段
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.00 sec)
2.3 distinct去重
把查询结果去除重复记录,不会对原数据进行修改。
mysql> select distinct job from emp;
+-----------+
| job |
+-----------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+-----------+
5 rows in set (0.00 sec)
下面这样写是错误的
mysql> select ename,distinct job from emp;
$distinct$只能出现在所有字段的最前方
mysql> select distinct job,deptno from emp; # distinct 会把 job,deptno两个字段联合起来去重。
+-----------+--------+
| job | deptno |
+-----------+--------+
| CLERK | 20 |
| SALESMAN | 30 |
| MANAGER | 20 |
| MANAGER | 30 |
| MANAGER | 10 |
| ANALYST | 20 |
| PRESIDENT | 10 |
| CLERK | 30 |
| CLERK | 10 |
+-----------+--------+
9 rows in set (0.00 sec)
三、条件查询
什么是条件查询?
不是将表中所有数据都查出来。是查询出来符合条件的。
都有哪些条件
运算符 | 说明 |
---|---|
= | 等于 |
<>或!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
between … and …. | 两个值之间,等同于 >= and <= |
is null | 为null(is not null 不为空) |
and | 并且 |
or | 或者 |
in | 包含,相当于多个or(not in不在这个范围中) |
not | not可以取非,主要用在is 或in中 |
like | like称为模糊查询,支持%或下划线匹配 %匹配任意个字符 下划线,一个下划线只匹配一个字符 |
select 字段... form 表名 where 条件; # 执行顺序先是 from, 然后是where, 最后是select
# 查询工资等于5000 的员工姓名
mysql> select ename from emp where sal=5000;
# 找出工资不等于 3000 的
mysql> select ename, sal from emp where sal <> 3000; # <> 可替换成 !=
# 找1100 和 3000 之间的
mysql> select ename, sal from emp where sal >= 1100 and sal <= 3000;
# 或者用between... and...(闭区间,必须遵循左小右大)
mysql> select ename, sal from emp where between 1100 and 3000;
# 查询哪些员工的津贴为 null的(is null)
mysql> select empno,ename,sal,comm from emp where comm is null;
# 查询哪些员工的津贴不为null
mysql> select empno,ename,sal,comm from emp where comm is not null;
# 查询工作岗位是MANAGER和SALESMAN的员工(or)
mysql> select empno,ename,job from emp where job = 'MANAGER' or job ='SALESMAN';
#注意:and 比 or 优先级高
# in 包含,相当于多个 or 查询工作岗位是MANAGER和SALESMAN的员工
mysql> select empno,ename,job from emp where job in ('MANAGER', 'SALESMAN');
# not in 表示这不在这几个值当中的数据
mysql> select empno,ename,job from emp where job not in ('MANAGER', 'SALESMAN');
# like 称为模糊查询,支持 % 或 _ 匹配,% 匹配任意多个字符,一个下划线匹配任意一个字符
# 找出名字中包含 o 的
mysql> select ename from emp where ename like '%o%';
# 如果名字中包含下划线用 转义字符
mysql> select ename from emp where ename like '%\_%';
四、排序数据
4.1、单一字段排序
按照薪水由小到大排序(系统默认由小到大)
mysql> select ename,sal from emp order by sal;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| KING | 5000.00 |
+--------+---------+
14 rows in set (0.00 sec)
# 也可以加参数升序
mysql> select ename,sal from emp order by sal asc;
按照薪水由大到小排序
mysql> select ename,sal from emp order by sal desc;
+--------+---------+
| ename | sal |
+--------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| SMITH | 800.00 |
+--------+---------+
14 rows in set (0.00 sec)
4.2、按照多个字段排序
按照员工名字和薪水排序,如果薪资一样就按照名字排序
mysql> select ename,sal from emp order by sal asc,ename asc;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| MARTIN | 1250.00 |
| WARD | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
+--------+---------+
14 rows in set (0.00 sec)
4.3、使用字段位置来排序
mysql> select ename,sal from emp order by 2; # 2表示是第二列
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| KING | 5000.00 |
+--------+---------+
14 rows in set (0.00 sec)
不建议使用此种方式,采用数字含义不明确,程序不健壮。
4.4 综合案例
找出工资在 1250 到 3000 之间的员工信息,要求按照薪资降序排序。
mysql> select ename,sal from emp where sal between 1250 and 3000 order by sal desc;
+--------+---------+
| ename | sal |
+--------+---------+
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
+--------+---------+
10 rows in set (0.00 sec)
关键字顺序不能变:select ... from ... where ... order by...
五、常用函数
5.1、数据处理函数
数据处理函数又称为单行处理函数
函数 | 说明 |
---|---|
Lower | 转换小写 |
upper | 转换大写 |
substr(被截取的字符串,起始下标,截取的长度) | 取子串() |
concat | 字符串拼接 |
length | 取长度 |
trim | 去空格 |
str_to_date | 将字符串转换成日期 |
date_format | 格式化日期 |
format | 设置千分位 |
round | 四舍五入 |
rand | 生成随机数 |
ifnull | 可以将 null 转换成一个具体的值 |
5.1.1 lower
:
mysql> select lower(ename) from emp; # 将字母转换成小写
+--------------+
| lower(ename) |
+--------------+
| smith |
| allen |
| ward |
| jones |
| martin |
| blake |
| clark |
| scott |
| king |
| turner |
| adams |
| james |
| ford |
| miller |
+--------------+
14 rows in set (0.00 sec)
5.1.2 upper
:
mysql> select upper(name) frome student; # 将字母转换成大写
5.1.3 substr
:
mysql> select substr(ename,1,1)as ename from emp; # 截取字符串
+-------+
| ename |
+-------+
| S |
| A |
| W |
| J |
| M |
| B |
| C |
| S |
| K |
| T |
| A |
| J |
| F |
| M |
+-------+
14 rows in set (0.03 sec)
5.1.4 concat
:
mysql> select concat(empno,ename) from emp; # 将empno和ename进行字符串拼接
+---------------------+
| concat(empno,ename) |
+---------------------+
| 7369SMITH |
| 7499ALLEN |
| 7521WARD |
| 7566JONES |
| 7654MARTIN |
| 7698BLAKE |
| 7782CLARK |
| 7788SCOTT |
| 7839KING |
| 7844TURNER |
| 7876ADAMS |
| 7900JAMES |
| 7902FORD |
| 7934MILLER |
+---------------------+
14 rows in set (0.03 sec)
5.1.5 length
:
mysql> select length(ename) enamelength from emp;
+-------------+
| enamelength |
+-------------+
| 5 |
| 5 |
| 4 |
| 5 |
| 6 |
| 5 |
| 5 |
| 5 |
| 4 |
| 6 |
| 5 |
| 5 |
| 4 |
| 6 |
+-------------+
14 rows in set (0.03 sec)
5.1.6trim
:
mysql> select * from emp where ename = trim(' KING');
+-------+-------+-----------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-----------+------+------------+---------+------+--------+
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
+-------+-------+-----------+------+------------+---------+------+--------+
1 row in set (0.00 sec)
5.1.7round
:
说round前要知道select后面可以是一个字面量,也可以是个字面值。
mysql> select 1000 as num from emp; # 这里的 1000 是个字面量,这表中有多少行就会输出多少个 1000
+------+
| num |
+------+
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
+------+
14 rows in set (0.00 sec)
mysql> select round(1234.5) as result from emp;
+--------+
| result |
+--------+
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
| 1235 |
+--------+
14 rows in set (0.00 sec)
round后面还可以有两个参数,第一个参数是字面值,第二个参数是保留的小数个数
mysql> select round(12345.45783,3) as result from emp;
+-----------+
| result |
+-----------+
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
| 12345.458 |
+-----------+
14 rows in set (0.00 sec)
5.1.8rand
:
mysql> select rand() from emp; # rand() 生成 0~1 之间的随机数
+----------------------+
| rand() |
+----------------------+
| 0.27825672484771974 |
| 0.6303644903286961 |
| 0.31705230783396615 |
| 0.6941680989173875 |
| 0.5196836018186841 |
| 0.515913743074903 |
| 0.020517940652107765 |
| 0.5548485047694748 |
| 0.7126887326246953 |
| 0.8988981795486977 |
| 0.3564247306030474 |
| 0.08542914510278883 |
| 0.357871564438447 |
| 0.5330704176175133 |
+----------------------+
14 rows in set (0.03 sec)
5.1.9ifnull
:
ifnull 是空处理函数,专门处理空的。在所有数据库当中,只要有NULL参与的数学运算,最终结果就是 NULL.
mysql> select ename, sal + comm as salcomm from emp; # 如果不用 ifnull 只要有一个结果为值为空计算结果就为空
+--------+---------+
| ename | salcomm |
+--------+---------+
| SMITH | NULL | # 空
| ALLEN | 1900.00 |
| WARD | 1750.00 |
| JONES | NULL | # 空
| MARTIN | 2650.00 |
| BLAKE | NULL | # 空
| CLARK | NULL | # 空
| SCOTT | NULL | # 空
| KING | NULL | # 空
| TURNER | 1500.00 |
| ADAMS | NULL | # 空
| JAMES | NULL | # 空
| FORD | NULL | # 空
| MILLER | NULL | # 空
+--------+---------+
14 rows in set (0.00 sec)
ifnull 可以将 null 转换成一个具体值第一个参数为转换的值,第二个参数是转换后的字
mysql> select ename, sal + ifnull(comm, 0) as salcomm from emp;
+--------+---------+
| ename | salcomm |
+--------+---------+
| SMITH | 800.00 |
| ALLEN | 1900.00 |
| WARD | 1750.00 |
| JONES | 2975.00 |
| MARTIN | 2650.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
14 rows in set (0.00 sec)
5.1.10 case...when...then...when...then...else...and
实现:
当员工的工作岗位是 MANAGER 的时候,工资上调 10%,当工作岗位是 SALESMAN 的时候,工资上调 50%,其他正常。(注意:不修改数据库,只是查询结果显示为工资上调)
mysql> select ename,job,sal as oldsal,(case job when 'MANAGGER' then sal*1 when 'SALLESMAN' then sal*1 else sal end) as newsal from emp;
+--------+-----------+---------+---------+
| ename | job | oldsal | newsal |
+--------+-----------+---------+---------+
| SMITH | CLERK | 800.00 | 800.00 |
| ALLEN | SALESMAN | 1600.00 | 1600.00 |
| WARD | SALESMAN | 1250.00 | 1250.00 |
| JONES | MANAGER | 2975.00 | 2975.00 |
| MARTIN | SALESMAN | 1250.00 | 1250.00 |
| BLAKE | MANAGER | 2850.00 | 2850.00 |
| CLARK | MANAGER | 2450.00 | 2450.00 |
| SCOTT | ANALYST | 3000.00 | 3000.00 |
| KING | PRESIDENT | 5000.00 | 5000.00 |
| TURNER | SALESMAN | 1500.00 | 1500.00 |
| ADAMS | CLERK | 1100.00 | 1100.00 |
| JAMES | CLERK | 950.00 | 950.00 |
| FORD | ANALYST | 3000.00 | 3000.00 |
| MILLER | CLERK | 1300.00 | 1300.00 |
+--------+-----------+---------+---------+
14 rows in set (0.00 sec)
5.2、分组函数(多行处理函数)
多行处理函数的特点:输入多行,最终输出一行。
函数 | 功能 |
---|---|
sum | 求和 |
avg | 平均值 |
max | 最大值 |
min | 最小值 |
注意:分组函数在使用必须先进行分组,然后才能使用。如果没有对数据进行分组,整张表默认为一组。
5.2.1 max
找出一列最大的值
mysql> select max(sal) '最高工资' from emp;
+----------+
| 最高工资 |
+----------+
| 5000.00 |
+----------+
1 row in set (0.00 sec)
5.2.2 min
找出工资最低者
mysql> select min(sal) '最低工资' from emp;
+----------+
| 最低工资 |
+----------+
| 800.00 |
+----------+
1 row in set (0.00 sec)
5.2.3 sum
计算工资和:
mysql> select sum(sal) '工资和' from emp;
+----------+
| 工资和 |
+----------+
| 29025.00 |
+----------+
1 row in set (0.00 sec)
5.2.4 avg
计算平均工资:
mysql> select avg(sal) "平均工资" from emp;
+-------------+
| 平均工资 |
+-------------+
| 2073.214286 |
+-------------+
1 row in set (0.00 sec)
5.2.5 count
计算员工总数量:
mysql> select count(ename) "员工" from emp;
+------+
| 员工 |
+------+
| 14 |
+------+
1 row in set (0.00 sec)
5.2.6 分组函数注意事项
第一点:
分组函数自动忽略 NULL,你不需要提前对 NULL 进行处理。
mysql> select sum(comm) from emp;
+-----------+
| sum(comm) |
+-----------+
| 2200.00 |
+-----------+
1 row in set (0.03 sec)
第二点:
分组函数中 count(*) 和 count(具体字段) 有什么区别?
count(具体字段):表示统计该字段下所有不为 NULL 的元素的总数。
mysql> select count(comm) from emp;
+-------------+
| count(comm) |
+-------------+
| 4 |
+-------------+
1 row in set (0.00 sec)
count(*):统计表当中的总函数。(只要有一行数据 则count++),因为每一行记录不可能都为NULL,一行数据中有一列不为 NULL,则这行数据就有效。
mysql> select count(*) from emp;
+----------+
| count(*) |
+----------+
| 14 |
+----------+
1 row in set (0.04 sec)
第三点:
分组函数不能够直接使用在 where 子句中。
找出比最低工资高的员工信息。
mysql> select ename,sal from emp where sal > min(sal); # 表面上没问题
ERROR 1111 (HY000): Invalid use of group function # 这里报错了,后面第6.1章有解释
第四点:
所有的分组函数可以组合起来一起用。
mysql> select min(sal),max(sal), avg(sal), sum(sal),count(*) from emp;
+----------+----------+-------------+----------+----------+
| min(sal) | max(sal) | avg(sal) | sum(sal) | count(*) |
+----------+----------+-------------+----------+----------+
| 800.00 | 5000.00 | 2073.214286 | 29025.00 | 14 |
+----------+----------+-------------+----------+----------+
1 row in set (0.00 sec)
六、分组查询
什么是分组查询?
在实际的应用中,可能有这样的需求,需要先进行分组,然后对每一组的数据进行操作。这个时候我们需要使用分组查询。分组查询主要涉及到两个子句,分别是:group by和having
6.1、语句执行顺序
将之前的关键字全部组合到一起的执行顺序:
select
...
from
...
where
...
group by
...
order by
...
以上关键字的顺序不能颠倒,执行顺序是:
from
-> where
-> group by
-> select
-> order by
这里就很好的解释了上面一章遗留报错的问题
select ename,sal from emp where sal > min(sal); # 报错
这里分组函数是放在 $where$ 后面,因为分组函数在使用的时候必须先分组之后才能使用。where 执行的时候,还没有分组。所以 $where$ 后面不能出现分组函数。
6.2、group by 案例
找出每个工作岗位的工资和?
实现思路:按照工作岗位分组,然后对工资求和。
mysql> select job,sum(sal) from emp group by job; # 先分组后执行
+-----------+----------+
| job | sum(sal) |
+-----------+----------+
| CLERK | 4150.00 |
| SALESMAN | 5600.00 |
| MANAGER | 8275.00 |
| ANALYST | 6000.00 |
| PRESIDENT | 5000.00 |
+-----------+----------+
5 rows in set (0.00 sec)
如果在 $select$ 后面加上 $ename$ 参数
mysql> select ename,job,sum(sal) from emp group by job;
+-------+-----------+----------+
| ename | job | sum(sal) |
+-------+-----------+----------+
| SMITH | CLERK | 4150.00 |
| ALLEN | SALESMAN | 5600.00 |
| JONES | MANAGER | 8275.00 |
| SCOTT | ANALYST | 6000.00 |
| KING | PRESIDENT | 5000.00 |
+-------+-----------+----------+
5 rows in set (0.00 sec)
以上语句在 mysql 中可以执行,但是毫无意义的。在 oracle 中执行错误。
重要结论:
在一条 select 语句当中,如果有 group by 语句的话,select 后面只能跟:参数分组的字段,以及分组函数。其他一律不能根。
找出每个部门的最高薪资
实现思路:
按照部门编号分组,求每一组的最大值。
mysql> select deptno,max(SAL) from emp group by deptno;
+--------+----------+
| deptno | max(SAL) |
+--------+----------+
| 20 | 3000.00 |
| 30 | 2850.00 |
| 10 | 5000.00 |
+--------+----------+
3 rows in set (0.00 sec)
找出每个部门不同工作岗位的最高薪资
mysql> select ename,job,sal,deptno from emp order by deptno asc; # 只是看一下内容,下面是答案
+--------+-----------+---------+--------+
| ename | job | sal | deptno |
+--------+-----------+---------+--------+
| CLARK | MANAGER | 2450.00 | 10 |
| KING | PRESIDENT | 5000.00 | 10 |
| MILLER | CLERK | 1300.00 | 10 |
| SMITH | CLERK | 800.00 | 20 |
| JONES | MANAGER | 2975.00 | 20 |
| SCOTT | ANALYST | 3000.00 | 20 |
| ADAMS | CLERK | 1100.00 | 20 |
| FORD | ANALYST | 3000.00 | 20 |
| ALLEN | SALESMAN | 1600.00 | 30 |
| WARD | SALESMAN | 1250.00 | 30 |
| MARTIN | SALESMAN | 1250.00 | 30 |
| BLAKE | MANAGER | 2850.00 | 30 |
| TURNER | SALESMAN | 1500.00 | 30 |
| JAMES | CLERK | 950.00 | 30 |
+--------+-----------+---------+--------+
14 rows in set (0.00 sec)
技巧:可以将子段联合成一个字段看。(两个字段联合分组)
mysql> select deptno,job, max(sal) from emp group by deptno, job;
+--------+-----------+----------+
| deptno | job | max(sal) |
+--------+-----------+----------+
| 20 | CLERK | 1100.00 |
| 30 | SALESMAN | 1600.00 |
| 20 | MANAGER | 2975.00 |
| 30 | MANAGER | 2850.00 |
| 10 | MANAGER | 2450.00 |
| 20 | ANALYST | 3000.00 |
| 10 | PRESIDENT | 5000.00 |
| 30 | CLERK | 950.00 |
| 10 | CLERK | 1300.00 |
+--------+-----------+----------+
9 rows in set (0.00 sec)
6.3、having
使用 $having$ 可以对分完组之后的数据进一步过滤。having 不能单独使用,having不能代替 where,having 必须和 group by 联合使用。
找出每个部门最高薪资,要求显示最高薪资大于 3000 的
-
找出每个部门最高薪资,按照部门分组求每一组的最大值
mysql> select deptno,max(sal) from emp group by deptno; +--------+----------+ | deptno | max(sal) | +--------+----------+ | 20 | 3000.00 | | 30 | 2850.00 | | 10 | 5000.00 | +--------+----------+ 3 rows in set (0.00 sec)
-
显示最高薪资大于 3000
mysql> select deptno,max(sal) from emp group by deptno having max(sal) > 3000;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
+--------+----------+
1 row in set (0.00 sec)
以上的 sql 语句效率比较低,可以先将大于 3000 的都找出来,然后再分组。
mysql> select deptno,max(sal) from emp where sal > 3000 group by deptno;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
+--------+----------+
1 row in set (0.00 sec)
优化策略:where 和 having,优先考虑 where。
找出每个部门平均薪资,要求显示平均薪资高于 2500 的
-
找出每个部门平均薪资高于 2500 的
mysql> select deptno,avg(sal) from emp group by deptno; +--------+-------------+ | deptno | avg(sal) | +--------+-------------+ | 20 | 2175.000000 | | 30 | 1566.666667 | | 10 | 2916.666667 | +--------+-------------+ 3 rows in set (0.00 sec)
-
显示平均薪资高于 2500 的
mysql> select deptno,avg(sal) from emp group by deptno having avg(sal) > 2500; # 这里不能用 where,必须用 having,因为 where 后面不能跟分组函数
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 10 | 2916.666667 |
+--------+-------------+
1 row in set (0.00 sec)
6.4、总结
select
...
from
...
where
...
group by
...
having
...
order by
...
以上关键字只能按照这个顺序来,不能颠倒。
执行顺序
- from
- where
- group by
- having
- select
- order by
从某张表中查询数据,先经过 where 条件筛选出有价值的数据。对这些有价值的数据进行分组。分组之后可以使用 having 继续过滤。 select 查询出来。最后排序输出!
案例:
找出每个岗位的平均薪资,要求显示平均薪资大于 1500 的,除 MANAGER 之外,要求按照平均薪资降序排
mysql> select job, avg(sal) as avgsal from emp where job<>'manager' group by job having avg(sal) > 1500 order by avgsal desc;
+-----------+-------------+
| job | avgsal |
+-----------+-------------+
| PRESIDENT | 5000.000000 |
| ANALYST | 3000.000000 |
+-----------+-------------+
2 rows in set (0.00 sec)
七、连接查询
什么是连接查询?
从一张表中单独查询,称为单表查询。
连接查询的分类
根据语法的年代分类:
-
L92:1992年的时候出现的语法
-
SQL99:1999年的时候出现的语法
主要介绍 SQL 99.
根据表连接的方式分类:
- 内连接:
- 等值连接
- 非等值连接
- 自连接
- 外连接:
- 左外连接(左连接)
- 右外连接(右连接)
- 全连接(用的少)
7.1、SQL92语法
显示每个员工信息,并显示所属的部门名称
emp 表中的数据
mysql> select ename from emp;
+--------+
| ename |
+--------+
| SMITH |
| ALLEN |
| WARD |
| JONES |
| MARTIN |
| BLAKE |
| CLARK |
| SCOTT |
| KING |
| TURNER |
| ADAMS |
| JAMES |
| FORD |
| MILLER |
+--------+
14 rows in set (0.00 sec)
dept 表中的数据
mysql> select dname from dept;
+------------+
| dname |
+------------+
| ACCOUNTING |
| RESEARCH |
| SALES |
| OPERATIONS |
+------------+
4 rows in set (0.00 sec)
将上面两表联合起来,如果不加条件限制:
mysql> select ename,dname from emp,dept;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | OPERATIONS |
| SMITH | SALES |
| SMITH | RESEARCH |
| SMITH | ACCOUNTING |
| ALLEN | OPERATIONS |
| ALLEN | SALES |
| ALLEN | RESEARCH |
| ALLEN | ACCOUNTING |
| WARD | OPERATIONS |
| WARD | SALES |
...
...
...
| FORD | ACCOUNTING |
| MILLER | OPERATIONS |
| MILLER | SALES |
| MILLER | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
56 rows in set (0.00 sec)
以上输出,不正确,输出了56条数据,其实就是两个表记录的成绩,这种情况我们称为:“笛卡儿乘积”,出现错误的原因是:没有指定连接条件.
指定条件连接:
mysql> select ename,dname from emp,dept where emp.deptno = dept.deptno;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
最终查询的结果条数是 $14$ 条,但是匹配的过程中,匹配的次数没有减少。
也可以这样写:
select emp.ename, dept.dname from emp, dept where emp.deptno=dept.deptno;
也可以使用别名
select e.ename, d.dname from emp e, dept d where e.deptno=d.deptno;
7.2、SQL99语法
7.2.1、内连接
内连接之等值连接
案例:查询每个员工所在部门名称员工名和部门名
SQL92的语法:
select ename,dname from emp,dept where emp.deptno = dept.deptno;
sql92的缺点:结构不清晰,表的连接条件,和后期进一步筛选的条件,都放到了where后面。
SQL99的语法:
select e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;
sql99优点:表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续添加where
SQL99语法:
select ... from a [inner] join b on a和b的连接条件 # inner 表内连可省略
内连接之非等值连接
案例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
数据:
# 员工数据
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.00 sec)
# 薪资等级数据
mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
5 rows in set (0.01 sec)
实现:
mysql> select e.ename,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal; # 条件不是一个等量条件,称为非等值连接。
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
14 rows in set (0.00 sec)
内连接之自连接
案例:查询员工的上级领导,要求显示员工名和对应的领导名?
数据
mysql> select empno,ename,mgr from emp;
+-------+--------+------+
| empno | ename | mgr |
+-------+--------+------+
| 7369 | SMITH | 7902 |
| 7499 | ALLEN | 7698 |
| 7521 | WARD | 7698 |
| 7566 | JONES | 7839 |
| 7654 | MARTIN | 7698 |
| 7698 | BLAKE | 7839 |
| 7782 | CLARK | 7839 |
| 7788 | SCOTT | 7566 |
| 7839 | KING | NULL |
| 7844 | TURNER | 7698 |
| 7876 | ADAMS | 7788 |
| 7900 | JAMES | 7698 |
| 7902 | FORD | 7566 |
| 7934 | MILLER | 7782 |
+-------+--------+------+
14 rows in set (0.00 sec)
实现:
mysql> select e.ename,b.ename as boss from emp e join emp b on e.mgr = b.empno; # 一张表看成两张表实现
+--------+-------+
| ename | boss |
+--------+-------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+-------+
13 rows in set (0.00 sec)
7.2.1、外连接
数据:
# 员工表
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.00 sec)
# 部门表
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
4 rows in set (0.00 sec)
内连接:
特点:完全能够匹配上这个条件的数据查询出来。
mysql> select e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
外连接之右连接:
表1 right [outer] join 表2 on 关联条件
outer可省略
如果 $right$ 左边部门没有员工,那么该部门也必须显示出来,将 $right$ 右边的表看成主表,主要是将这张表的数据全部查询出来。
mysql> select e.ename,d.dname from emp e right join dept d on e.deptno = d.deptno;
+--------+------------+
| ename | dname |
+--------+------------+
| MILLER | ACCOUNTING |
| KING | ACCOUNTING |
| CLARK | ACCOUNTING |
| FORD | RESEARCH |
| ADAMS | RESEARCH |
| SCOTT | RESEARCH |
| JONES | RESEARCH |
| SMITH | RESEARCH |
| JAMES | SALES |
| TURNER | SALES |
| BLAKE | SALES |
| MARTIN | SALES |
| WARD | SALES |
| ALLEN | SALES |
| NULL | OPERATIONS |
+--------+------------+
15 rows in set (0.00 sec)
外连接之左连接:
表1 left [outer] join 表2 on 关联条件
mysql> select e.ename,d.dname from emp e left join dept d on e.deptno = d.deptno;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
案例:查询每个员工的上级领导,要求显示所有员工的名字和领导名?
mysql> select e.ename as '员工', d.ename as '老板' from emp e left outer join emp d on e.mgr = d.empno;
+--------+-------+
| 员工 | 老板 |
+--------+-------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| KING | NULL | # 这里的 king 的老板查出来了,为空
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+-------+
14 rows in set (0.00 sec)
7.3、多张表的连接
语法:
select
...
from
a
join
b
on
a和b连接的条件
join
c
on
a和c连接的条件
right join
d
on
a和d的连接条件
# 一条SQL中内连接的外连接可以混用。
案例:找出每个员工的部门名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级?
数据:
# 员工数据
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.00 sec)
# 部门数据
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
4 rows in set (0.00 sec)
# 等级数据
mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
5 rows in set (0.00 sec)
实现:
mysql> select a.ename '员工名', b.dname '部门名',a.sal '薪资',c.GRADE '薪资等级' from emp a join dept b on a.deptno=b.deptno left join salgrade c on a.sal between c.losal and c. hisal;
+--------+------------+---------+----------+
| 员工名 | 部门名 | 薪资 | 薪资等级 |
+--------+------------+---------+----------+
| SMITH | RESEARCH | 800.00 | 1 |
| ALLEN | SALES | 1600.00 | 3 |
| WARD | SALES | 1250.00 | 2 |
| JONES | RESEARCH | 2975.00 | 4 |
| MARTIN | SALES | 1250.00 | 2 |
| BLAKE | SALES | 2850.00 | 4 |
| CLARK | ACCOUNTING | 2450.00 | 4 |
| SCOTT | RESEARCH | 3000.00 | 4 |
| KING | ACCOUNTING | 5000.00 | 5 |
| TURNER | SALES | 1500.00 | 3 |
| ADAMS | RESEARCH | 1100.00 | 1 |
| JAMES | SALES | 950.00 | 1 |
| FORD | RESEARCH | 3000.00 | 4 |
| MILLER | ACCOUNTING | 1300.00 | 2 |
+--------+------------+---------+----------+
14 rows in set (0.00 sec)
八、子查询
子查询就是嵌套的select语句,可以理解为子查询是一张表。
子查询出现的位置:
select
...(select)
from
...(select)
where
...(select)
8.1、在where语句中使用子查询
案例:找出比最低工资高的员工姓名和工资?
实现思路:
-
第一步:查询最低工资是多少
mysql> select min(sal) from emp; +----------+ | min(sal) | +----------+ | 800.00 | +----------+ 1 row in set (0.03 sec)
-
第二步:找出大于800的
mysql> select ename,sal from emp where sal>800; +--------+---------+ | ename | sal | +--------+---------+ | ALLEN | 1600.00 | | WARD | 1250.00 | | JONES | 2975.00 | | MARTIN | 1250.00 | | BLAKE | 2850.00 | | CLARK | 2450.00 | | SCOTT | 3000.00 | | KING | 5000.00 | | TURNER | 1500.00 | | ADAMS | 1100.00 | | JAMES | 950.00 | | FORD | 3000.00 | | MILLER | 1300.00 | +--------+---------+
-
合并
mysql> select ename,sal from emp where sal>(select min(sal) from emp); +--------+---------+ | ename | sal | +--------+---------+ | ALLEN | 1600.00 | | WARD | 1250.00 | | JONES | 2975.00 | | MARTIN | 1250.00 | | BLAKE | 2850.00 | | CLARK | 2450.00 | | SCOTT | 3000.00 | | KING | 5000.00 | | TURNER | 1500.00 | | ADAMS | 1100.00 | | JAMES | 950.00 | | FORD | 3000.00 | | MILLER | 1300.00 | +--------+---------+ 13 rows in set (0.00 sec)
8.2、from子句中的子查询
注意:from后面的子查询,可以将子查询的查询结果当做一张临时表。
案例:找出每个岗位的平均工资的薪资等级。
-
找出每个岗位的平均工资(按照岗位分组求平均值)
mysql> select job, avg(sal) from emp group by job; +-----------+-------------+ | job | avg(sal) | +-----------+-------------+ | CLERK | 1037.500000 | | SALESMAN | 1400.000000 | | MANAGER | 2758.333333 | | ANALYST | 3000.000000 | | PRESIDENT | 5000.000000 | +-----------+-------------+ 5 rows in set (0.00 sec)
-
把以上的查询结果就当做一张真实存在的表 a
salgrade 里面的数据:
mysql> select * from salgrade; +-------+-------+-------+ | GRADE | LOSAL | HISAL | +-------+-------+-------+ | 1 | 700 | 1200 | | 2 | 1201 | 1400 | | 3 | 1401 | 2000 | | 4 | 2001 | 3000 | | 5 | 3001 | 9999 | +-------+-------+-------+ 5 rows in set (0.00 sec)
将上面的两张表联合起来:
mysql> select a.*,b.grade from (select job, avg(sal) avgsal from emp group by job) a join salgrade b on a.avgsal between b.losal and hisal; +-----------+-------------+-------+ | job | avgsal | grade | +-----------+-------------+-------+ | CLERK | 1037.500000 | 1 | | SALESMAN | 1400.000000 | 2 | | MANAGER | 2758.333333 | 4 | | ANALYST | 3000.000000 | 4 | | PRESIDENT | 5000.000000 | 5 | +-----------+-------------+-------+ 5 rows in set (0.00 sec)
8.3、select后面的子查询
案例:找出每个员工的部门名称,要求显示员工名,部门名?
mysql> select e.ename,e.deptno, (select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;
+--------+--------+------------+
| ename | deptno | dname |
+--------+--------+------------+
| SMITH | 20 | RESEARCH |
| ALLEN | 30 | SALES |
| WARD | 30 | SALES |
| JONES | 20 | RESEARCH |
| MARTIN | 30 | SALES |
| BLAKE | 30 | SALES |
| CLARK | 10 | ACCOUNTING |
| SCOTT | 20 | RESEARCH |
| KING | 10 | ACCOUNTING |
| TURNER | 30 | SALES |
| ADAMS | 20 | RESEARCH |
| JAMES | 30 | SALES |
| FORD | 20 | RESEARCH |
| MILLER | 10 | ACCOUNTING |
+--------+--------+------------+
14 rows in set (0.00 sec)
注意:对于 select 后面的子查询来说,这个子查询只能返回一条结果,多余1条就报错。
# 错误:ERROR 1242 (21000): Subquery returns more than 1 row
mysql> select e.ename,e.deptno,(select dname from dept d) as dname from emp e;
ERROR 1242 (21000): Subquery returns more than 1 row
九、union合并查询
案例:查询工作岗位是 MANAGER 和 SALESMAN 的员工?
以前的方法:
mysql> select ename,job from emp where job='manager' or job = 'salesman';
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
用 union 合并:
mysql> select ename,job from emp where job='MANAGER' union select ename,job from emp where job = 'SALESMAN';
+--------+----------+
| ename | job |
+--------+----------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。
但是 $union$ 可以减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。
所以 $union$ 的效率要高一些。
比如:
a 连接 b 连接 c
a 10条记录
b 10条记录
c 10条记录
匹配的次数是:10^3 = 1000
a 连接 b 一个结果:10 * 10 = 100 次
a 连接 c 一个结果:10 * 10 = 100 次
使用union的话是:100次 + 100次 = 200次。(union把乘法变成了加法运算)
union 在使用的时候的注意事项?
# 错误的:union 在进行结果合并的时候,要求两个结果集的列数相同。
select ename,job from emp where job = 'MANAGER' union select ename from emp where job = 'SALESMAN';
# 在 MySQL 中可以运行,但是在 oracle 不可以报错。要求结果合并时列和列的数据类型也要一致。
mysql> select ename,job from emp where job = 'MANAGER' union select ename,sal from emp where job = 'SALESMAN';
+--------+---------+
| ename | job |
+--------+---------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| TURNER | 1500.00 |
+--------+---------+
7 rows in set (0.00 sec)
十、limit 的使用
limit 是将查询结果集的一部分取出来,通常使用在分页查询当中。
用法:
完整用法:limit startIndex,length
startIndex 是起始下标,起始下标为 0,length 是长度。
缺省用法:limit length
这是取前 length 个
案例1:
按照薪资降序,取出排名在前 5 名的员工?
mysql> select ename,sal from emp order by sal desc limit 5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
5 rows in set (0.00 sec)
注意:mysql 当中 limit 在 order by 之后执行
案例2:
取出工资排名在[3-5]名的员工?
mysql> select ename,sal from emp order by sal desc limit 2,3;
+-------+---------+
| ename | sal |
+-------+---------+
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
3 rows in set (0.00 sec)
案例3:
取出工资排名在[5-9]名的员工?
mysql> select ename,sal from emp order by sal desc limit 4,5;
+--------+---------+
| ename | sal |
+--------+---------+
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
+--------+---------+
5 rows in set (0.00 sec)
十一、表
11.1、创建表
语法格式:(建表属于 DDL 语句,DDL 包括:create drop alter)
creat table 表名(字段名1 数据类型 , 字段名2 数据类型,字段名3 数据类型);
MySql常用数据类型
类型 | 描述 |
---|---|
Char(长度) | 定长字符串,存储空间大小固定,适合作为主键或外键 |
Varchar(长度) | 变长字符串,存储空间等于实际数据空间 |
double(有效数字位数,小数位) | 数值型 |
Float(有效数字位数,小数位) | 数值型 |
Int( 长度) | 整型 |
bigint(长度) | 长整型 |
Date | 日期型 年月日 |
DateTime | 日期型 年月日 时分秒 毫秒 |
time | 日期型 时分秒 |
BLOB | Binary Large OBject(二进制大对象) |
CLOB | Character Large OBject(字符大对象) |
建立学生信息表,字段包括:学号、姓名、年龄、性别、email
create table t_student(
no int,
name varchar(32),
sex char(1),
age int(3),
email varchar(255)
)
快速创建表
# 将一个查询结果当做一张表新建
creat table emp2 as select * from emp;
# 查表
mysql> show tables;
+---------------------+
| Tables_in_dawncoody |
+---------------------+
| dept |
| emp |
| emp2 | # 将 emp 复制到 emp2
| salgrade |
| t_student |
| t_user |
+---------------------+
6 rows in set (0.04 sec)
11.2、删除表
drop table 表名; # 这不是删除表中的数据,这是把表删除。
11.3、向表中插入数据 (insert)
11.3.1、insert语法格式
语法格式:
insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3...);
注意:字段名 和值要一一对应。数量要对应,数据类型也要对应。
insert into t_student(no,name,sex,age,email) values(1,'nst','m',19,'nst@dawncoody.top');
insert into t_student(email,name,sex,age, no) values('dawn@dawncoody.top', 'dawn','f',20,2);
没有给其他字段指定值的话,默认值是 NULL。
创建表时修改默认值:
create table t_student(
no int,
name varchar(32),
sex char(1) default 'm', # 这里指定默认值 m
age int(3),
email varchar(255)
);
insert 语句中的字段名如果省略,就表示都写上了
# 错误的
insert into t_student values(2);
# 正确的
insert into t_student values(2,'lisi','f',20,'lisi@123.com');
insert 语句可以一次插入多条记录
# 插入了3条语句
insert into t_student(no,name,sex,age,email) values(1,'lisi','f',30,'lisi@12.com'),(2,'zs','f',20,'zs@123.com'),(3,'wangwu','m',22,'wangwu@123.com');
# 查询
mysql> select * from t_student;
+------+--------+------+------+----------------+
| no | name | sex | age | email |
+------+--------+------+------+----------------+
| 1 | lisi | f | 30 | lisi@12.com |
| 2 | zs | f | 20 | zs@123.com |
| 3 | wangwu | m | 22 | wangwu@123.com |
+------+--------+------+------+----------------+
3 rows in set (0.00 sec)
将查询结果插入到一张表中
insert into 表名 select语句
11.3.2、insert 插入日期
format(数字,‘格式’):数字格式化
# 不常用
select ename,format(sal, '$999,999') as sal from emp;
str_to_date:将字符串 varchar 类型转换成 date 类型
date_format:将 date 类型转换成具有一定格式的 varchar 类型。
先建立一张有日期的表:
drop table if exists t_user; # 这里表示如果有 t_user 表就删除该表
create table t_user(
id int,
name varchar(32),
birth date # 生日用date日期类型
)
mysql> desc t_user;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| birth | date | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.03 sec)
插入数据
# 这里会报错,最后一个是日期类型必须使用日期格式
insert into t_user(id, name, birth) values(1,'dawn','01-10-1990');
可以使用str_to_date函数进行类型转换
语法格式:str_to_date('字符串日期','日期格式')
mysql 的日期格式:
格式 | 含义 |
---|---|
%Y | 年 |
%m | 月 |
%d | 日 |
%h | 时 |
%i | 分 |
%s | 秒 |
# 插入日期要格式化
insert into t_user(id, name, birth) values(1,'dawn',str_to_date('01-10-1999', '%d-%m-%Y'));
如果你提供的日期字符串是按照 %Y-%m-%d
这样的格式,str_to_date 函数就可以省略不写
insert into t_user(id,name,birth) values(2,'nst','2000-02-02');
date_format
用法:date_format(日期类型数据,'日期格式')
这个函数可以将日期类型转换成特定格式的字符串。
select id,name,date_format(birth,'%m/%d/%Y') as birth from t_user;
可以直接使用查询日期的方式:
# 会自动化的将数据库中的 date 类型转换成 varchar 类型。并且采用的格式是 mysql 默认的格式:'%Y-%m-%d'
mysql> select id,name,birth from t_user;
+------+------+------------+
| id | name | birth |
+------+------+------------+
| 1 | dawn | 1999-10-01 |
| 2 | nst | 2000-02-02 |
+------+------+------------+
2 rows in set (0.00 sec)
now() 获取当前系统时间
insert into t_user(id,name,birth) values(2,'li',now());
11.4、修改 update
语法格式:update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3... where条件;
注意:没有条件限制会导致所有数据更新。
update t_user set name='jack',birth='2000-10-11',id=3 where name=li;
# 修改后的数据
mysql> select * from t_user;
+------+------+------------+
| id | name | birth |
+------+------+------------+
| 1 | dawn | 1999-10-01 |
| 2 | nst | 2000-02-02 |
| 3 | jack | 2000-10-11 |
+------+------+------------+
3 rows in set (0.00 sec)
11.5、删除数据
delete 删除数据(这种操作属于DML语句)
语法格式:delete from 表名 where 条件
注意:没有条件,整张表的数据会全部删除
delete from t_user where id = 3;
# 删除后的数据
mysql> select * from t_user;
+------+------+------------+
| id | name | birth |
+------+------+------------+
| 1 | dawn | 1999-10-01 |
| 2 | nst | 2000-02-02 |
+------+------+------------+
2 rows in set (0.03 sec)
delect 语句删除的原理:
表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放。优点:删除效率比较低。缺点:支持回滚,可以恢复数据。
truncate 删除数据(这种操作属于DDL操作)
这种删除效率比较高,表被一次截断,物理删除。优点:快速。缺点:不支持回滚。
truncate table t_user;
mysql> select * from t_user;
Empty set (0.04 sec)
11.6、表结构修改(不常用)
什么是对表结构的修改
添加一个字段,删除一个字段,修改一个字段!!!
对表结构的修改需要使用 alter 属于DDL语句
11.7、创建表加入约束
在创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性。
- 常见的约束
- 非空约束,not null2。
- 唯一约束,unique
- 主键约束,primary key
- 外键约束,foreign key
- 自定义检查约束,check(不建议使用)(在mysql中现在还不支持)
11.7.1、非空约束:not null
非空约束,针对某个字段设置其值不为空,如:学生的姓名不能为空。
drop table if exists t_vip; # 如果有 t_vip 就删除
create table t_vip( # 创建 t_vip 表
id int ,
name varchar(255) not null # 给定约束 name 不能为空,255 是建议字符长度
);
insert into t_vip(id, name) values(1,'nst');
insert into t_vip(id,name) values(2,'dawn');
# 执行下面语句后会报错
insert into t_vip(id) values(3); # 这里name因为为空,所以报错
11.7.2、唯一性约束:unique
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) unique, # 约束直接添加到列后面的,叫做列级约束
email varchar(255)
);
insert into t_vip(id,name,email) values(1,'dawn','dawn@dawncoody.com');
insert into t_vip(id,name,email) values(2,'nst','dawnnst@dawncoody.com');
# 执行下面代码会报错,因为 name 不能为重复。
insert into t_vip(id,name,email) values(3,'dawn','dawnfd@dawncoody.com');
# 这里不会报错,空名字不算重复
insert into t_vip(id) values(4);
insert into t_vip(id) values(5);
将 id 和 name 和 email 两个字段联合起来唯一
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255),
email varchar(255),
unique(name,email) # 约束没有添加到列的后面,这种级别称为表级约束
);
insert into t_vip(id,name,email) values(1,'dawn','dawn@dawncoody.com');
insert into t_vip(id,name,email) values(2,'dawn','3434@dawncoody.com');
# 运行下面的代码报错
insert into t_vip(id,name,email) values(3,'dawn','dawn@dawncoody.com');
ERROR 1062 (23000): Duplicate entry 'dawn-dawn@dawncoody.com' for key 't_vip.name'
unique 和 not null 可以联合
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) unique not null
);
# 查看表结构
desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(255) | NO | PRI | NULL | | # 这里变成主键字段
+-------+--------------+------+-----+---------+-------+
# 在mysql中,如果一个字段同时被 not null 和 unique 约束的话,该字段自动变成主键字段。(注意:oracle中不一样)
11.7.3、主键约束(primary key 简称 PK)
每个表应该具有主键,主键可以标识记录的唯一性,主键分为单一主键和复合(联合)主键,单一主键是由一个字段构成的,复合(联合)主键是由多个字段构成的
drop table if exists t_vip;
create table t_vip(
id int primary key,
name varchar(222)
);
insert into t_vip(id,name) values(1,'dawn');
insert into t_vip(id,name) values(2,'nst');
insert into t_vip(id,name) values(3,'dawn');
# 报错,3 为主键值不能重复
insert into t_vip(id,name) values(3,'wuh');
ERROR 1062 (23000): Duplicate entry '3' for key 't_vip.PRIMARY'
# 报错,主键值不能为空
insert into t_vip(name) values('wuh');
ERROR 1364 (HY000): Field 'id' doesn't have a default value
复合主键(不建议使用):
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255),
email varchar(255),
primary key(id,name) # 表级约束
);
insert into t_vip(id,name,email) values(1,'dawn','dawn@dawncoody.com');
insert into t_vip(id,name,email) values(1,'nst','dawnnst@dawncoody.com');
# 报错:id和name联合起来不能重复
insert into t_vip(id,name,email) values(1,'dawn','d@dawncoody.com');
ERROR 1062 (23000): Duplicate entry '1-dawn' for key 't_vip.PRIMARY'
一个表中主键约束能加两个吗?
# 报错,不能有两个主键约束
drop table if exists t_vip;
create table t_vip(
id int primary key,
name varchar(255) primary key
)
ERROR 1068 (42000): Multiple primary key defined
主键值建议使用:
- int
- bigint
- char
- 不建议使用 varchar。主键值一般都是数字,一般都是定长的
主键除了:单一主键和复合主键之外,还可以这样分类
- 自然主键:主键值是一个自然数,和业务没关系
- 业务主键:主键值和业务紧密关联
在mysql 当中,有一种机制,可以帮助我们自动维护一个主键值
drop table if exists t_vip;
create table t_vip(
id int primary key auto_increment, # auto_increment 表示自增,从 1 开始,以 1 递增
name varchar(255)
);
insert into t_vip(name) values('dawn');
insert into t_vip(name) values('dawn');
insert into t_vip(name) values('dawn');
insert into t_vip(name) values('dawn');
select * from t_vip;
+----+------+
| id | name |
+----+------+
| 1 | dawn |
| 2 | dawn |
| 3 | dawn |
| 4 | dawn |
+----+------+
4 rows in set (0.00 sec)
11.7.4、外键约束(foreign key)
外键主要是维护表之间的关系的,主要是为了保证参照完整性,如果表中的某个字段为外键字段,那么该字段的值必须来源于参照的表的主键,如:emp中的deptno值必须来源于dept表中的deptno字段值。
建立学生表和班级表之间的连接:
首先建立班级表 t_class(父表):
drop table if exists t_class;
drop table if exists t_class;
create table t_class(
classno int primary key,
classname varchar(255)
);
在 t_student 中加入外键约束
drop table if exists t_student;
create table t_student(
no int primary key auto_increment,
name varchar(255),
cno int,
foreign key(cno) references t_class(classno) # cno的外键约束
);
向 t_class 和 t_student 中加入数据
# t_class
insert into t_class(classno, classname) values(100,'高三1班');
insert into t_class(classno, classname) values(101,'高三1班');
# t_student
insert into t_student(name,cno) values('jack',100);
insert into t_student(name,cno) values('lucy',100);
insert into t_student(name,cno) values('hanmeimei',100);
insert into t_student(name,cno) values('lilei',100);
insert into t_student(name,cno) values('zhangsan',101);
insert into t_student(name,cno) values('lisi',101);
insert into t_student(name,cno) values('wangwu',101);
insert into t_student(name,cno) values('zhaoliu',101);
注意:
子表中的外键引用的父表中的字段,不一定是主键,但至少具有唯一性约束
十二、存储引擎(了解)
12.1、存储引擎的使用
-
数据库中的各表均被(在创建表时)指定的存储引擎来处理。
-
服务器可用的引擎依赖于以下因素:
- MySQL的版本
- 服务器在开发时如何被配置
- 启动选项
-
为了解当前服务器中有哪些存储引擎可用,可使用SHOW ENGINES语句:
mysql> show engines G *************************** 1. row *************************** Engine: MEMORY Support: YES Comment: Hash based, stored in memory, useful for temporary tables Transactions: NO XA: NO Savepoints: NO *************************** 2. row *************************** Engine: MRG_MYISAM Support: YES Comment: Collection of identical MyISAM tables Transactions: NO XA: NO Savepoints: NO *************************** 3. row *************************** Engine: CSV Support: YES Comment: CSV storage engine Transactions: NO XA: NO Savepoints: NO *************************** 4. row *************************** Engine: FEDERATED Support: NO Comment: Federated MySQL storage engine Transactions: NULL XA: NULL Savepoints: NULL *************************** 5. row *************************** Engine: PERFORMANCE_SCHEMA Support: YES Comment: Performance Schema Transactions: NO XA: NO Savepoints: NO *************************** 6. row *************************** Engine: MyISAM Support: YES Comment: MyISAM storage engine Transactions: NO XA: NO Savepoints: NO *************************** 7. row *************************** Engine: InnoDB Support: DEFAULT Comment: Supports transactions, row-level locking, and foreign keys Transactions: YES XA: YES Savepoints: YES *************************** 8. row *************************** Engine: BLACKHOLE Support: YES Comment: /dev/null storage engine (anything you write to it disappears) Transactions: NO XA: NO Savepoints: NO *************************** 9. row *************************** Engine: ARCHIVE Support: YES Comment: Archive storage engine Transactions: NO XA: NO Savepoints: NO 9 rows in set (0.00 sec)
-
在创建表时,可使用ENGINE选项为CREATE TABLE语句显式指定存储引擎。
create table tablename (NO INT) engines = MyISAM;
-
如果在创建表时没有显式指定存储引擎,则该表使用当前默认的存储引擎
-
默认的存储引擎可在my.ini配置文件中使用
default-storage-engine
选项指定。 -
现有表的存储引擎可使用ALTER TABLE语句来改变:
alter table tablename engine = innodb
; -
为确定某表所使用的存储引擎,可以使用
show create table
或show table status
语句:mysql> SHOW CREATE TABLE empG
mysql> SHOW TABLE STATUS LIKE 'emp' G
12.2、常用的搜索引擎
12.2.1、MyISAM 存储引擎
-
MyISAM存储引擎是MySQL最常用的引擎。
-
它管理的表具有以下特征:
- 使用三个文件表示每个表:
- 格式文件 — 存储表结构的定义(mytable.frm)
- 数据文件 — 存储表行的内容(mytable.MYD)
- 索引文件 — 存储表上索引(mytable.MYI)
- 灵活的AUTO_INCREMENT字段处理
- 可被转换为压缩、只读表来节省空间
- 对于一张表来说,只要有主键,或者加油 unique 约束的字段上会自动创建索引。
- 使用三个文件表示每个表:
12.2.2、InnoDB 存储引擎
- InnoDB存储引擎是MySQL的缺省引擎。
- 它管理的表具有下列主要特征:
- 每个InnoDB表在数据库目录中以.frm格式文件表示
- InnoDB表空间tablespace被用于存储表的内容
- 提供一组用来记录事务性活动的日志文件
- 用COMMIT(提交)、SAVEPOINT及ROLLBACK(回滚)支持事务处理
- 提供全ACID兼容
- 在MySQL服务器崩溃后提供自动恢复
- 多版本(MVCC)和行级锁定
- 支持外键及引用的完整性,包括级联删除和更新
12.2.3、MEMORY存储引擎
- 使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得 MEMORY 存储引擎非常快。
- MEMORY 存储引擎管理的表具有下列特征:
- 在数据库目录内,每个表均以 .frm 格式的文件表示。
- 表数据及索引被存储在内存中。
- 表级锁机制。
- 不能包含 TEXT 或 BLOB 字段。
- MEMEORY 存储引擎以前被称为 HEAP 引擎。
优点:查询效率最高
缺点:不安全,关机后数据消失。
十三、事务
13.1、概述
一个事务其实就是一个完整的业务逻辑。
假设转账,从 A 账户向 B 账户中转账 10000.将 A 账户的钱减去 10000,将 B 账户的钱加上 10000 这就是一个完整的业务逻辑。
事务可以保证多个操作原子性,要么全成功,要么全失败。对于数据库来说事务保证批量的DML要么全成功,要么全失败。
事务具有四个特征ACID:
- 原子性(Atomicity)
- 整个事务中的所有操作,必须作为一个单元全部完成(或全部取消)。
- 一致性(Consistency)
- 在事务开始之前与结束之后,数据库都保持一致状态。
- 隔离性(Isolation)
- 一个事务不会影响其他事务的运行。
- 持久性(Durability)
- 在事务完成以后,该事务对数据库所作的更改将持久地保存在数据库之中,并不会被回滚。
事务中存在一些概念:
- 事务(Transaction):一批操作(一组DML)
- 开启事务(Start Transaction)
- 回滚事务(rollback)
- 提交事务(commit)
- SET AUTOCOMMIT:禁用或启用事务的自动提交模式
当执行DML语句是其实就是开启一个事务
关于事务的回滚需要注意:只能回滚insert、delete和update语句,不能回滚select(回滚select没有任何意义),对于create、drop、alter这些无法回滚.
事务只对DML有效果。
注意:rollback,或者commit后事务就结束了。
13.2、事务的提交与回滚演示
-
创建表
drop table if exists user; create table user( id int (11) primary key not null auto_increment , username varchar(30), password varchar(30) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-
查询表中的数据
mysql> select * from user; Empty set (0.04 sec)
-
开启事务
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
- 插入数据
insert into user (username,password) values('zhangsan','123');
- 查看数据
mysql> select * from user;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhangsan | 123 |
+----+----------+----------+
1 row in set (0.00 sec)
-
修改数据
update user set username='lisi' where id = 1;
-
查看数据
mysql> select * from user; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | lisi | 123 | +----+----------+----------+ 1 row in set (0.00 sec)
-
回滚事务
rollback;
-
查看数据
mysql> select * from user; Empty set (0.00 sec)
13.3、自动提交模式
-
自动提交模式用于决定新事务如何及何时启动。
-
启用自动提交模式:
- 如果自动提交模式被启用,则单条DML语句将缺省地开始一个新的事务。
- 如果该语句执行成功,事务将自动提交,并永久地保存该语句的执行结果。
- 如果语句执行失败,事务将自动回滚,并取消该语句的结果。
- 在自动提交模式下,仍可使用START TRANSACTION语句来显式地启动事务。这时,一个事务仍可包含多条语句,直到这些语句被统一提交或回滚。
-
禁用自动提交模式:
- 如果禁用自动提交,事务可以跨越多条语句。
- 在这种情况下,事务可以用COMMIT和ROLLBACK语句来显式地提交或回滚。
-
自动提交模式可以通过服务器变量AUTOCOMMIT来控制。
-
例如:
mysql> SET AUTOCOMMIT = OFF;
mysql> SET AUTOCOMMIT = ON;
或
mysql> SET SESSION AUTOCOMMIT = OFF;
mysql> SET SESSION AUTOCOMMIT = ON;
show variables like '%auto%'; -- 查看变量状态
13.4、事务的隔离级别
13.4.1、四个隔离级别
-
InnoDB 实现了四个隔离级别,用以控制事务所做的修改,并将修改通告至其他并发的事务:
-
读未提交:read uncommitted(最低的隔离级别)
允许一个事务可以看到其他事务未提交的修改。
-
读已提交:read committed
允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的。
-
可重复读:repeatable read
确保如果在一个事务中执行两次相同的SELECT语句,都能得到相同的结果,不管其他事务是否提交这些修改。 (银行总账)该隔离级别为InnoDB的缺省设置。
-
序列化/串行化:serializable(最高的隔离级别)
将一个事务与其他事务完全地隔离。
例:A可以开启事物,B也可以开启事物
A在事物中执行DML语句时,未提交
B不以执行DML,DQL语句
-
13.4.2、隔离级别一致性问题的关系
13.4.3、查看隔离级别
-
服务器变量tx_isolation(包括会话级和全局级两个变量)中保存着当前的会话隔离级别。
-
为了查看当前隔离级别,可访问tx_isolation变量:
- 查看会话级的当前隔离级别:
mysql> SELECT @@tx_isolation;
或:
mysql> SELECT @@session.tx_isolation;
-
查看全局级的当前隔离级别:
mysql> SELECT @@global.tx_isolation;
13.4.4、并发事务与隔离级别实例
read uncommitted(未提交读) --脏读(Drity Read):
会话一 | 会话二 |
---|---|
mysql> prompt s1> | mysql> use bjpowernode |
s1>use bjpowernode | mysql> prompt s2> |
s1>create table tx ( id int(11), num int (10) ); | |
s1>set global transaction isolation level read uncommitted; | |
s1>start transaction; | |
s2>start transaction; | |
s1>insert into tx values (1,10); | |
s2>select * from tx; | |
s1>rollback; | |
s2>select * from tx; |
read committed(已提交读)
会话一 | 会话二 |
---|---|
s1> set global transaction isolation level read committed; | |
s1>start transaction; | |
s2>start transaction; | |
s1>insert into tx values (1,10); | |
s1>select * from tx; | |
s2>select * from tx; | |
s1>commit; | |
s2>select * from tx; |
repeatable read(可重复读)
会话一 | 会话二 |
---|---|
s1> set global transaction isolation level repeatable read; | |
s1>start transaction; | s2>start transaction; |
s1>select * from tx; | |
s1>insert into tx values (1,10); | |
s2>select * from tx; | |
s1>commit; | |
s2>select * from tx; |
十四、索引
14.1、索引原理
索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL不得不首先以第一条记录开始,然后读完整个表直到它找出相关的行。表越大,花费时间越多。对于一个有序字段,可以运用二分查找(Binary Search),这就是为什么性能能得到本质上的提高。MYISAM和INNODB都是用B+Tree作为索引结构。
在 MySQL 当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,在MyISAM
存储引擎中,索引存储在一个.MYI文件中。在 InnoDB
存储引擎中索引存储在一个逻辑名称叫做 tablespace 的当中。在MEMEORY
存储引擎当中索引被存储在内存当中。不管索引存储在哪里,索引在 MySQL 当中都是一个树的形式存在。(自平衡二叉树:B-Tree)
MySQL 在查询方面主要就是两种方式:
- 全表扫描
- 根据索引检索
在 mysql 中,什么条件下,我们会考虑给字段添加索引?
- 数据量庞大
- 该字段经常出现在 where 的后面,以条件的形式存在,也就是说这个字段总是被扫描。
- 该字段很少的 DML 操作。(因为 DML 之后,索引需要重新排序。)
14.2、索引的应用
14.2.1、创建索引
# 给 emp 表的 ename 字段添加索引起名:emp_ename_indx
create index emp_ename_index on emp(ename);
14.2.2、删除索引
# 将 emp 表上的 emp_ename_index 索引对象删除
drop index emp_ename_index on emp;
14.2.3、查看索引
show index from emp;
14.2.4、使用索引
查看一条 SQL 语句时候使用了索引进行检索
explain select * from emp where ename ='king';
14.2.5、索引失效
- ename 上添加了索引,也不会走索引,因为模糊匹配中以 '%' 开头了
select * from emp where ename like '%T';
-
使用 or 的时候会失效,如果使用 or 那么要求 or 两边的条件字段都要有索引,才会走索引,如果其中一边有一个字段没有索引,那么另一个字段上的索引也会失效。
# 如果 ename 这个字段有索引,而 job 没有,索引就会失效 select * from emp where ename = 'KING' or job = 'MANAGER'
-
使用复合索引的时候,没有使用左侧的列查找。
# 给 job和sal 复合添加索引 create index emp_job_sal_index on emp(job,sal); # 使用了索引 select * from emp where job = 'MANAGER'; # 没有使用索引 select * from emp where sal = 800;
-
在 where 当中索引列参加了运算
create index emp_sal_index on emp(sal); # 使用了索引 select * from emp where sal = 800; # 没有使用索引 select * from emp where sal + 1 = 800;
-
在 where 当中索引列使用了函数
create index emp_ename_index on emp(ename); # 没有使用索引 select * from emp where lower(ename) = 'smith';
十五、视图
15.1、什么是视图
- 视图是一种根据查询(也就是SELECT表达式)定义的数据库对象,用于获取想要看到和使用的局部数据。 (简单来说就是站在不同的角度去看待同一份数据)。
- 视图有时也被成为“虚拟表”。
- 视图可以被用来从常规表(称为“基表”)或其他视图中查询数据。
- 相对于从基表中直接获取数据,视图有以下好处:
- 访问数据变得简单
- 可被用来对不同用户显示不同的表的内容
15.2、创建视图
create view 视图名 as select * from 表名;
15.3、删除视图
drop view 视图名;
15.3、视图可以做什么
我们可以向视图对象进行增删改查,对视图对象的增删改查,会导致原表被操作!(视图的特点:通过对视图的操作,会影响原表数据。)
十六、DBA命令
16.1、新建用户
CREATE USER username IDENTIFIED BY 'password';
# 说明:username——你将创建的用户名, password——该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器.
例如:
create user p361 identified by '123';
# --可以登录但是只可以看见一个库 information_schema
16.2、授权
# 命令详解
mysql> grant all privileges on dbname.tbname to 'username'@'login ip' identified by 'password' with grant option;
/*
1) dbname=*表示所有数据库
2) tbname=*表示所有表
3) login ip=%表示任何ip
4) password为空,表示不需要密码即可登录
5) with grant option; 表示该用户还可以授权给其他用户
*/
-
细粒度授权
首先以root用户进入mysql,然后键入命令:grant select,insert,update,delete on . to p361 @localhost Identified by "123"; 如果希望该用户能够在任何机器上登陆mysql,则将localhost改为 "%" 。
-
粗粒度授权
我们测试用户一般使用该命令授权,
GRANT ALL PRIVILEGES ON *.* TO 'p361'@'%' Identified by "123";
注意:用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:
GRANT ALL PRIVILEGES ON *.* TO 'p361'@'%' Identified by "123" WITH GRANT OPTION;
privileges包括:
- alter:修改数据库的表
- create:创建新的数据库或表
- delete:删除表数据
- drop:删除数据库/表
- index:创建/删除索引
- insert:添加表数据
- select:查询表数据
- update:更新表数据
- all:允许任何操作
- usage:只允许登录
回收权限
命令详解
# 命令详解
revoke privileges on dbname[.tbname] from username;
revoke all privileges on *.* from p361;
use mysql
select * from user
# 进入 mysql库中
# 修改密码;
update user set password = password('qwe') where user = 'p646';
刷新权限;
flush privileges
16.3、导出导入数据库
# 导出数据库
mysqldump dawncoody > D:dawncoody.sql -uroot -p123
# 导出指定库下的指定表
mysqldump dawncoody emp> D:dawncoody.sql -uroot –p123
# 导入
# 登录MYSQL数据库管理系统之后执行:
source D:dawncoody.sql
十七、数据库设计的三范式
数据库表的设计依据。教你怎么进行数据库表的设计。
17.1、第一范式
数据库表中不能出现重复记录,每个字段是原子性的不能再分
不符合第一范式的示例
学生编号 | 学生姓名 | 联系方式 |
---|---|---|
1001 | 张三 | zs@gmail.com,1359999999 |
1002 | 李四 | ls@gmail.com,13699999999 |
1001 | 王五 | ww@163.net,13488888888 |
存在问题:
-
最后一条记录和第一条重复(不唯一,没有主键)
-
联系方式字段可以再分,不是原子性的
学生编号(pk) | 学生姓名 | 联系电话 | |
---|---|---|---|
1001 | 张三 | zs@gmail.com | 1359999999 |
1002 | 李四 | ls@gmail.com | 13699999999 |
1003 | 王五 | ww@163.net | 13488888888 |
关于第一范式,每一行必须唯一,也就是每个表必须有主键,这是我们数据库设计的最基本要求,主要通常采用数值型或定长字符串表示,关于列不可再分,应该根据具体的情况来决定。如联系方式,为了开发上的便利行可能就采用一个字段了。
17.2、第二范式
第二范式是建立在第一范式基础上的,另外要求所有非主键字段完全依赖主键,不能产生部分依赖
示例:
学生编号 | 学生姓名 | 教师编号 | 教师姓名 |
---|---|---|---|
1001 | 张三 | 001 | 王老师 |
1002 | 李四 | 002 | 赵老师 |
1003 | 王五 | 001 | 王老师 |
1001 | 张三 | 002 | 赵老师 |
确定主键:
学生编号(PK) | 教师编号(PK) | 学生姓名 | 教师姓名 |
---|---|---|---|
1001 | 001 | 张三 | 王老师 |
1002 | 002 | 李四 | 赵老师 |
1003 | 001 | 王五 | 王老师 |
1001 | 002 | 张三 | 赵老师 |
学生编号,教室编号,两个字段联合做主键,复合主键,经过修改后,以上的表满足了第一范式。但是不满足第二范式,学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号,而教师姓名部门依赖了主键的一个字段教师编号,这就是第二范式部分依赖。
解决方案如下:
学生信息表
学生编号(PK) | 学生姓名 |
---|---|
1001 | 张三 |
1002 | 李四 |
1003 | 王五 |
教师信息表
教师编号(PK) | 教师姓名 |
---|---|
001 | 王老师 |
002 | 赵老师 |
教师和学生的关系表
学生编号(PK) -> 学生表的学生编号 | 教师编号(PK) ->教师表的教师编号 |
---|---|
1001 | 001 |
1002 | 002 |
1003 | 001 |
1001 | 002 |
设计口诀:
多对多,三张表,关系表两个外键
17.3、第三范式
建立在第二范式基础上的,非主键字段不能传递依赖于主键字段。(不要产生传递依赖)
学生编号(PK) | 学生姓名 | 班级编号 | 班级名称 |
---|---|---|---|
1001 | 张三 | 01 | 一年一班 |
1002 | 李四 | 02 | 一年二班 |
1003 | 王五 | 03 | 一年三班 |
1004 | 赵六 | 03 | 一年三班 |
满足第一范式,有主键。满足第二范式,因为主键不是复合主键,没有产生部分依赖。主键是单一主键。不满足第三范式,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖,解决的办法是将冗余字段单独拿出来建立表,如:
学生信息表
学生编号(PK) | 学生姓名 | 班级编号(FK) |
---|---|---|
1001 | 张三 | 01 |
1002 | 李四 | 02 |
1003 | 王五 | 03 |
1004 | 赵六 | 03 |
班级信息表
班级编号(PK) | 班级名称 |
---|---|
01 | 一年一班 |
02 | 一年二班 |
设计口诀:
一对多,两张表,多的表加外键
十八、题目练习
18.1、取得每个部门最高薪水的人员名称
-
取得每个部门最高薪水(按照部门分组,找出每一组的最大值)
mysql> select deptno,max(sal) as maxsal from emp group by deptno; +--------+---------+ | deptno | maxsal | +--------+---------+ | 20 | 3000.00 | | 30 | 2850.00 | | 10 | 5000.00 | +--------+---------+ 3 rows in set (0.00 sec)
-
将以上的查询结果当做一张临时表t,t 和 emp 表连接,条件:
t.deptno = emp.deptno and t.maxsal = emp.sal
select emp.ename, t.* from emp join (select deptno, max(sal) as maxsal from emp group by deptno) t on t.deptno = emp.deptno and t.maxsal = emp.sal; +-------+--------+---------+ | ename | deptno | maxsal | +-------+--------+---------+ | BLAKE | 30 | 2850.00 | | SCOTT | 20 | 3000.00 | | KING | 10 | 5000.00 | | FORD | 20 | 3000.00 | +-------+--------+---------+
18.2、哪些人的薪水在部门的平均薪水之上
-
取得每个部门的平均薪水
select deptno, avg(sal) as avgsal from emp group by deptno; +--------+-------------+ | deptno | avgsal | +--------+-------------+ | 20 | 2175.000000 | | 30 | 1566.666667 | | 10 | 2916.666667 | +--------+-------------+ 3 rows in set (0.00 sec)
-
将以上的查询的结果当做一张临时表 t,t 和 emp 表连接条件是:
emp.deptno = t.deptno and emp.sal > t.avgsal
select t.*,emp.ename, emp.sal from emp join (select deptno, avg(sal) as avgsal from emp group by deptno) t on emp.deptno = t.deptno and emp.sal > t.avgsal; +--------+-------------+-------+---------+ | deptno | avgsal | ename | sal | +--------+-------------+-------+---------+ | 30 | 1566.666667 | ALLEN | 1600.00 | | 20 | 2175.000000 | JONES | 2975.00 | | 30 | 1566.666667 | BLAKE | 2850.00 | | 20 | 2175.000000 | SCOTT | 3000.00 | | 10 | 2916.666667 | KING | 5000.00 | | 20 | 2175.000000 | FORD | 3000.00 | +--------+-------------+-------+---------+ 6 rows in set (0.00 sec)
18.3、取得部门中(所有人的)平均的薪水等级
-
找出每个人的薪水等级
emp 和 salgrade 表连接 连接条件
emp.sal between s.losal and s.hisal
select emp.ename,emp.sal,emp.deptno,salgrade.grade from emp join salgrade on emp.sal between salgrade.losal and salgrade.hisal; +--------+---------+--------+-------+ | ename | sal | deptno | grade | +--------+---------+--------+-------+ | SMITH | 800.00 | 20 | 1 | | ALLEN | 1600.00 | 30 | 3 | | WARD | 1250.00 | 30 | 2 | | JONES | 2975.00 | 20 | 4 | | MARTIN | 1250.00 | 30 | 2 | | BLAKE | 2850.00 | 30 | 4 | | CLARK | 2450.00 | 10 | 4 | | SCOTT | 3000.00 | 20 | 4 | | KING | 5000.00 | 10 | 5 | | TURNER | 1500.00 | 30 | 3 | | ADAMS | 1100.00 | 20 | 1 | | JAMES | 950.00 | 30 | 1 | | FORD | 3000.00 | 20 | 4 | | MILLER | 1300.00 | 10 | 2 | +--------+---------+--------+-------+ 14 rows in set (0.03 sec)
-
基于以上的结果继续按照 deptno 分组,求 grade 的平均值。
select emp.deptno,avg(salgrade.grade) from emp join salgrade on emp.sal between salgrade.losal and salgrade.hisal group by emp.deptno; +--------+---------------------+ | deptno | avg(salgrade.grade) | +--------+---------------------+ | 20 | 2.8000 | | 30 | 2.5000 | | 10 | 3.6667 | +--------+---------------------+
18.4、不用组函数(Max),取得最高薪水
方法一:降序,limit 1
select ename,sal from emp order by sal desc limit 1;
方法二:表的自连接
select
ename,sal
from
emp
where
sal not in(select distinct a.sal from emp a join emp b on a.sal < b.sal);
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
+-------+---------+
18.5、取得平均薪水最高的部门的部门编号
第一种方案:
-
找出每个部门的平均薪水
select deptno,avg(sal) as avgsal from emp group by deptno; +--------+-------------+ | deptno | avgsal | +--------+-------------+ | 20 | 2175.000000 | | 30 | 1566.666667 | | 10 | 2916.666667 | +--------+-------------+
-
降序选第一个
select deptno,avg(sal) as avgsal from emp group by deptno order by avgsal desc limit 1;
第二种方案: max 函数
select max(t.avgsal) from (select deptno,avg(sal) as avgsal from emp group by deptno) t;
18.6 、取得平均薪水最高的部门的部门名称
select
d.dname,avg(e.sal) as avgsal
from
emp e
join
dept d
on
e.deptno = d.deptno
group by
d.dname
order by
avgsal desc
limit
1;
18.7、求平均薪水的等级最低的部门名称
第一步:按照部门名称分组,找出每个部门的平均薪水
select deptno,avg(sal) as avgsal from emp group by deptno;
第二步:找出每个部门的平均薪水的等级
# 将以上 t 表和 salgrade 表连接,条件:t.avgsal between s.losal and s.hisal
select t.*,s.grade from salgrade s join (select deptno,avg(sal) as avgsal from emp group by deptno) t on t.avgsal between s.losal and s.hisal;
18.8、取得比普通员工(员工代码没有在 mgr 字段上出现过的)的最高薪水还要高的领导姓名
第一步:找出普通员工的最高薪水
select max(sal) from emp where empno not in(select distinct mgr from emp where mgr is not null);
第二步:找出高于 1600 的
select ename,sal from emp where sal > (select max(sal) from emp where empno not in(select distinct mgr from emp where mgr is not null));
+-------+---------+
| ename | sal |
+-------+---------+
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| FORD | 3000.00 |
+-------+---------+
6 rows in set (0.00 sec)
18.9、取得薪水最高的前五名员工
select ename,sal from emp order by sal desc limit 5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
18.10、取得薪水最高的第六名到十名员工
select ename, sal from emp order by sal desc limit 5,5;
+--------+---------+
| ename | sal |
+--------+---------+
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| WARD | 1250.00 |
+--------+---------+
5 rows in set (0.00 sec)
18.11、取得最后入职的 5 名员工
日期也可以降序,升序排
select ename,hiredate from emp order by hiredate desc limit 5;
+--------+------------+
| ename | hiredate |
+--------+------------+
| ADAMS | 1987-05-23 |
| SCOTT | 1987-04-19 |
| MILLER | 1982-01-23 |
| JAMES | 1981-12-03 |
| FORD | 1981-12-03 |
+--------+------------+
5 rows in set (0.00 sec)
18.12、取得每个薪水等级有多少员工
第一步:找出每个员工的薪水等级
select
e.ename,e.sal,s.grade
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
第二步:继续按照 grade 分组统计数量
select
s.grade,count(*)
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal
group by
s.grade;
+-------+----------+
| grade | count(*) |
+-------+----------+
| 1 | 3 |
| 3 | 2 |
| 2 | 3 |
| 4 | 5 |
| 5 | 1 |
+-------+----------+
5 rows in set (0.03 sec)
18.13、面试题
有3个表S(学生表),C(课程表),SC(学生选课表)
S(SNO,SNAME)代表(学号,姓名)
C(CNO,CNAME,CTEACHER)代表(课号,课名,教师)
SC(SNO,CNO,SCGRADE)代表(学号,课号,成绩)
问题:
- 找出没选过“黎明”老师的所有学生姓名。
- 列出2门以上(含2门)不及格学生姓名及平均成绩。
- 即学过1号课程又学过2号课所有学生的姓名。
请用标准SQL语言写出答案,方言也行(请说明是使用什么方言)。
18.14、列出所有员工及领导的姓名
select
a.ename '员工',b.ename '领导'
from
emp a
left join
emp b
on
a.mgr = b.empno;
18.15、列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
select
a.ename '员工', a.hiredate, b.ename '领导', c.dname
from
emp a
join
emp b
on
a.hiredate < b.hiredate and a.mgr = b.empno
join
dept c
on
a.deptno = c.deptno;
+-------+------------+-------+------------+
| 员工 | hiredate | 领导 | dname |
+-------+------------+-------+------------+
| SMITH | 1980-12-17 | FORD | RESEARCH |
| ALLEN | 1981-02-20 | BLAKE | SALES |
| WARD | 1981-02-22 | BLAKE | SALES |
| JONES | 1981-04-02 | KING | RESEARCH |
| BLAKE | 1981-05-01 | KING | SALES |
| CLARK | 1981-06-09 | KING | ACCOUNTING |
+-------+------------+-------+------------+
6 rows in set (0.00 sec)
18.16、列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门.
select
e.*, d.dname
from
emp e
right join
dept d
on
e.deptno = d.deptno;
+-------+--------+-----------+------+------------+---------+---------+--------+------------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | dname |
+-------+--------+-----------+------+------------+---------+---------+--------+------------+
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | ACCOUNTING |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | ACCOUNTING |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | ACCOUNTING |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | RESEARCH |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | RESEARCH |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | RESEARCH |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | RESEARCH |
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 | RESEARCH |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | SALES |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | SALES |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | SALES |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | SALES |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | SALES |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | SALES |
| NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | OPERATIONS |
+-------+--------+-----------+------+------------+---------+---------+--------+------------+
15 rows in set (0.00 sec)
18.17、列出至少有 5 个员工的所有部门
select
d.dname, count(*)
from
emp e
join
dept d
on
e.deptno = d.deptno
group by
d.dname
having
count(*) >= 5;
+----------+----------+
| dname | count(*) |
+----------+----------+
| RESEARCH | 5 |
| SALES | 6 |
+----------+----------+
18.18、列出薪金比 “SMITH” 多的所有员工信息
select ename, sal from emp where sal > (select sal from emp where ename = 'SMITH');
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
13 rows in set (0.00 sec)
18.19、列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数.
# 先列出姓名及其部门名称
select
e.ename, d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno
where job = 'CLERK';
# 每个部门的人数
select
deptno,count(*) as deptcount
from
emp
group by
deptno;
将上面的两表联合:
select
t1.*, t2.deptcount
from
(select
e.ename, d.dname, d.deptno
from
emp e
join
dept d
on
e.deptno = d.deptno
where
e.job = 'CLERK'
) t1
join
(select
deptno,count(*) as deptcount
from
emp
group by
deptno
) t2
on
t1.deptno = t2.deptno;
+--------+------------+--------+-----------+
| ename | dname | deptno | deptcount |
+--------+------------+--------+-----------+
| SMITH | RESEARCH | 20 | 5 |
| ADAMS | RESEARCH | 20 | 5 |
| JAMES | SALES | 30 | 6 |
| MILLER | ACCOUNTING | 10 | 3 |
+--------+------------+--------+-----------+
4 rows in set (0.00 sec)
18.20、列出最低薪金大于 1500 的各种工作及从事此工作的全部雇员人数
select job, count(*) from emp group by job having min(sal) > 1500;
+-----------+----------+
| job | count(*) |
+-----------+----------+
| MANAGER | 3 |
| ANALYST | 2 |
| PRESIDENT | 1 |
+-----------+----------+
3 rows in set (0.00 sec)
18.21、列出在部门"SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号.
select ename from emp where deptno = (select deptno from dept where dname = 'SALES');
+--------+
| ename |
+--------+
| ALLEN |
| WARD |
| MARTIN |
| BLAKE |
| TURNER |
| JAMES |
+--------+
18.22、列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,雇员的工资等级.
select
e.ename '员工',d.dname,l.ename '领导', s.grade
from
emp e
join
dept d
on
e.deptno = d.deptno
left join
emp l
on
e.mgr = l.empno
join
salgrade s
on
e.sal between s.losal and s.hisal
where
e.sal > (select avg(sal) from emp);
+-------+------------+-------+-------+
| 员工 | dname | 领导 | grade |
+-------+------------+-------+-------+
| FORD | RESEARCH | JONES | 4 |
| SCOTT | RESEARCH | JONES | 4 |
| CLARK | ACCOUNTING | KING | 4 |
| BLAKE | SALES | KING | 4 |
| JONES | RESEARCH | KING | 4 |
| KING | ACCOUNTING | NULL | 5 |
+-------+------------+-------+-------+
18.23、列出与"SCOTT"从事相同工作的所有员工及部门名称.
select
e.ename, e.job, d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno
where
e.job = (select job from emp where ename = 'scott') and e.ename <> 'scott';
+-------+---------+----------+
| ename | job | dname |
+-------+---------+----------+
| FORD | ANALYST | RESEARCH |
+-------+---------+----------+
1 row in set (0.00 sec)
18.24、列出薪金等于部门30中员工的薪金的其他员工的姓名和薪金.
select ename, sal from emp where sal in (select distinct sal from emp where deptno = 30) and deptno <> 30;
Empty set (0.00 sec)
18.25、列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金.部门名称.
select
e.ename,e.sal,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno
where
e.sal > (select max(sal) from emp where deptno = 30);
+-------+---------+------------+
| ename | sal | dname |
+-------+---------+------------+
| JONES | 2975.00 | RESEARCH |
| SCOTT | 3000.00 | RESEARCH |
| KING | 5000.00 | ACCOUNTING |
| FORD | 3000.00 | RESEARCH |
+-------+---------+------------+
4 rows in set (0.00 sec)
18.26、列出在每个部门工作的员工数量,平均工资和平均服务期限.
在 mysql 当中计算两个日期的 “年差”:TimeStampDiff(间隔类型,前一个日期,后一个日期)
间隔类型:
- SECOND 秒
- MINUTE 分钟
- HOUR 小时
- DAY 天
- WEEK 星期
- MONTH 月
- QUARTER 季度
- YEAR 年
select
d.*,count(e.ename) as '员工数量', ifnull(avg(e.sal), 0) as '平均工资',ifnull(avg(timestampdiff(YEAR, hiredate,now())), 0) as avgservicetime
from
emp e
right join
dept d
on
e.deptno = d.deptno
group by
d.deptno,d.dname,d.loc;
+--------+------------+----------+----------+-------------+----------------+
| DEPTNO | DNAME | LOC | 员工数量 | 平均工资 | avgservicetime |
+--------+------------+----------+----------+-------------+----------------+
| 10 | ACCOUNTING | NEW YORK | 3 | 2916.666667 | 39.0000 |
| 20 | RESEARCH | DALLAS | 5 | 2175.000000 | 36.8000 |
| 30 | SALES | CHICAGO | 6 | 1566.666667 | 39.3333 |
| 40 | OPERATIONS | BOSTON | 0 | 0.000000 | 0.0000 |
+--------+------------+----------+----------+-------------+----------------+
18.27、列出所有员工的姓名、部门名称和工资。
select e.ename,d.dname,e.sal from emp e join dept d on e.deptno = d.deptno;
+--------+------------+---------+
| ename | dname | sal |
+--------+------------+---------+
| SMITH | RESEARCH | 800.00 |
| ALLEN | SALES | 1600.00 |
| WARD | SALES | 1250.00 |
| JONES | RESEARCH | 2975.00 |
| MARTIN | SALES | 1250.00 |
| BLAKE | SALES | 2850.00 |
| CLARK | ACCOUNTING | 2450.00 |
| SCOTT | RESEARCH | 3000.00 |
| KING | ACCOUNTING | 5000.00 |
| TURNER | SALES | 1500.00 |
| ADAMS | RESEARCH | 1100.00 |
| JAMES | SALES | 950.00 |
| FORD | RESEARCH | 3000.00 |
| MILLER | ACCOUNTING | 1300.00 |
+--------+------------+---------+
14 rows in set (0.00 sec)
18.28、列出所有部门的详细信息和人数
select d.*,count(e.ename) '部门人数' from emp e right join dept d on e.deptno = d.deptno group by d.deptno, d.dname,d.loc;
+--------+------------+----------+----------+
| DEPTNO | DNAME | LOC | 部门人数 |
+--------+------------+----------+----------+
| 10 | ACCOUNTING | NEW YORK | 3 |
| 20 | RESEARCH | DALLAS | 5 |
| 30 | SALES | CHICAGO | 6 |
| 40 | OPERATIONS | BOSTON | 0 |
+--------+------------+----------+----------+
4 rows in set (0.00 sec)
18.29、列出各种工作的最低工资及从事此工作的雇员姓名
select
e.ename,t.*
from
emp e
join
(select
job, min(sal) as minsal
from
emp
group by
job
) t
on
e.job = t.job and e.sal = t.minsal;
+--------+-----------+---------+
| ename | job | minsal |
+--------+-----------+---------+
| SMITH | CLERK | 800.00 |
| WARD | SALESMAN | 1250.00 |
| MARTIN | SALESMAN | 1250.00 |
| CLARK | MANAGER | 2450.00 |
| SCOTT | ANALYST | 3000.00 |
| KING | PRESIDENT | 5000.00 |
| FORD | ANALYST | 3000.00 |
+--------+-----------+---------+
7 rows in set (0.00 sec)
18.30、列出各个部门的 MANAGER(领导) 的最低薪资
select
deptno,min(sal)
from
emp
where
job = 'MANAGER'
group by
deptno;
+--------+----------+
| deptno | min(sal) |
+--------+----------+
| 20 | 2975.00 |
| 30 | 2850.00 |
| 10 | 2450.00 |
+--------+----------+
3 rows in set (0.00 sec)
18.31、列出所有员工的年工资,按年薪从低到高排序
select
ename,(sal + ifnull(comm, 0)) * 12 as yearsal
from
emp
order by
yearsal asc;
+--------+----------+
| ename | yearsal |
+--------+----------+
| SMITH | 9600.00 |
| JAMES | 11400.00 |
| ADAMS | 13200.00 |
| MILLER | 15600.00 |
| TURNER | 18000.00 |
| WARD | 21000.00 |
| ALLEN | 22800.00 |
| CLARK | 29400.00 |
| MARTIN | 31800.00 |
| BLAKE | 34200.00 |
| JONES | 35700.00 |
| SCOTT | 36000.00 |
| FORD | 36000.00 |
| KING | 60000.00 |
+--------+----------+
14 rows in set (0.00 sec)
18.32、求出员工领导的薪水超过3000的员工名称与领导名称
select
a.ename '员工', b.ename '领导'
from
emp a
join
emp b
on
a.mgr = b.empno
where
b.sal > 3000;
+-------+------+
| 员工 | 领导 |
+-------+------+
| JONES | KING |
| BLAKE | KING |
| CLARK | KING |
+-------+------+
18.33、求出部门名称中,带'S'字符的部门员工的工资合计、部门人数.
select
d.*,count(e.ename), ifnull(sum(e.sal), 0) as sumsal
from
emp e
right join
dept d
on
e.deptno = d.deptno
where
d.dname like '%S%'
group by
d.deptno, d.dname, d.loc;
+--------+------------+---------+----------------+----------+
| DEPTNO | DNAME | LOC | count(e.ename) | sumsal |
+--------+------------+---------+----------------+----------+
| 20 | RESEARCH | DALLAS | 5 | 10875.00 |
| 30 | SALES | CHICAGO | 6 | 9400.00 |
| 40 | OPERATIONS | BOSTON | 0 | 0.00 |
+--------+------------+---------+----------------+----------+
3 rows in set (0.00 sec)
18.34、给任职日期超过30年的员工加薪10%
update emp set sal = sal * 1.1 where timestampdiff(year,hiredate,now()) > 30