zoukankan      html  css  js  c++  java
  • MySQL

    目录

    一、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/
    img

    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> 加一个闪烁的光标等待命令的输入, 输入 exitquit 退出登录。

    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 的

    1. 找出每个部门最高薪资,按照部门分组求每一组的最大值

      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)
      
    2. 显示最高薪资大于 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 的

    1. 找出每个部门平均薪资高于 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)
      
    2. 显示平均薪资高于 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
    ...
    

    以上关键字只能按照这个顺序来,不能颠倒。

    执行顺序

    1. from
    2. where
    3. group by
    4. having
    5. select
    6. 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语句中使用子查询

    案例:找出比最低工资高的员工姓名和工资?

    实现思路:

    1. 第一步:查询最低工资是多少

      mysql> select min(sal) from emp;
      +----------+
      | min(sal) |
      +----------+
      |   800.00 |
      +----------+
      1 row in set (0.03 sec)
      
    2. 第二步:找出大于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 |
      +--------+---------+
      
    3. 合并

      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后面的子查询,可以将子查询的查询结果当做一张临时表。

    案例:找出每个岗位的平均工资的薪资等级。

    1. 找出每个岗位的平均工资(按照岗位分组求平均值)

      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)
      
    2. 把以上的查询结果就当做一张真实存在的表 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、创建表加入约束

    在创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性。

    • 常见的约束
    1. 非空约束,not null2。
    2. 唯一约束,unique
    3. 主键约束,primary key
    4. 外键约束,foreign key
    5. 自定义检查约束,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 tableshow 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:

    1. 原子性(Atomicity)
      • 整个事务中的所有操作,必须作为一个单元全部完成(或全部取消)。
    2. 一致性(Consistency)
      • 在事务开始之前与结束之后,数据库都保持一致状态。
    3. 隔离性(Isolation)
    • 一个事务不会影响其他事务的运行。
    1. 持久性(Durability)
      • 在事务完成以后,该事务对数据库所作的更改将持久地保存在数据库之中,并不会被回滚。

    事务中存在一些概念:

    1. 事务(Transaction):一批操作(一组DML)
    2. 开启事务(Start Transaction)
    3. 回滚事务(rollback)
    4. 提交事务(commit)
    5. SET AUTOCOMMIT:禁用或启用事务的自动提交模式

    当执行DML语句是其实就是开启一个事务

    关于事务的回滚需要注意:只能回滚insert、delete和update语句,不能回滚select(回滚select没有任何意义),对于create、drop、alter这些无法回滚.

    事务只对DML有效果。

    注意:rollback,或者commit后事务就结束了。

    13.2、事务的提交与回滚演示

    1. 创建表

      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
      
    2. 查询表中的数据

      mysql> select * from user;
      Empty set (0.04 sec)
      
    3. 开启事务

    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    1. 插入数据
    insert into user (username,password) values('zhangsan','123');
    
    1. 查看数据
    mysql> select * from user;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | zhangsan | 123      |
    +----+----------+----------+
    1 row in set (0.00 sec)
    
    1. 修改数据

      update user set username='lisi' where id = 1;
      
    2. 查看数据

      mysql> select * from user;
      +----+----------+----------+
      | id | username | password |
      +----+----------+----------+
      |  1 | lisi     | 123      |
      +----+----------+----------+
      1 row in set (0.00 sec)
      
    3. 回滚事务

    rollback;
    
    1. 查看数据

      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、隔离级别一致性问题的关系

    image-2082193-20210428155422074

    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 在查询方面主要就是两种方式:

    1. 全表扫描
    2. 根据索引检索

    在 mysql 中,什么条件下,我们会考虑给字段添加索引?

    1. 数据量庞大
    2. 该字段经常出现在 where 的后面,以条件的形式存在,也就是说这个字段总是被扫描。
    3. 该字段很少的 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';
    

    image2082193-20210428155632019-158286907

    14.2.5、索引失效

    1. ename 上添加了索引,也不会走索引,因为模糊匹配中以 '%' 开头了
    select * from emp where ename like '%T';
    
    1. 使用 or 的时候会失效,如果使用 or 那么要求 or 两边的条件字段都要有索引,才会走索引,如果其中一边有一个字段没有索引,那么另一个字段上的索引也会失效。

      # 如果 ename 这个字段有索引,而 job 没有,索引就会失效
      select * from emp where ename = 'KING' or job = 'MANAGER'
      
    2. 使用复合索引的时候,没有使用左侧的列查找。

      # 给 job和sal 复合添加索引
      create index emp_job_sal_index on emp(job,sal);
      
      # 使用了索引
      select * from emp where job = 'MANAGER';
      # 没有使用索引
      select * from emp where sal = 800;
      
    3. 在 where 当中索引列参加了运算

      create index emp_sal_index on emp(sal);
      
      # 使用了索引
      select * from emp where sal = 800;
      # 没有使用索引
      select * from emp where sal + 1 = 800;
      
    4. 在 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包括:

      1. alter:修改数据库的表
      2. create:创建新的数据库或表
      3. delete:删除表数据
      4. drop:删除数据库/表
      5. index:创建/删除索引
      6. insert:添加表数据
      7. select:查询表数据
      8. update:更新表数据
      9. all:允许任何操作
      10. 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) 学生姓名 email 联系电话
    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、取得每个部门最高薪水的人员名称

    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)
      
    2. 将以上的查询结果当做一张临时表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、哪些人的薪水在部门的平均薪水之上

    1. 取得每个部门的平均薪水

      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)
      
    2. 将以上的查询的结果当做一张临时表 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、取得部门中(所有人的)平均的薪水等级

    1. 找出每个人的薪水等级

      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)
      
    2. 基于以上的结果继续按照 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、取得平均薪水最高的部门的部门编号

    第一种方案:

    1. 找出每个部门的平均薪水

      select deptno,avg(sal) as avgsal from emp group by deptno;
      +--------+-------------+
      | deptno | avgsal      |
      +--------+-------------+
      |     20 | 2175.000000 |
      |     30 | 1566.666667 |
      |     10 | 2916.666667 |
      +--------+-------------+
      
    2. 降序选第一个

      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)代表(学号,课号,成绩)

    问题:

    1. 找出没选过“黎明”老师的所有学生姓名。
    2. 列出2门以上(含2门)不及格学生姓名及平均成绩。
    3. 即学过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
    
  • 相关阅读:
    java实现转方阵
    java实现转方阵
    java实现取球游戏
    java实现取球游戏
    java实现取球游戏
    java实现取球游戏
    java实现取球游戏
    java实现蓝桥杯约瑟夫环
    java实现蓝桥杯约瑟夫环
    免费css布局和模板集合
  • 原文地址:https://www.cnblogs.com/DawnCoody/p/14714506.html
Copyright © 2011-2022 走看看