MySQL学习笔记-B站动力节点

文章目录

  • MySQL
    • Day1
      • 1.概述
      • 2.sql、DB、DBMS分别是什么?他们之间的关系?
      • 3.表
      • 4.sql语句分类
      • 5.导入数据
      • 6.sql脚本
      • 7.删除数据库命令
      • 8.查看表结构
      • 9.查看表中的数据
      • 10.mysql常用的命令
      • --------从此开始正式学习sql语句--------
      • 11.简单的查询语句(DQL)
      • 12.条件查询
      • 13.排序(升序,降序)
      • 14.单行处理函数
      • 15.分组函数(多行处理函数)
      • 16.分组查询group by和having
      • 17.总结一个完整的DQL语句(查询语句)怎么写
    • Day2
      • 1.关于查询结果的去重
      • 2.连接查询
        • 2.1.什么是连接查询?
        • 2.2.连接查询的分类
        • 2.3.笛卡尔积现象(笛卡尔乘积现象)
        • 2.4.如何避免笛卡尔积现象?
        • 2.5.内连接之等值连接
        • 2.6.内连接之非等值连接
        • 2.7.内连接之自连接
        • 2.8.外连接
        • 2.9.三张表怎么连接查询?
        • 2.10.介绍工具Navicat
      • 3.子查询
        • 3.1.概述
        • 3.2.where子句中使用子查询
        • 3.3.from后面嵌套子查询
        • 3.4.在select后面嵌套子查询
      • 4.union(可以将查询结果集相加)
      • 5.limit (重点中的重点,以后分页查询全靠它了)
      • --------DQL语句到此学完--------
      • 6.创建表
      • 7.insert语句(向表中插入一条数据)
      • 8.表的删除
      • 9.表的复制
      • 10.将查询结果插入到一张表中
      • 11.修改数据:update
      • 12.删除数据
      • 13.关于表结构的修改和以上小总结
      • 14.约束(Constraint)
        • 14.1.什么是约束?常见的约束有哪些呢?
        • 14.2.非空约束 not null
    • Day3
      • 1.约束
        • 1.1.唯一性约束(unique)
        • 1.2.主键约束
        • 1.3.外键约束
      • 2.存储引擎(了解)
        • 2.1.完整的建表语句
        • 2.2.什么是存储引擎?
        • 2.3.查看当前mysql支持的存储引擎
        • 2.4.常见的存储引擎
      • 3.事务(Transaction)
        • 3.1.什么是事务?
        • 3.2.和事务相关的语句只有:DML语句(insert delete update)
        • 3.3.假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗?
        • 3.4.事务的原理
        • 3.5.事务的特性
        • 3.6.关于事务之间的隔离性
        • 3.7.演示事务
      • 4.索引
        • 4.1.什么是索引?有什么用?
        • 4.2.怎么创建索引对象?怎么删除索引对象?
        • 4.3.什么时候考虑给字段添加索引?(满足什么条件)
        • 4.4.注意:主键和具有unique约束的字段会自动添加索引。
        • 4.5.查看sql语句的执行计划
        • 4.6.索引底层采用的数据结构是:B + Tree
        • 4.7.索引的实现原理
        • 4.8.索引的分类
        • 4.9.索引什么时候失效?
      • 5.视图(view)
        • 5.1.什么是视图?
        • 5.2.怎么创建视图?怎么删除视图?
        • 5.3.对视图进行增删改查,会影响到原表数据
        • 5.4.面向视图操作
        • 5.5.视图的作用
      • 6.DBA命令
        • 6.1.把数据库当中的数据导出
        • 6.2.把数据导入数据库中
      • 7.数据库设计三范式(重点内容,面试经常会问)
        • 7.1.什么是设计范式?
        • 7.2.三范式都是哪些?
        • 7.3.一对一怎么设计?
        • 7.4.数据库三范式总结
    • 课后习题
      • 1.取得每个部门最高薪水的人员名称
      • 2.哪些人的薪水在部门的平均薪水之上
      • 3.取得部门中(所有人的)平均的薪水等级
      • 4.不准用分组函数(Max),取得最高薪水
      • 5.取得平均薪水最高的部门的部门编号
      • 6.取得平均薪水最高的部门的部门名称
      • 7.求平均薪水的等级最低的部门的部门名称
      • 8.取得比普通员工(员工代码没有在mgr字段上出现的)的最高薪水还要高的领导人姓名
      • 9.取得薪水最高的前五名员工
      • 10.取得薪水最高的第六到第十名员工
      • 11.取得最后入职的5名员工
      • 12.取得每个薪水等级有多少员工
      • 13.面试题
      • 14.列出所有员工及领导的姓名
      • 15.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
      • 16.列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门
      • 17.列出至少有5个员工的所有部门
      • 18.列出薪金比"SMITH"多的所有员工信息
      • 19.列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数
      • 20.列出最低薪金大于1500的各种工作及从事此工作的全部雇员人数
      • 21.列出在部门"SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号
      • 22.列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,雇员的工资等级
      • 23.列出与"SCOTT"从事相同工作的所有员工及部门名称
      • 24.列出薪金等于部门30中员工的薪金的其他员工的姓名和薪金
      • 25.列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金.部门名称
      • 26.列出在每个部门工作的员工数量,平均工资和平均服务期限
      • 27.列出所有员工的姓名、部门名称和工资
      • 28.列出所有部门的详细信息和人数
      • 29.列出各种工作的最低工资及从事此工作的雇员姓名
      • 30.列出各个部门的MANAGER(领导)的最低薪金
      • 31.列出所有员工的年工资,按年薪从低到高排序
      • 32.求出员工领导的薪水超过3000的员工名称与领导名称
      • 33.求出部门名称中,带'S'字符的部门员工的工资合计、部门人数
      • 34.给任职日期超过30年的员工加薪10%

MySQL

Day1

1.概述

数据库(数据库管系统:简单的sql语句)
常见的数据库管理系统有哪些?
Oracle MySQL DB2 Sybase "MS SqlServer 支持标准sql的数据库管理系统"

如何登录MySQL?
在命令窗口输入 mysql -uroot -p密码
或者为了不让别人看见密码,输入 mysql -uroot -p 然后直接回车 再输入密码

mysql修改密码或者忘记密码该怎么做?
看文章“mysql修改密码或者忘记密码该怎么做”

2.sql、DB、DBMS分别是什么?他们之间的关系?

DB:DataBase(数据库,数据库实际上在硬盘上以文件的形式存在)
DBMS:DataBase Management System(数据库管理系统,常见的有:MySQL Oracle DB2 Sybase SqlServer)

sql:结构化程序查询语言,是一门标准通用语言。标准的sql适用于所有的数据库产品。
sql属于高级语言。只要能看懂英语单词的,写出来的sql语句,可以读懂什么意思。
sql语句在执行的时候,实际上内部也会先进行编译,然后再执行sql。
sql语句的编译由DBMS完成。
DBMS负责执行sql语句,通过执行sql语句来操作DB中的数据。

3.表

表:table 是数据库的基本组成单元,所有的数据都以表格的形式组织,因为表的可读性强。

一个表包括行和列:
	行:被称为数据/记录(data)
	列:被称为字段(column)

如下表:
学号	    姓名        年龄
------------------------------------
110			张三		20
120			李四		21

每一个字段应该包括哪些属性?
	字段名、数据类型、相关的约束。
	如第一列:
		字段名:学号
		数据类型:int
		相关的约束:学号不能超过多少。。。
	如第二列:
		字段名:姓名
		数据类型:varchar(variable character可变字符串)(即String)
		相关的约束:姓名不能为空等

4.sql语句分类

学习MySQL主要还是学习通用的SQL语句,SQL语句包括增删改查,SQL语句怎么分类呢?
DQL(数据查询语言): 查询语句,凡是select语句都是DQL。
DML(数据操作语言):对表当中的数据进行增删改,有insert delete update。
DDL(数据定义语言):对表结构的增删改,有create drop alter。
TCL(事务控制语言):commit提交事务,rollback回滚事务。
DCL(数据控制语言): grant授权、revoke撤销权限等。

DQL:Data Query Language 数据库查询语言。
	关键字:SELECT ... FROM ... WHERE。
DML:Data Manipulation Language 数据操纵语言。
	关键字:INSERT、UPDATE、DELETE。
DDL:Data Definition Language 数据库模式定义语言。
	关键字:CREATE,DROP,ALTER。
TCL:Transaction Control Language 事务控制语言。
	关键字:COMMIT、ROLLBACK、SAVEPOINT。
DCL:Data Control Language 数据控制语言。
	关键字:GRANT、REVOKE。
DDL,DML,DCL,DQL,TCL共同组成数据库的完整语言。

5.导入数据

(后期大家练习的时候使用这个演示的数据)
第一步:登录mysql数据库管理系统
	dos命令窗口:mysql -uroot -p密码
第二步:查看有哪些数据库
	show databases; (这个不是SQL语句,属于MySQL的命令。)
	+--------------------+
	| Database           |
	+--------------------+
	| information_schema |
	| mysql              |
	| performance_schema |
	| test               |
	+--------------------+
第三步:创建属于我们自己的数据库
	create database bjpowernode; (这个不是SQL语句,属于MySQL的命令。)
第四步:使用bjpowernode数据(即进入bjpowernode数据库)
	use bjpowernode; (这个不是SQL语句,属于MySQL的命令。)
第五步:查看当前使用的数据库中有哪些表?
	show tables; (这个不是SQL语句,属于MySQL的命令。)
第六步:初始化数据(将事先准备好的txt文件中的数据放入表中,即source+文件路径或者把文件拖进命令窗口会自动生成文件路径)
	mysql> source D:\course\05-MySQL\resources\bjpowernode.sql

注意:数据初始化完成之后,有三张表:
+-----------------------+
| Tables_in_bjpowernode |
+-----------------------+
| dept                  |
| emp                   |
| salgrade              |
+-----------------------+

6.sql脚本

什么是sql脚本呢?
bjpowernode.sql,这个文件以sql结尾,这样的文件被称为“sql脚本”。
当一个文件的扩展名是.sql,并且该文件中编写了大量的sql语句,我们称这样的文件为sql脚本。

注意:当sql脚本文件太大时,用记事本是打不开的。
这时可以在DOS命令窗口中,直接使用source+sql脚本文件路径,再回车就直接把数据添加进了。
source命令

在这里插入图片描述

7.删除数据库命令

drop database bjpowernode;

8.查看表结构

数据库bjpowernode 里面有三张表
+-----------------------+
| Tables_in_bjpowernode |
+-----------------------+
| dept                  |   (部门表)
| emp                   |   (员工表)
| salgrade              |   (工资等级表)
+-----------------------+

查看每张表的结构命令:desc+表的名称

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    |       |		最高薪资
+-------+---------+------+-----+---------+-------+

9.查看表中的数据

查看表中的数据命令:select * from 表名称;

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 |
+-------+--------+-----------+------+------------+---------+---------+--------+

mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+

mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+

10.mysql常用的命令

以下不是sql语句:

创建数据库:create database 数据库名称; 
查询当前使用的数据库:select  database();  
查询数据库版本可以使用 select  version();
终止一条语句:\c
退出mysql:exit

查看现有哪些数据库:show databases;
使用某个数据库:use 数据库名称;
查看当前使用哪个数据库:select database();
查看当前数据库中有哪些表:show tables;
查看其他数据库中有哪些表:show tables from 数据库名称;
查看表的结构:desc 表名称;
查看一个表的创建语句:show create table 表名称;

--------从此开始正式学习sql语句--------

11.简单的查询语句(DQL)

语法格式:
	select 字段名1,字段名2,字段名3,.... from 表名;
提示:
	1、任何一条sql语句以“;”结尾。
	2、sql语句不区分大小写。
	
查询员工的年薪?(字段可以参与数学运算。)
	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 |
	+--------+----------+
	
给查询结果的列sal*12重命名?
	select ename,sal * 12 as yearsal from emp;
	+--------+----------+
	| 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 |
	+--------+----------+

别名中有中文?
	select ename,sal * 12 as 年薪 from emp; // 错误
	select ename,sal * 12 as '年薪' from emp;
	+--------+----------+
	| ename  | 年薪     |
	+--------+----------+
	| 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 |
	+--------+----------+

注意:标准sql语句中要求字符串使用单引号括起来。虽然mysql支持双引号,尽量别用。

as关键字可以省略?
	mysql> select empno,ename,sal * 12 yearsal from emp;
	+-------+--------+----------+
	| empno | ename  | yearsal  |
	+-------+--------+----------+
	|  7369 | SMITH  |  9600.00 |
	|  7499 | ALLEN  | 19200.00 |
	|  7521 | WARD   | 15000.00 |
	|  7566 | JONES  | 35700.00 |
	|  7654 | MARTIN | 15000.00 |
	|  7698 | BLAKE  | 34200.00 |
	|  7782 | CLARK  | 29400.00 |
	|  7788 | SCOTT  | 36000.00 |
	|  7839 | KING   | 60000.00 |
	|  7844 | TURNER | 18000.00 |
	|  7876 | ADAMS  | 13200.00 |
	|  7900 | JAMES  | 11400.00 |
	|  7902 | FORD   | 36000.00 |
	|  7934 | MILLER | 15600.00 |
	+-------+--------+----------+

查询所有字段?
	select * from emp; // 实际开发中不建议使用*,效率较低。

12.条件查询

语法格式:
	select 
		字段,字段...
	from
		表名
	where
		条件;

执行顺序:先from,然后where,最后select

查询工资等于5000的员工姓名?
	select ename from emp where sal = 5000;
	+-------+
	| ename |
	+-------+
	| KING  |
	+-------+
查询SMITH的工资?
	select sal from emp where ename = 'SMITH'; //字符串使用单引号括起来。
	+--------+
	| sal    |
	+--------+
	| 800.00 |
	+--------+
找出工资高于3000的员工?
	select ename,sal from emp where sal > 3000;

	select ename,sal from emp where sal >= 3000;

	select ename,sal from emp where sal < 3000;

	select ename,sal from emp where sal <= 3000;

找出工资不等于3000的?
	方法一:
		select ename,sal from emp where sal <> 3000; //不等于3000即大于小于3000
	方法二:
		select ename,sal from emp where sal != 3000;

找出工资在1100和3000之间的员工,包括1100和3000?
	方法一:
		select ename,sal from emp where sal >= 1100 and sal <= 3000;
	方法二:
		select ename,sal from emp where sal between 1100 and 3000; 
		注意:between...and...是闭区间 [1100 ~ 3000]
	
	注意:between and在使用的时候必须左小右大。
	select ename,sal from emp where sal between 3000 and 1100; //查询不到任何数据
	
	注意:between and除了可以使用在数字方面之外,还可以使用在字符串方面。
	但此时应用在字符串方面是:左闭右开。
	select ename from emp where ename between 'A' and 'C';
	+-------+
	| ename |
	+-------+
	| ALLEN |
	| BLAKE |
	| ADAMS |
	+-------+

找出哪些人津贴为NULL?
	在数据库当中NULL不是一个值,代表什么也没有,为空。
	空不是一个值,不能用等号衡量。
	必须使用 is null或者is not null
	
	select ename,sal,comm from emp where comm is null;
	+--------+---------+------+
	| ename  | sal     | comm |
	+--------+---------+------+
	| SMITH  |  800.00 | NULL |
	| JONES  | 2975.00 | NULL |
	| BLAKE  | 2850.00 | NULL |
	| CLARK  | 2450.00 | NULL |
	| SCOTT  | 3000.00 | NULL |
	| KING   | 5000.00 | NULL |
	| ADAMS  | 1100.00 | NULL |
	| JAMES  |  950.00 | NULL |
	| FORD   | 3000.00 | NULL |
	| MILLER | 1300.00 | NULL |
	+--------+---------+------+
		
	select ename,sal,comm from emp where comm = null; //错误,没有 =null
	Empty set (0.00 sec)

找出哪些人津贴不为NULL?
	select ename,sal,comm from emp where comm is not null;
	+--------+---------+---------+
	| ename  | sal     | comm    |
	+--------+---------+---------+
	| ALLEN  | 1600.00 |  300.00 |
	| WARD   | 1250.00 |  500.00 |
	| MARTIN | 1250.00 | 1400.00 |
	| TURNER | 1500.00 |    0.00 |
	+--------+---------+---------+
	
找出哪些人没有津贴?
	select ename,sal,comm from emp where comm is null or comm = 0;
	+--------+---------+------+
	| ename  | sal     | comm |
	+--------+---------+------+
	| SMITH  |  800.00 | NULL |
	| JONES  | 2975.00 | NULL |
	| BLAKE  | 2850.00 | NULL |
	| CLARK  | 2450.00 | NULL |
	| SCOTT  | 3000.00 | NULL |
	| KING   | 5000.00 | NULL |
	| TURNER | 1500.00 | 0.00 |
	| ADAMS  | 1100.00 | NULL |
	| JAMES  |  950.00 | NULL |
	| FORD   | 3000.00 | NULL |
	| MILLER | 1300.00 | NULL |
	+--------+---------+------+
	
找出工作岗位是MANAGER和SALESMAN的员工?
	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 |
	+--------+----------+
	
	
	
and和or联合起来用:找出薪资大于1000的并且部门编号是20或30部门的员工。
	错误的:select ename,sal,deptno from emp where sal > 1000 and deptno = 20 or deptno = 30; 
	正确的:select ename,sal,deptno from emp where sal > 1000 and (deptno = 20 or deptno = 30); 
	注意:当运算符的优先级不确定的时候加小括号。
	
in等同于or,但语法不同:找出工作岗位是MANAGER和SALESMAN的员工?
	select ename,job from emp where job = 'SALESMAN' or job = 'MANAGER';
	select ename,job from emp where job in('SALESMAN', 'MANAGER');

	注意:in后面的值不是区间,是具体的值:
		select ename,job from emp where sal in(800, 5000); //工资=800的和=5000的
		+-------+-----------+
		| ename | job       |
		+-------+-----------+
		| SMITH | CLERK     |
		| KING  | PRESIDENT |
		+-------+-----------+
	
	not in: 不在这几个值当中。
		select ename,job from emp where sal not in(800, 5000);
		+--------+----------+
		| ename  | job      |
		+--------+----------+
		| ALLEN  | SALESMAN |
		| WARD   | SALESMAN |
		| JONES  | MANAGER  |
		| MARTIN | SALESMAN |
		| BLAKE  | MANAGER  |
		| CLARK  | MANAGER  |
		| SCOTT  | ANALYST  |
		| TURNER | SALESMAN |
		| ADAMS  | CLERK    |
		| JAMES  | CLERK    |
		| FORD   | ANALYST  |
		| MILLER | CLERK    |
		+--------+----------+
	


模糊查询like(像):
	注意:在模糊查询当中,必须掌握两个特殊的符号,一个是%,一个是_
		  %代表任意多个字符,_代表任意1个字符。
		  
	找出名字当中含有O的?	
		select ename from emp where ename like '%O%';
		+-------+
		| ename |
		+-------+
		| JONES |
		| SCOTT |
		| FORD  |
		+-------+
		
	找出名字中第二个字母是A的?
		select ename from emp where ename like '_A%';
		+--------+
		| ename  |
		+--------+
		| WARD   |
		| MARTIN |
		| JAMES  |
		+--------+
		
	找出名字中有下划线的?
		首先创建一个新表t_user:
		+------+----------+
		| id   | name     |
		+------+----------+
		|    1 | zhangsan |
		|    2 | lisi     |
		|    3 | WANG_WU  |
		+------+----------+
		
		然后查找:
		select name from t_user where name like '%_%'; //错误,_代表一个字符
		+----------+
		| name     |
		+----------+
		| zhangsan |
		| lisi     |
		| WANG_WU  |
		+----------+
		
		select name from t_user where name like '%\_%';//正确,加一个转义字符\
		+---------+
		| name    |
		+---------+
		| WANG_WU |
		+---------+

	找出名字中最后一个字母是T的?
		select ename from emp where ename like '%T';
		+-------+
		| ename |
		+-------+
		| SCOTT | 
		+-------+

13.排序(升序,降序)

按照工资升序,找出员工名和薪资?
语法:
	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 |
| FORD   | 3000.00 |
| SCOTT  | 3000.00 |
| KING   | 5000.00 |
+--------+---------+

注意:默认是升序。怎么指定升序或者降序呢?asc表示升序,desc表示降序。
	select ename,sal from emp order by sal; // 升序
	select ename,sal from emp order by sal asc; // 升序
	select ename,sal from emp order by sal desc; // 降序。

按照工资的降序排列:
	select ename,sal from emp order by sal desc;
当工资相同的时候再按照名字的升序排列:
	select ename,sal from emp order by sal desc,ename asc;
注意:越靠前的字段越能起到主导作用。只有当前面的字段无法完成排序的时候,才会启用后面的字段。

注意:select * from emp order by 6;
//根据表的第6列排序,但是如果原表的第6列内容变了,每次排序都不一样,所以最好不要这样。
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |    NULL |     20 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+

找出工作岗位是SALESMAN的员工,并且要求按照薪资的降序排列。
	select 
		ename,job,sal
	from
		emp
	where 
		job = 'SALESMAN'
	order by
		sal desc;
+--------+----------+---------+
| ename  | job      | sal     |
+--------+----------+---------+
| ALLEN  | SALESMAN | 1600.00 |
| TURNER | SALESMAN | 1500.00 | 
| WARD   | SALESMAN | 1250.00 |
| MARTIN | SALESMAN | 1250.00 |
+--------+----------+---------+

select 
	字段						3
from
	表名						1
where
	条件						2
order by
	....						4

order by是最后执行的。

14.单行处理函数

什么是单行处理函数?
	输入一行,输出一行(对表中每一行的数据进行处理)
	
计算每个员工的年薪?
	select ename,(sal+comm)*12 as yearsal from emp; //错误
	重点:所有数据库都是这样规定的,只要有NULL参与的运算结果一定是NULL。
	sal不是NULL,而comm是NULL,则结果为NULL,所以上述错误。
	
	正确:使用ifnull函数:
	select ename,(sal+ifnull(comm,0))*12 as yearsal from emp;

单行处理函数:ifnull(xxx,xxx) (空处理函数)对可能为NULL的数据进行预处理
	ifnull(可能为NULL的字段名,若为空则被当做什么处理)
	select ename,ifnull(comm,0) as comm from emp;
	+--------+---------+
	| ename  | comm    |
	+--------+---------+
	| SMITH  |    0.00 |
	| ALLEN  |  300.00 |
	| WARD   |  500.00 |
	| JONES  |    0.00 |
	| MARTIN | 1400.00 |
	| BLAKE  |    0.00 |
	| CLARK  |    0.00 |
	| SCOTT  |    0.00 |
	| KING   |    0.00 |
	| TURNER |    0.00 |
	| ADAMS  |    0.00 |
	| JAMES  |    0.00 |
	| FORD   |    0.00 |
	| MILLER |    0.00 |
	+--------+---------+

15.分组函数(多行处理函数)

count 计数
sum 求和
avg 平均值
max 最大值
min 最小值
记住:所有的分组函数都是对“某一组”数据进行操作的。

找出工资总和?
	select sum(sal) from emp;
	+----------+
	| sum(sal) |
	+----------+
	| 29025.00 |
	+----------+
	
找出最高工资?
	select max(sal) from emp;
	+----------+
	| max(sal) |
	+----------+
	|  5000.00 |
	+----------+
	
找出最低工资?
	select min(sal) from emp;
	+----------+
	| min(sal) |
	+----------+
	|   800.00 |
	+----------+
	
找出平均工资?
	select avg(sal) from emp;
	+-------------+
	| avg(sal)    |
	+-------------+
	| 2073.214286 |
	+-------------+
	
找出总人数?
	select count(*) from emp;
	或者:select count(ename) from emp;
	+--------------+
	| count(ename) |
	+--------------+
	|           14 |
	+--------------+

注意:分组函数一共只有5个。
分组函数还有另一个名字:多行处理函数。
多行处理函数的特点:输入多行,最终输出的结果是1行。(表中数据只有14行,最后输出1行)

注意:分组函数自动忽略NULL。
	select count(comm) from emp;
	+-------------+
	| count(comm) |
	+-------------+
	|           4 |
	+-------------+

	select sum(comm) from emp;
	+-----------+
	| sum(comm) |
	+-----------+
	|   2200.00 |
	+-----------+
	
	因此,不需要额外添加这个过滤条件。sum函数自动忽略NULL:
		select sum(comm) from emp where comm is not null; 



count(*)和count(具体的某个字段),他们有什么区别?
	count(*):不是统计某个字段中数据的个数,而是统计总记录条数。(和某个字段无关)
	+----------+
	| count(*) |
	+----------+
	|       14 |
	+----------+
	
	count(comm): 表示统计comm字段中不为NULL的数据总数量。
	+-------------+
	| count(comm) |
	+-------------+
	|           4 |
	+-------------+



分组函数也能组合起来用:
	select count(*),sum(sal),avg(sal),max(sal),min(sal) from emp;

	+----------+----------+-------------+----------+----------+
	| count(*) | sum(sal) | avg(sal)    | max(sal) | min(sal) |
	+----------+----------+-------------+----------+----------+
	|       14 | 29025.00 | 2073.214286 |  5000.00 |   800.00 |
	+----------+----------+-------------+----------+----------+


//看完分组查询再看下面这个问题。
找出工资高于平均工资的员工?
	select avg(sal) from emp; // 平均工资
	+-------------+
	| avg(sal)    |
	+-------------+
	| 2073.214286 |
	+-------------+

	select ename,sal from emp where sal > avg(sal); //ERROR 1111 (HY000): Invalid use of group function
	思考以上的错误信息:无效的使用了分组函数?(分组=group)
	原因:SQL语句当中有一个语法规则,分组函数不可直接使用在where子句当中。
	怎么解释?
		因为group by是在where执行之后才会执行的。
		先分组group by,才能使用分组函数。先where后group by。
			
			select		5
				..			
			from			1
				..
			where			2
				..
			group by		3
				..
			having		4
				..
			order by		6
				..

找出工资高于平均工资的员工?
	第一步:找出平均工资
		select avg(sal) from emp;
		+-------------+
		| avg(sal)    |
		+-------------+
		| 2073.214286 |
		+-------------+
	第二步:找出高于平均工资的员工
		select ename,sal from emp where sal > 2073.214286;
		+-------+---------+
		| ename | sal     |
		+-------+---------+
		| JONES | 2975.00 |
		| BLAKE | 2850.00 |
		| CLARK | 2450.00 |
		| SCOTT | 3000.00 |
		| KING  | 5000.00 |
		| FORD  | 3000.00 |
		+-------+---------+

	把上面两步并为一步:select ename,sal from emp where sal > (select avg(sal) from emp);
	select语句中嵌套select语句,叫做子查询,后面会学。

16.分组查询group by和having

group by:按照某个字段或者某些字段进行分组。
having:having是对分组之后的数据进行再次过滤。

案例:找出每个工作岗位的最高薪资。
select max(sal) from emp group by job;//先按照job分组,再找每组的最大薪资
select max(sal),job from emp group by job;

+----------+-----------+
| max(sal) | job       |
+----------+-----------+
|  3000.00 | ANALYST   |
|  1300.00 | CLERK     |
|  2975.00 | MANAGER   |
|  5000.00 | PRESIDENT |
|  1600.00 | SALESMAN  |
+----------+-----------+


注意:分组函数一般都会和group by联合使用,这也是为什么它被称为分组函数的原因。
并且任何一个分组函数(count sum avg max min)都是在group by语句执行结束之后才会执行的。
当一条sql语句没有group by的话,整张表的数据会自成一组。


这条语句对吗:select ename,max(sal),job from emp group by job;
以上在mysql当中,查询结果是有的,但是结果没有意义。
在Oracle数据库当中会报错。语法错误。因为Oracle的语法规则比MySQL语法规则严谨。

所以记住一个规则:
当一条语句中有group by的话,select后面只能跟分组函数和按照该字段分组的字段。
	select max(sal),job from emp group by job;//正确
	select ename,max(sal),job from emp group by job;//并没有按照ename分组,所以不能写ename


每个工作岗位的平均薪资?
	select job,avg(sal) from emp group by job;
	+-----------+-------------+
	| job       | avg(sal)    |
	+-----------+-------------+
	| ANALYST   | 3000.000000 |
	| CLERK     | 1037.500000 |
	| MANAGER   | 2758.333333 |
	| PRESIDENT | 5000.000000 |
	| SALESMAN  | 1400.000000 |
	+-----------+-------------+



多个字段能不能联合起来一块分组?能
案例:找出每个部门不同工作岗位的最高薪资。

原表:select deptno,job,sal from emp order by deptno;
+--------+-----------+---------+
| deptno | job       | sal     |
+--------+-----------+---------+
|     10 | MANAGER   | 2450.00 |
|     10 | PRESIDENT | 5000.00 |
|     10 | CLERK     | 1300.00 |

|     20 | CLERK     |  800.00 |
|     20 | MANAGER   | 2975.00 |
|     20 | ANALYST   | 3000.00 |
|     20 | CLERK     | 1100.00 |
|     20 | ANALYST   | 3000.00 |

|     30 | SALESMAN  | 1600.00 |
|     30 | SALESMAN  | 1250.00 |
|     30 | SALESMAN  | 1250.00 |
|     30 | MANAGER   | 2850.00 |
|     30 | SALESMAN  | 1500.00 |
|     30 | CLERK     |  950.00 |
+--------+-----------+---------+

案例:找出每个部门不同工作岗位的最高薪资。
	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 |
+--------+-----------+----------+



找出每个部门的最高薪资,要求显示薪资大于2900的数据。

	第一步:找出每个部门的最高薪资
	select max(sal),deptno from emp group by deptno;
	+----------+--------+
	| max(sal) | deptno |
	+----------+--------+
	|  5000.00 |     10 |
	|  3000.00 |     20 |
	|  2850.00 |     30 |
	+----------+--------+

	第二步:找出薪资大于2900
	//这种方式效率低:
	select max(sal),deptno from emp group by deptno having max(sal) > 2900; 
	+----------+--------+
	| max(sal) | deptno |
	+----------+--------+
	|  5000.00 |     10 |
	|  3000.00 |     20 |
	+----------+--------+
	
	//效率较高,建议能够使用where过滤的尽量使用where:
	select max(sal),deptno from emp where sal > 2900 group by deptno;  
	+----------+--------+
	| max(sal) | deptno |
	+----------+--------+
	|  5000.00 |     10 |
	|  3000.00 |     20 |
	+----------+--------+



找出每个部门的平均薪资,要求显示薪资大于2000的数据。

第一步:找出每个部门的平均薪资
select deptno,avg(sal) from emp group by deptno;
+--------+-------------+
| deptno | avg(sal)    |
+--------+-------------+
|     10 | 2916.666667 |
|     20 | 2175.000000 |
|     30 | 1566.666667 |
+--------+-------------+

第二步:要求显示薪资大于2000的数据
select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000;	
+--------+-------------+
| deptno | avg(sal)    |
+--------+-------------+
|     10 | 2916.666667 |
|     20 | 2175.000000 |
+--------+-------------+

where后面不能使用分组函数:
	select deptno,avg(sal) from emp where avg(sal) > 2000 group by deptno;//错误了。
	这种情况只能使用having过滤。

17.总结一个完整的DQL语句(查询语句)怎么写

书写顺序  执行顺序
select		5
	..
from		1	
	..
where		2
	..
group by	3
	..
having		4
	..
order by	6
	..

from+表名称  从哪个表中查询
where+条件   条件查询 分组函数不可直接使用在where子句当中(因为使用分组函数要先分组group by)
group by+字段名  按照哪个字段进行分组
having+条件  分组之后再进行过滤(条件查询)能用where就用where,where不行再用having
			 having不能单独使用,只能和group by一起使用
select+要显示的内容
order by+字段名+asc升序/desc降序  按照哪个字段排序(默认升序)

分组函数(count sum avg max min)都是在group by语句执行结束之后才会执行的。
分组函数一般都会和group by联合使用,这也是为什么它被称为分组函数的原因。
当一条sql语句没有group by的话,整张表的数据会自成一组。

Day2

1.关于查询结果的去重

mysql> select distinct job from emp; // distinct关键字去除重复记录。
+-----------+
| job       |
+-----------+
| CLERK     |
| SALESMAN  |
| MANAGER   |
| ANALYST   |
| PRESIDENT |
+-----------+	

mysql> select ename,distinct job from emp;
以上的sql语句是错误的。因为ename有14条,而distinct job只有5条。
注意:distinct只能出现在所有字段的最前面。

注意:distinct出现在所有字段的最前方,代表所有字段联合起来去除重复记录。
原表:select deptno,job from emp order by deptno;
+--------+-----------+
| deptno | job       |
+--------+-----------+
|     10 | MANAGER   |
|     10 | PRESIDENT |
|     10 | CLERK     |
|     20 | CLERK     |
|     20 | MANAGER   |
|     20 | ANALYST   |
|     20 | CLERK     |
|     20 | ANALYST   |
|     30 | SALESMAN  |
|     30 | SALESMAN  |
|     30 | SALESMAN  |
|     30 | MANAGER   |
|     30 | SALESMAN  |
|     30 | CLERK     |
+--------+-----------+

mysql> select distinct deptno,job from emp;
+--------+-----------+
| deptno | job       |
+--------+-----------+
|     20 | CLERK     |
|     30 | SALESMAN  |
|     20 | MANAGER   |
|     30 | MANAGER   |
|     10 | MANAGER   |
|     20 | ANALYST   |
|     10 | PRESIDENT |
|     30 | CLERK     |
|     10 | CLERK     |
+--------+-----------+


案例:统计岗位的数量?
select count(distinct job) from emp;

+---------------------+
| count(distinct job) |
+---------------------+
|                   5 |
+---------------------+

2.连接查询

2.1.什么是连接查询?
在实际开发中,大部分的情况下都不是从单表中查询数据,一般都是多张表联合查询取出最终的结果。

在实际开发中,一般一个业务都会对应多张表,比如:学生和班级,起码两张表。
	stuno		stuname			classno		classname
	-----------------------------------------------------------------------------------
	1			zs					1		北京大兴区亦庄经济技术开发区第二中学高三1班
	2			ls					1		北京大兴区亦庄经济技术开发区第二中学高三1班
	...
	如果学生和班级信息存储到一张表中,结果就像上面一样,数据会存在大量的重复,导致数据的冗余。
2.2.连接查询的分类
根据语法出现的年代来划分的话,包括:
	SQL92(一些老的DBA可能还在使用这种语法。DBA:DataBase Administrator,数据库管理员)
	SQL99(比较新的语法)

根据表的连接方式来划分,包括:
	内连接:
		等值连接
		非等值连接
		自连接
	外连接:
		左外连接(左连接)
		右外连接(右连接)
	全连接(这个不讲,很少用!)
2.3.笛卡尔积现象(笛卡尔乘积现象)
在表的连接查询方面有一种现象被称为:笛卡尔积现象(笛卡尔乘积现象)

案例:找出每一个员工的部门名称,要求显示员工名和部门名。
emp表中只有员工名和部门编号,部门名在dept表中。

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 |
+-------+--------+-----------+------+------------+---------+---------+--------+

DEPT表
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+

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      |
| WARD   | RESEARCH   |
| WARD   | ACCOUNTING |
| JONES  | OPERATIONS |
| JONES  | SALES      |
| JONES  | RESEARCH   |
| JONES  | ACCOUNTING |
| MARTIN | OPERATIONS |
| MARTIN | SALES      |
| MARTIN | RESEARCH   |
| MARTIN | ACCOUNTING |
| BLAKE  | OPERATIONS |
| BLAKE  | SALES      |
| BLAKE  | RESEARCH   |
| BLAKE  | ACCOUNTING |
| CLARK  | OPERATIONS |
| CLARK  | SALES      |
| CLARK  | RESEARCH   |
| CLARK  | ACCOUNTING |
| SCOTT  | OPERATIONS |
| SCOTT  | SALES      |
| SCOTT  | RESEARCH   |
| SCOTT  | ACCOUNTING |
| KING   | OPERATIONS |
| KING   | SALES      |
| KING   | RESEARCH   |
| KING   | ACCOUNTING |
| TURNER | OPERATIONS |
| TURNER | SALES      |
| TURNER | RESEARCH   |
| TURNER | ACCOUNTING |
| ADAMS  | OPERATIONS |
| ADAMS  | SALES      |
| ADAMS  | RESEARCH   |
| ADAMS  | ACCOUNTING |
| JAMES  | OPERATIONS |
| JAMES  | SALES      |
| JAMES  | RESEARCH   |
| JAMES  | ACCOUNTING |
| FORD   | OPERATIONS |
| FORD   | SALES      |
| FORD   | RESEARCH   |
| FORD   | ACCOUNTING |
| MILLER | OPERATIONS |
| MILLER | SALES      |
| MILLER | RESEARCH   |
| MILLER | ACCOUNTING |
+--------+------------+
56 rows in set (0.00 sec)

连接查询原理:将第一张表的每一条数据与第二张表的每一条数据匹配。

笛卡尔积现象:当两张表进行连接查询的时候,没有任何条件进行限制,最终的查询结果条数是两张表记录条数的乘积。

关于表的别名:
	select e.ename,d.dname from emp e,dept d;
	表的别名有什么好处?
		第一:执行效率高。
		第二:可读性好。
		
		两张表中可能会有相同的字段名,所以要给表起别名。
		从此开始,开始给表写别名。
		写法:先起别名from emp e,dept d;然后再e.ename,d.dname
2.4.如何避免笛卡尔积现象?
如何避免笛卡尔积现象:加条件进行过滤。

思考:避免了笛卡尔积现象,会减少记录的匹配次数吗?
	不会,次数还是56次。只不过显示的是有效记录。不会提高连接查询效率。

案例:找出每一个员工的部门名称,要求显示员工名和部门名。
	select	
		e.ename,d.dname
	from
		emp e , dept d
	where
		e.deptno = d.deptno; //SQL92,以后不用。
		
+--------+------------+
| 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)
2.5.内连接之等值连接
内连接和外连接的区别在内外连接讲完之后再讲。

内连接之等值连接:最大特点是:条件是等量关系。

案例:查询每个员工的部门名称,要求显示员工名和部门名。

SQL92:(太老,不用了)
	select 
		e.ename,d.dname
	from
		emp e, dept d
	where
		e.deptno = d.deptno;

SQL99:(常用的)
	select 
		e.ename,d.dname
	from
		emp e
	join
		dept d
	on
		e.deptno = d.deptno; //不同表之间的连接条件是等号,所以叫等值连接

SQL99语法结构更清晰一些:表的连接条件和后来的where条件分离了。

语法:
	...
		A表
(inner)join
		B表
	on
		表连接条件
	where
		...


// inner可以省略的,带着inner目的是可读性好一些。
select 
	e.ename,d.dname
from
	emp e
inner join
	dept d
on
	e.deptno = d.deptno;

+--------+------------+
| ename  | dname      |
+--------+------------+
| CLARK  | ACCOUNTING |
| KING   | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH  | RESEARCH   |
| JONES  | RESEARCH   |
| SCOTT  | RESEARCH   |
| ADAMS  | RESEARCH   |
| FORD   | RESEARCH   |
| ALLEN  | SALES      |
| WARD   | SALES      |
| MARTIN | SALES      |
| BLAKE  | SALES      |
| TURNER | SALES      |
| JAMES  | SALES      |
+--------+------------+
2.6.内连接之非等值连接
内连接之非等值连接:最大的特点是:连接条件中的关系是非等量关系。

案例:找出每个员工的工资等级,要求显示员工名、工资、工资等级。
员工名和工资在表emp中,工资等级在表salgrade中

EMP表
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 |
+-------+--------+-----------+------+------------+---------+---------+--------+

SALGRADE表
mysql> select * from salgrade; 
+-------+-------+-------+ 
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+

select 
	e.ename,e.sal,s.grade
from
	emp e
inner join   // inner可以省略
	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 |
+--------+---------+-------+
2.7.内连接之自连接
自连接:最大的特点是:一张表看做两张表。自己连接自己。

案例:找出每个员工的上级领导,要求显示员工名和对应的领导名。
员工名和领导名都在表emp中。
将一个表看作两个表:emp a和emp b

mysql> select empno,ename,mgr from emp;
emp a 员工表
+-------+--------+------+
| 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 |
+-------+--------+------+
emp b 领导表
+-------+--------+
| empno | ename  |
+-------+--------+
|  7566 | JONES  |
|  7698 | BLAKE  |
|  7782 | CLARK  |
|  7788 | SCOTT  |
|  7839 | KING   |
|  7902 | FORD   |
+-------+--------+

员工的领导编号 = 领导的员工编号

select 
	a.ename as '员工名',b.ename as '领导名'
from
	emp a
inner join
	emp b
on
	a.mgr = b.empno;

+--------+--------+
| 员工名 | 领导名 |
+--------+--------+
| 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  |
+--------+--------+
2.8.外连接
什么是外连接,和内连接有什么区别?

内连接:
	假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接。
	AB两张表没有主副之分,两张表是平等的。
	第一张表的某条数据与第二张表匹配不上,这条数据就会被舍去。

外连接:
	假设A和B表进行连接,使用外连接的话,AB两张表中有一张表是主表,一张表是副表,主要查询主表中
	的数据,捎带着查询副表,当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。

外连接的分类?
	左外连接(左连接):表示左边的这张表是主表。
	右外连接(右连接):表示右边的这张表是主表。

	任何一个左连接都有右连接的写法,任何一个右连接也会有对应的左连接的写法。

案例:找出每个员工的上级领导?(所有员工必须全部查询出来。)

emp a 员工表
+-------+--------+------+
| 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 |
+-------+--------+------+

emp b 领导表
+-------+--------+
| empno | ename  |
+-------+--------+
|  7566 | JONES  |
|  7698 | BLAKE  |
|  7782 | CLARK  |
|  7788 | SCOTT  |
|  7839 | KING   |
|  7902 | FORD   |
+-------+--------+


内连接:
select 
	a.ename '员工', b.ename '领导'
from
	emp a
join
	emp b
on
	a.mgr = b.empno;
	
//king这条数据没有领导被舍去了
+--------+--------+
| 员工   | 领导   |
+--------+--------+
| 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)


外连接:(左外连接/左连接)
select 
	a.ename '员工', b.ename '领导'
from
	emp a
left (outer) join   // outer是可以省略的。
	emp b
on
	a.mgr = b.empno;

//king这条数据匹配不上但未被舍去
+--------+--------+
| 员工   | 领导   |
+--------+--------+
| SMITH  | FORD   |
| ALLEN  | BLAKE  |
| WARD   | BLAKE  |
| JONES  | KING   |
| MARTIN | BLAKE  |
| BLAKE  | KING   |
| CLARK  | KING   |
| SCOTT  | JONES  |
| KING   | NULL   |
| TURNER | BLAKE  |
| ADAMS  | SCOTT  |
| JAMES  | BLAKE  |
| FORD   | JONES  |
| MILLER | CLARK  |
+--------+--------+
14 rows in set (0.00 sec)


//上述左连接写成右连接
外连接:(右外连接/右连接)
select 
	a.ename '员工', b.ename '领导'
from
	emp b
right (outer) join   // outer是可以省略的。
	emp a
on
	a.mgr = b.empno;


注意:inner和outer都可以省略,因为不是根据inner和outer来判断是否为内连接还是外连接,
而是根据有无left,right;有left或right表示是外连接,没有则是内连接。

以后外连接使用居多(不能让无法匹配的数据丢失)

外连接最重要的特点是:主表的数据无条件的全部查询出来。



案例:找出哪个部门没有员工?
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 |
+-------+--------+-----------+------+------------+---------+---------+--------+
DEPT
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+

select 
	d.*
from
	emp e
right join
	dept d
on
	e.deptno = d.deptno
where
	e.empno is null;

+--------+------------+--------+
| DEPTNO | DNAME      | LOC    |
+--------+------------+--------+
|     40 | OPERATIONS | BOSTON |
+--------+------------+--------+
2.9.三张表怎么连接查询?
案例:找出每一个员工的部门名称以及工资等级。
EMP e
+-------+--------+---------+--------+
| empno | ename  | sal     | deptno |
+-------+--------+---------+--------+
|  7369 | SMITH  |  800.00 |     20 |
|  7499 | ALLEN  | 1600.00 |     30 |
|  7521 | WARD   | 1250.00 |     30 |
|  7566 | JONES  | 2975.00 |     20 |
|  7654 | MARTIN | 1250.00 |     30 |
|  7698 | BLAKE  | 2850.00 |     30 |
|  7782 | CLARK  | 2450.00 |     10 |
|  7788 | SCOTT  | 3000.00 |     20 |
|  7839 | KING   | 5000.00 |     10 |
|  7844 | TURNER | 1500.00 |     30 |
|  7876 | ADAMS  | 1100.00 |     20 |
|  7900 | JAMES  |  950.00 |     30 |
|  7902 | FORD   | 3000.00 |     20 |
|  7934 | MILLER | 1300.00 |     10 |
+-------+--------+---------+--------+
DEPT d
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
SALGRADE s
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+

注意,解释一下:
	....
		A
	join
		B
	join
		C
	on
	...
	
	或者
	
	....
		A
	join
		B
	on
	...
	join
		C
	on
	...
	
表示:A表和B表先进行表连接,连接之后A表继续和C表进行连接。
或者A和B连接的结果再和C连接。

select 
	e.ename,d.dname,s.grade
from
	emp e
join
	dept d
on
	e.deptno = d.deptno
join
	salgrade s
on
	e.sal between s.losal and s.hisal;

+--------+------------+-------+
| ename  | dname      | grade |
+--------+------------+-------+
| SMITH  | RESEARCH   |     1 |
| ALLEN  | SALES      |     3 |
| WARD   | SALES      |     2 |
| JONES  | RESEARCH   |     4 |
| MARTIN | SALES      |     2 |
| BLAKE  | SALES      |     4 |
| CLARK  | ACCOUNTING |     4 |
| SCOTT  | RESEARCH   |     4 |
| KING   | ACCOUNTING |     5 |
| TURNER | SALES      |     3 |
| ADAMS  | RESEARCH   |     1 |
| JAMES  | SALES      |     1 |
| FORD   | RESEARCH   |     4 |
| MILLER | ACCOUNTING |     2 |
+--------+------------+-------+



案例:找出每一个员工的部门名称、工资等级、以及上级领导。
	select 
		e.ename '员工',d.dname,s.grade,e1.ename '领导'
	from
		emp e
	join
		dept d
	on
		e.deptno = d.deptno
	join
		salgrade s
	on
		e.sal between s.losal and s.hisal
	left join   //这里用外连接,否则用内连接king数据会被删除(king的领导为NULL)
		emp e1
	on
		e.mgr = e1.empno;
		
注意:什么时候用外连接(注意NULL情况)

+--------+------------+-------+-------+
| 员工   | dname      | grade | 领导    |
+--------+------------+-------+-------+
| SMITH  | RESEARCH   |     1 | FORD  |
| ALLEN  | SALES      |     3 | BLAKE |
| WARD   | SALES      |     2 | BLAKE |
| JONES  | RESEARCH   |     4 | KING  |
| MARTIN | SALES      |     2 | BLAKE |
| BLAKE  | SALES      |     4 | KING  |
| CLARK  | ACCOUNTING |     4 | KING  |
| SCOTT  | RESEARCH   |     4 | JONES |
| KING   | ACCOUNTING |     5 | NULL  |
| TURNER | SALES      |     3 | BLAKE |
| ADAMS  | RESEARCH   |     1 | SCOTT |
| JAMES  | SALES      |     1 | BLAKE |
| FORD   | RESEARCH   |     4 | JONES |
| MILLER | ACCOUNTING |     2 | CLARK |
+--------+------------+-------+-------+
2.10.介绍工具Navicat
一直都是在DOS命令窗口写,使用这个工具就可以不使用DOS了
并且会很简便,甚至不需要写sql语句。
但是先不要用,先学习sql怎么写。

3.子查询

3.1.概述
什么是子查询?子查询都可以出现在哪里?
select语句当中嵌套select语句,被嵌套的select语句是子查询。
子查询可以出现在哪里?
	select
		..(select).
	from
		..(select).
	where
		..(select).
3.2.where子句中使用子查询
案例:找出高于平均薪资的员工信息。
select * from emp where sal > avg(sal); //错误的写法,where后面不能直接使用分组函数。

第一步:找出平均薪资
	select avg(sal) from emp;
	+-------------+
	| avg(sal)    |
	+-------------+
	| 2073.214286 |
	+-------------+
第二步:where过滤
	select * from emp where sal > 2073.214286;
	+-------+-------+-----------+------+------------+---------+------+--------+
	| EMPNO | ENAME | JOB       | MGR  | HIREDATE   | SAL     | COMM | DEPTNO |
	+-------+-------+-----------+------+------------+---------+------+--------+
	|  7566 | JONES | MANAGER   | 7839 | 1981-04-02 | 2975.00 | NULL |     20 |
	|  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 |
	|  7902 | FORD  | ANALYST   | 7566 | 1981-12-03 | 3000.00 | NULL |     20 |
	+-------+-------+-----------+------+------------+---------+------+--------+
第一步和第二步合并:
	select * from emp where sal > (select avg(sal) from emp);
3.3.from后面嵌套子查询
案例:找出每个部门平均薪水的等级。
第一步:找出每个部门平均薪水(按照部门编号分组,求sal的平均值)
select deptno,avg(sal) as avgsal from emp group by deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     10 | 2916.666667 |
|     20 | 2175.000000 |
|     30 | 1566.666667 |
+--------+-------------+
第二步:将以上的查询结果当做临时表t,让t表和salgrade s表连接,条件是:t.avgsal between s.losal and s.hisal

两步合一步:
select 
	t.*,s.grade
from
	(select deptno,avg(sal) as avgsal from emp group by deptno) t
join
	salgrade s
on
	t.avgsal between s.losal and s.hisal;

+--------+-------------+-------+
| deptno | avgsal      | grade |
+--------+-------------+-------+
|     30 | 1566.666667 |     3 |
|     10 | 2916.666667 |     4 |
|     20 | 2175.000000 |     4 |
+--------+-------------+-------+



案例:找出每个部门平均的薪水等级。
第一步:找出每个员工的薪水等级。
select e.ename,e.sal,e.deptno,s.grade from emp e join salgrade s on e.sal between s.losal and s.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 |
+--------+---------+--------+-------+
第二步:基于以上结果,继续按照deptno分组,求grade平均值。//不用把上表当成临时表
from把两表连接成一表,然后按照e.deptno分组,然后显示编号和平均值
select 
	e.deptno,avg(s.grade)
from 
	emp e 
join 
	salgrade s 
on 
	e.sal between s.losal and s.hisal
group by
	e.deptno;

+--------+--------------+
| deptno | avg(s.grade) |
+--------+--------------+
|     10 |       3.6667 |
|     20 |       2.8000 |
|     30 |       2.5000 |
+--------+--------------+


可以把第一步得到的表作为临时表继续按照deptno分组,求grade平均值,但没必要。
select 
	t.deptno,avg(t.grade)
from 
	(select e.deptno,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal) t 
group by 
	t.deptno;
+--------+--------------+
| deptno | avg(t.grade) |
+--------+--------------+
|     20 |       2.8000 |
|     30 |       2.5000 |
|     10 |       3.6667 |
+--------+--------------+
3.4.在select后面嵌套子查询
案例:找出每个员工所在的部门名称,要求显示员工名和部门名。

select 
	e.ename,d.dname
from
	emp e
join
	dept d
on
	e.deptno = d.deptno;


select 
	e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname 
from 
	emp e;

+--------+------------+
| 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 |
+--------+------------+

4.union(可以将查询结果集相加)

案例:找出工作岗位是SALESMAN和MANAGER的员工?
第一种:select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
第二种:select ename,job from emp where job in('MANAGER','SALESMAN');
+--------+----------+
| ename  | job      |
+--------+----------+
| ALLEN  | SALESMAN |
| WARD   | SALESMAN |
| JONES  | MANAGER  |
| MARTIN | SALESMAN |
| BLAKE  | MANAGER  |
| CLARK  | MANAGER  |
| TURNER | SALESMAN |
+--------+----------+

第三种:union
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 |
+--------+----------+


两张不相干的表中的数据拼接在一起显示?
select ename from emp
union
select dname from dept;

+------------+
| ename      |
+------------+
| SMITH      |
| ALLEN      |
| WARD       |
| JONES      |
| MARTIN     |
| BLAKE      |
| CLARK      |
| SCOTT      |
| KING       |
| TURNER     |
| ADAMS      |
| JAMES      |
| FORD       |
| MILLER     |
| ACCOUNTING | 从此开始是部门名
| RESEARCH   |
| SALES      |
| OPERATIONS |
+------------+

mysql> select ename,sal from emp
    -> union
    -> select dname from dept;  //拼接的数据必须两两相对应。不能一张表是一个数据,另一张表是两个数据,这样无法拼接!
ERROR 1222 (21000): The used SELECT statements have a different number of columns

5.limit (重点中的重点,以后分页查询全靠它了)

5.1、limit是mysql特有的,其他数据库中没有,不通用。
(Oracle中有一个相同的机制,叫做rownum)

5.2、limit取结果集中的部分数据,这是它的作用。

5.3、语法机制:
	limit startIndex,length
		startIndex表示起始位置,从0开始,0表示第一条数据。
		length表示取几个
	
	案例:取出工资前5名的员工(思路:降序取前5个。先排序,再去前5个)
		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 |
		+--------+---------+
		
		取前5个:
			select ename,sal from emp order by sal desc limit 0, 5;
			select ename,sal from emp order by sal desc limit 5;//startIndex默认是0
			+-------+---------+
			| ename | sal     |
			+-------+---------+
			| KING  | 5000.00 |
			| SCOTT | 3000.00 |
			| FORD  | 3000.00 |
			| JONES | 2975.00 |
			| BLAKE | 2850.00 |
			+-------+---------+

5.4、limit是sql语句最后执行的一个环节:
	select		5
		...
	from		1
		...		
	where		2
		...	
	group by	3
		...
	having		4
		...
	order by	6
		...
	limit		7
		...;

5.5、案例:找出工资排名在第4到第9名的员工?
	select ename,sal from emp order by sal desc limit 3,6;
	+--------+---------+
	| ename  | sal     |
	+--------+---------+
	| JONES  | 2975.00 |
	| BLAKE  | 2850.00 |
	| CLARK  | 2450.00 |
	| ALLEN  | 1600.00 |
	| TURNER | 1500.00 |
	| MILLER | 1300.00 |
	+--------+---------+

5.6、通用的标准分页sql?
不可能把所有的记录都放在一页上,所以要分页。

每页显示3条记录:
第1页:0, 3
第2页:3, 3
第3页:6, 3
第4页:9, 3
第5页:12, 3

每页显示pageSize条记录:
第pageNo页:(pageNo - 1) * pageSize, pageSize

pageSize是什么?是每页显示多少条记录
pageNo是什么?显示第几页

java代码{
	int pageNo = 2; // 页码是2
	int pageSize = 10; // 每页显示10条
	
	limit (pageNo - 1) * pageSize, pageSize
}

--------DQL语句到此学完--------

6.创建表

建表语句的语法格式:
	create table 表名(
		字段名1 数据类型 约束,
		字段名2 数据类型 约束,
		字段名3 数据类型 约束,
		....
	); //先不管约束

关于MySQL当中字段的数据类型?以下只说常见的
	int			整数型(java中的int)
	bigint		长整型(java中的long)
	float		浮点型(java中的float double)
	char		定长字符串(java中的String)
	varchar		可变长字符串 至多255个字符(java中的StringBuffer/StringBuilder)
	date		日期类型 可以直接存储日期(对应Java中的java.sql.Date类型)
	BLOB		二进制大对象(存储图片、视频等流媒体信息) Binary Large OBject (对应java中的Object)
	CLOB		字符大对象(存储较大文本,比如,可以存储4G的字符串) Character Large OBject(对应java中的Object)
	......

char和varchar怎么选择?
	比如:有一个字段name
	若数据类型是char(6),表示字符串的大小不超过6,超过6报错。
	若数据类型是varchar(6),如果name是jack,则只分配4个空间,而char(6)会分配6个空间。
	即不管name是几个字符,在不超过6的条件下,char(6)都会分配6个空间,varchar(6)根据字符个数分配空间。
	根据实际情况选char/varchar	
	char类型效率高,不用去判断分配几个空间。

	在实际的开发中,当某个字段中的数据长度不发生改变的时候,是定长的,例如:性别、生日等都是采用char。
	当一个字段的数据长度不确定,例如:简介、姓名等都是采用varchar。


BLOB和CLOB类型的使用?
	电影表: t_movie
	id(int)   name(varchar)   playtime(date/char)   haibao(BLOB)   history(CLOB)
	----------------------------------------------------------------------------------------
	1			蜘蛛侠	
	2
	3

表名在数据库当中一般建议以:t_或者tbl_开始。

创建学生表:
	学生信息包括:
		学号、姓名、性别、班级编号、生日
		学号:bigint
		姓名:varchar
		性别:char
		班级编号:int
		生日:char
	
	create table t_student(
		no bigint,
		name varchar(255),
		sex char(1),
		classno varchar(255),
		birth char(10)
	);

7.insert语句(向表中插入一条数据)

语法格式:
	insert into 表名(字段名1,字段名2,字段名3,....) values(值1,值2,值3,....);
	要求:字段的数量和值的数量相同,并且数据类型要对应相同。

//DOS命令窗口字体是GBK,而输入的是utf-8,所以输入中文会不匹配乱码,先不输中文。
insert into t_student(no,name,sex,classno,birth) values(1,'zhangsan','1','gaosan1ban');//错误
ERROR 1136 (21S01): Column count doesn't match value count at row 1

insert into t_student(no,name,sex,classno,birth) values(1,'zhangsan','1','gaosan1ban', '1950-10-12');

mysql> select * from t_student;
+------+----------+------+------------+------------+
| no   | name     | sex  | classno    | birth      |
+------+----------+------+------------+------------+
|    1 | zhangsan | 1    | gaosan1ban | 1950-10-12 |
+------+----------+------+------------+------------+

insert into t_student(name,sex,classno,birth,no) values('lisi','1','gaosan1ban', '1950-10-12',2);

mysql> select * from t_student;
+------+----------+------+------------+------------+
| no   | name     | sex  | classno    | birth      |
+------+----------+------+------------+------------+
|    1 | zhangsan | 1    | gaosan1ban | 1950-10-12 |
|    2 | lisi     | 1    | gaosan1ban | 1950-10-12 |
+------+----------+------+------------+------------+

insert into t_student(name) values('wangwu'); // 除name字段之外,剩下的所有字段自动插入NULL。
mysql> select * from t_student;
+------+----------+------+------------+------------+
| no   | name     | sex  | classno    | birth      |
+------+----------+------+------------+------------+
|    1 | zhangsan | 1    | gaosan1ban | 1950-10-12 |
|    2 | lisi     | 1    | gaosan1ban | 1950-10-12 |
| NULL | wangwu   | NULL | NULL       | NULL       |
+------+----------+------+------------+------------+

//insert语句每次都会插入一条新的数据,而要修改某条数据的某个字段用update
insert into t_student(no) values(3);
mysql> select * from t_student;
+------+----------+------+------------+------------+
| no   | name     | sex  | classno    | birth      |
+------+----------+------+------------+------------+
|    1 | zhangsan | 1    | gaosan1ban | 1950-10-12 |
|    2 | lisi     | 1    | gaosan1ban | 1950-10-12 |
| NULL | wangwu   | NULL | NULL       | NULL       |
|    3 | NULL     | NULL | NULL       | NULL       |
+------+----------+------+------------+------------+



//当这个表存在的话删除,删除某个表:
drop table if exists t_student; 

//再新建这个表
create table t_student(
	no bigint,
	name varchar(255),
	sex char(1) default 1, //加上default 1,默认为1,不写这句,默认是NULL
	classno varchar(255),
	birth char(10)
);
//可以使用desc t_student; 查看default是什么

insert into t_student(name) values('zhangsan');
mysql> select * from t_student;
+------+----------+------+---------+-------+
| no   | name     | sex  | classno | birth |
+------+----------+------+---------+-------+
| NULL | zhangsan | 1    | NULL    | NULL  |
+------+----------+------+---------+-------+

需要注意的地方:
	当一条insert语句执行成功之后,表格当中必然会多一行记录。
	即使多的这一行记录当中某些字段是NULL,后期也没有办法再执行
	insert语句插入数据了,只能使用update进行更新。




// 字段可以省略不写,但是后面的value对数量和顺序都有要求(数量和顺序都不能错)
insert into t_student values(1,'jack','0','gaosan2ban','1986-10-23');
mysql> select * from t_student;
+------+----------+------+------------+------------+
| no   | name     | sex  | classno    | birth      |
+------+----------+------+------------+------------+
| NULL | zhangsan | 1    | NULL       | NULL       |
|    1 | jack     | 0    | gaosan2ban | 1986-10-23 |
+------+----------+------+------------+------------+

insert into t_student values(1,'jack','0','gaosan2ban');
ERROR 1136 (21S01): Column count doesn't match value count at row 1

// 一次插入多行数据
insert into t_student
	(no,name,sex,classno,birth) 
values
	(3,'rose','1','gaosi2ban','1952-12-14'),(4,'laotie','1','gaosi2ban','1955-12-14');

mysql> select * from t_student;
+------+----------+------+------------+------------+
| no   | name     | sex  | classno    | birth      |
+------+----------+------+------------+------------+
| NULL | zhangsan | 1    | NULL       | NULL       |
|    1 | jack     | 0    | gaosan2ban | 1986-10-23 |
|    3 | rose     | 1    | gaosi2ban  | 1952-12-14 |
|    4 | laotie   | 1    | gaosi2ban  | 1955-12-14 |
+------+----------+------+------------+------------+

8.表的删除

//当这个表存在的话删除,删除某个表:
drop table if exists t_student; 

语法:
	drop table 表名; //通用写法
	drop table if exits 表名; //Oracle中不支持这种写法

9.表的复制

语法:
	create table 表名 as select语句;
	将查询结果当做表创建出来。

	例子:create table emp1 as select * from emp;
	创建一个表emp1,将select的查询结果(select * from emp)作为一个新表创建出来。

10.将查询结果插入到一张表中

创建一个新表:mysql> create table dept1 as select * from dept;
mysql> select * from dept1;
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+

mysql> insert into dept1 select * from dept; //将查询结果当作数据插入表中
mysql> select * from dept1;
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
注意:dept中的字段个数要等于dept1中的字段个数,才能插入。

11.修改数据:update

语法格式:
	update 表名 set 字段名1=值1,字段名2=值2... where 条件;

注意:没有条件整张表数据全部更新。

mysql> select * from dept1;
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+

案例:在表dept1中,将部门10的LOC修改为SHANGHAI,将部门名称修改为RENSHIBU
update dept1 set loc = 'SHANGHAI', dname = 'RENSHIBU' where deptno = 10;
mysql> select * from dept1;
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | RENSHIBU   | SHANGHAI |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
|     10 | RENSHIBU   | SHANGHAI |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+

更新所有记录
	update dept1 set loc = 'x', dname = 'y';
	mysql> select * from dept1;
	+--------+-------+------+
	| DEPTNO | DNAME | LOC  |
	+--------+-------+------+
	|     10 | y     | x    |
	|     20 | y     | x    |
	|     30 | y     | x    |
	|     40 | y     | x    |
	|     10 | y     | x    |
	|     20 | y     | x    |
	|     30 | y     | x    |
	|     40 | y     | x    |
	+--------+-------+------+

12.删除数据

语法格式:
	delete from 表名 where 条件;

注意:没有条件全部删除。

删除10部门数据?
	delete from dept1 where deptno = 10;

删除所有记录?
	delete from dept1;

怎么删除大表中的数据?(重点)
	truncate table 表名; // 表被截断,不可回滚。永久丢失。
	//使用delete删除数据后,数据还可以恢复,即回滚;使用truncate删除后无法恢复数据。

drop、truncate和delete的区别:
百度吧。简单来说:truncate和delete只删除表中数据,而drop删除表的数据和表结构。

13.关于表结构的修改和以上小总结

DQL(select) 查询数据
DML(insert delete update) 对于 表中的数据 进行 增删改
DDL(create drop alter)	  对于 表结构 进行 创建 删除 修改
除了alter,其他以上都学了。
对于表结构的修改,即alter就不讲了,使用工具来做。

对于表结构的修改,这里不讲了,大家使用工具完成即可。因为在实际开发中表一旦
设计好之后,对表结构的修改是很少的,修改表结构就是对之前的设计进行了否定,即使
需要修改表结构,我们也可以直接使用工具操作。修改表结构的语句不会出现在Java代码当中。

出现在java代码当中的sql包括:insert delete update select(这些都是表中的数据操作)

增删改查有一个术语:CRUD操作
Create(增) Retrieve(检索) Update(修改) Delete(删除)

14.约束(Constraint)

14.1.什么是约束?常见的约束有哪些呢?
在创建表的时候,可以给表的字段添加相应的约束,添加约束的目的是为了保证表中数据的
合法性、有效性、完整性。

常见的约束有哪些呢?
	非空约束(not null):约束的字段不能为NULL
	唯一约束(unique):约束的字段不能重复
	主键约束(primary key):约束的字段既不能为NULL,也不能重复(简称PK)
	外键约束(foreign key):...说不太清楚(简称FK)
	检查约束(check):注意Oracle数据库有check约束,但是mysql没有,目前mysql不支持该约束。
14.2.非空约束 not null
drop table if exists t_user;
create table t_user(
	id int,
	username varchar(255) not null,
	password varchar(255)
);

//编译错误,约束username字段不能为空!
insert into t_user(id,password) values(1,'123'); 
ERROR 1364 (HY000): Field 'username' doesn't have a default value

mysql>desc t_user;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id       | int          | YES  |     | NULL    |       |
| username | varchar(255) | NO   |     | NULL    |       |
| password | varchar(255) | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+

insert into t_user(id,username,password) values(1,'lisi','123');

Day3

1.约束

1.1.唯一性约束(unique)
* 唯一性约束修饰的字段具有唯一性,不能重复。但可以为null。

* 案例:给某一列添加unique
	drop table if exists t_user;
    create table t_user(
		id int,
		username varchar(255) unique  //【列级约束】
	);
	
	insert into t_user values(1,'zhangsan');		
	insert into t_user values(2,'zhangsan'); 
	ERROR 1062 (23000) : Duplicate entry 'zhangsan' for key 'username'
	//出现编译错误,唯一性约束,该字段与上一行字段重复,但可以为null(如下三行语句)

	insert into t_user(id) values(2);
    insert into t_user(id) values(3);
	insert into t_user(id) values(4);
	
*案例:给两个列或者多个列添加unique
    drop table if exists t_user;
	create table t_user(
	    id int,
	    usercode varchar(255),
	    username varchar(255),
	    unique(usercode,username) //多个字段联合起来添加一个约束unique 【表级约束】
 	);

	insert into t_user values(1,'111','zs');
	insert into t_user values(2,'111','ls');
	insert into t_user values(3,'222','zs');
	
	select * from t_user;
	+------+----------+----------+
	| id   | usercode | username |
	+------+----------+----------+
	|    1 | 111      | zs       |
	|    2 | 111      | ls       |
	|    3 | 222      | zs       |
	+------+----------+----------+
	
	//出现编译错误!这两个字段联合起来不能一样
	insert into t_user values(4,'111','zs');
	ERROR 1062 (23000) : Duplicate entry '111-zs' for key 'usercode'

* drop table if exists t_user;
  create table t_suer(
	id int,
	usercode varchar(255) unique,  //【列级约束】
	username varchar(255) unique  //【列级约束】
 );
 
    //'111'重复了
	insert into t_user values(1,'111','zs');
	insert into t_user values(2,'111','ls');
	ERROR 1062 (23000) : Duplicate entry '111' for key 'usercode'

* 注意:第三个案例和第二个案例的区别。即列级约束和表级约束的不同。
  列级约束可以写成表级约束:比如第一个案例可以成unique(username)
  
* 列级约束和表级约束的区别就是写法不同:
  		列级约束:直接写在某一字段后如:username varchar(255) unique 
  		表级约束:不写在某一字段后,另起一行写如:unique(username)
  和表示的意思不同:
  		列级约束:
  			usercode varchar(255) unique
			username varchar(255) unique
			表示usercode和usercode之间不同,username和username之间不同  
			例如:(1,'111','zs');
				(2,'111','lisi');//错误
  		表级约束:
  			unique(usercode,username)
  			表示usercode1和username1整体不能等于usercode2和username2
  			(usercode1,username1)!=(usercode2,username2)
  			例如:(1,'111','zs');//对
  			     (2,'111','lisi');//对
  			     (3,'111','zs');//错
  		
* 注意:not null约束只有列级约束,没有表级约束。
1.2.主键约束
* 怎么给一张表添加主键约束呢?
drop table if exists t_user;
create table t_user(
  id int primary key,  //【列级约束】
  username varchar(255),
  email varchar(255)
);

  insert into t_user(id,username,email) values(1,'zs','[email protected]');
  insert into t_user(id,username,email) values(2,'ls','[email protected]');
  insert into t_user(id,username,email) values(3,'ww','[email protected]');
  
  select * from t_user;
  +-----------------------------+
  | id | username | email       |
  +-----------------------------+
  |  1 | zs       | [email protected]  |
  |  2 | ls       | [email protected]  |
  |  3 | ww       | [email protected]  |
  +----+----------+-------------+

  //出现编译错误,主键约束,不能为null也不能重复!//重复
  insert into t_user(id,username,email) values(1,'jack','[email protected]'); 
  ERROR 1364 (HY000) : Field 'id' doesn't have a default value

  //出现编译错误,主键约束,不能为null也不能重复!//空
  insert into t_user(username,email) values('jack','[email protected]');
  ERROR 1364 (HY000): Field 'id' doesn't have a default value

  根据以上的测试得出:
  	id是主键,因为添加了主键约束,主键字段中的数据不能为null,也不能重复。
  
  主键的特点:不能为null,也不能重复。

* 主键相关的术语?
    主键约束 :primary key
    主键字段 : id字段添加primary key之后,id叫做主键字段
    主键值 :id字段中的每一个值都是主键值。

* 主键有什么作用?
	-表的设计三范式中有要求,第一范式就要求任何一张表都应该有主键。
	-主键的作用:
		主键值是这行记录在这张表上的唯一标识,用来区分每一条数据。(就像是身份证号)
		
* 主键的分类:
   	-根据主键字段的字段数量来划分:
     	单一主键:推荐的,常用的。(只有一个字段是主键约束)
	  	复合主键:多个字段联合起来添加一个主键约束
	  	(复合主键不建议使用,因为复合主键违背三范式)
	  
    -根据主键性质来划分:
     	自然主键(这种方式是推荐的):
     		主键值最好就是一个和业务没有任何关系的自然数。
	 	业务主键(不推荐使用): 
	 		主键值和系统的业务挂钩,
	 		例如:拿着银行卡的卡号做主键、拿着身份证号做为主键。
	 		
	        最好不要拿着和业务挂钩的字段做为主键。
	        因为以后的业务一旦发生改变的时候,主键也可能需要随着
		    发生变化,但有的时候没有办法变化,因为变化可能会导致主键重复。
 
* 一张表的主键约束只能有1个(必须记住)
(但是可以多个字段联合起来添加一个主键约束,即复合主键,但不建议使用)
  
* 使用表级约束方式定义主键:
      drop table if exists t_user;
      create table t_user(
          id int,
	  username varchar(255),
	  primary key(id)  //单一主键 表级约束方式
	);
	
	insert into t_user(id,username) values(1,'zs');
	insert into t_user(id,username) values(2,'ls');
	insert into t_user(id,username) values(3,'ws');
	insert into t_user(id,username) values(4,'cs');
	select * from t_user;

	insert into t_user(id,username) values(3,'cx');  //出现编译错误!
	ERROR 1062 (23000) : Duplicate entry '4' for key 'PRIMARY'

	以下内容是演示一下复合主键,不需要掌握:
	    drop table if exists t_user;
	    create table t_user(
	        id int,
		username varchar(255),
		password varchar(255),
		primary key(id,username)  //复合主键 表级约束方式
	     );
	    insert ......


* mysql提供主键值自增:(非常重要)
    drop table if exists t_user;
      create table t_user(
      
      //id字段自动维护一个自增的数字,从1开始,以1递增。
      id int primary key auto_increment,  
      
	  username varchar(255)
    );
    
      insert into t_user(username) values('a'); 
      insert into t_user(username) values('b');
      insert into t_user(username) values('c');
      insert into t_user(username) values('d');
      insert into t_user(username) values('e');
      insert into t_user(username) values('f');
      
      select * from t_user;
        +----+----------+
		| id | username |
		+----+----------+
		|  1 | a        |
		|  2 | b        |
		|  3 | c        |
		|  4 | d        |
		|  5 | e        |
		|  6 | f        |
		+----+----------+ 

注意:主键应该系统自动生成,所以添加auto_increment,自增可以使用工具。
提示:Oracle当中也提供了一个自增机制,叫做:序列(sequence)对象。
1.3.外键约束
 * 关于外键约束的相关术语:
  外键约束:foreign key
  外键字段:添加有外键约束的字段
  外键值:外键字段中的每一个值。

  * 业务背景:
      请设计数据库表,用来维护学生和班级的信息?
      
      第一种方案:一张表存储所有数据
      缺点:冗余【不推荐】
	  no(pk)          name          classno         classname
	  -----------------------------------------------------------
	   1               zs1            101          河南省平顶山市舞钢市垭口一高高三1班         
	   2               zs2            101          河南省平顶山市舞钢市垭口一高高三1班 
	   3               zs3            102          河南省平顶山市舞钢市垭口一高高三2班 
	   4               zs4            102          河南省平顶山市舞钢市垭口一高高三2班
	   5               zs5            102          河南省平顶山市舞钢市垭口一高高三2班 
	   	
	   	
	   第二种方案:两张表(班级表和学生表)
	   
	   t_class 班级表
	   cno(pk)         cname
   	   -------------------------------------------------------------
        101           河南省平顶山市舞钢市垭口一高高三1班 
    	102           河南省平顶山市舞钢市垭口一高高三2班 

    	t_student 学生表
    	sno(pk)        sname          classno(该字段添加外键约束fk)
    	-----------------------------------------------------------
     	1              zs1              101
     	2              zs2              101
     	3              zs3              102
     	4              zs4              102
     	5              zs5              102

		注意:
		classno字段加了外键约束fk引用cno字段,则classno的值必须是cno里有的值
		否则报错。若没加fk,则classno的值随便。

		t_student中的classno字段引用t_class表中的cno字段
		此时t_student表叫做子表,t_class表叫做父表。

  * 将以上表的建表语句写出来:

      删除数据的时候,先删除子表,再删除父表。
      添加数据的时候,先添加父表,再添加子表。
      创建表的时候,先创建父表,再创建子表。

   drop table if exists t_student;
   drop table if exists t_class;

   create table t_class(
       cno int,
       cname varchar(255),
       primary key(cno)  //主键约束
     );

	create table t_student(
       sno int,
	   sname varchar(255),
       classno int,
       primary key(sno),    //主键约束
       foreign key(classno) references t_class(cno)  //外键约束
     );

	//references 引用

	//先插父表
	insert into t_class values(101,'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
	insert into t_class values(102,'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy');

	//再插子表
    insert into t_student values(1,'zs1',101);
    insert into t_student values(2,'zs2',101);
    insert into t_student values(3,'zs3',102);
    insert into t_student values(4,'zs4',102);
    insert into t_student values(5,'zs5',102);
    insert into t_student values(6,'zs6',102);
    
    select * from t_class;
    +-----+-----------------------------------+
	| cno | cname                             |
	+-----+-----------------------------------+
	| 101 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
	| 102 | yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy |
	+-----+-----------------------------------+
	
    select * from t_student;
    +-----+-------+---------+
	| sno | sname | classno |
	+-----+-------+---------+
	|   1 | zs1   |     101 |
	|   2 | zs2   |     101 |
	|   3 | zs3   |     102 |
	|   4 | zs4   |     102 |
	|   5 | zs5   |     102 |
	|   6 | zs6   |     102 |
	+-----+-------+---------+
	
	//编译错误,引用的103,父表中cno字段没有该数据!
    insert into t_student values(7,'lisi',103);  
    ERROR 1452 (23000) : Cannot add or update a child row :aforeign key constraint fails (bjpowernode INT YT......)

  * 外键值可以为NULL?
      外键可以为null。

	 insert into t_student(sno,sname) values(7,'zs7');
	 select * from t_student;
		+-----+-------+---------+
		| sno | sname | classno |
		+-----+-------+---------+
		|   1 | zs1   |     101 |
		|   2 | zs2   |     101 |
		|   3 | zs3   |     102 |
		|   4 | zs4   |     102 |
		|   5 | zs5   |     102 |
		|   6 | zs6   |     102 |
		|   7 | zs7   |    NULL |
		+-----+-------+---------+

  * 外键字段引用其他表的某个字段的时候,被引用的字段必须是主键吗?
      注意:被引用的字段不一定是主键,但至少是具有unique约束,具有唯一性,不可重复!

2.存储引擎(了解)

2.1.完整的建表语句
create table t_x(id int);  //建表
show create table t_x;  //查看建表语句
 
//这个才是真正的建表语句:
CREATE TABLE `t_x` (
  `id` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

 注意:在MySQL当中,凡是标识符使用飘号括起来的。最好别用,不通用。

 建表的时候可以指定存储引擎,也可以指定字符集。

 mysql默认使用的存储引擎是InnoDB方式。
 默认采用的字符集是UTF-8。
2.2.什么是存储引擎?
存储引擎这个名字只有在mysql中存在。
(Oracle中有对应的机制,但不叫做存储引擎。Oracle中没有特殊的名字,就是"表的存储方式")

mysql支持很多存储引擎,每个存储引擎都对应了一种不同的存储方式。
每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
2.3.查看当前mysql支持的存储引擎
show engines \G;

 mysql 5.5.36版本支持的光速引擎有9个:
 *************************** 1. row ***************************
      Engine: FEDERATED
     Support: NO
     Comment: Federated MySQL storage engine
Transactions: NULL
	  	  XA: NULL
  Savepoints: NULL
*************************** 2. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO
	  	  XA: NO
  Savepoints: NO
*************************** 3. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
	  	  XA: NO
  Savepoints: NO
*************************** 4. row ***************************
      Engine: BLACKHOLE
     Support: YES
     Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
	  	  XA: NO
  Savepoints: NO
*************************** 5. row ***************************
      Engine: CSV
     Support: YES
     Comment: CSV storage engine
Transactions: NO
	  	  XA: NO
  Savepoints: NO
*************************** 6. row ***************************
      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
	  	  XA: NO
  Savepoints: NO
*************************** 7. row ***************************
      Engine: ARCHIVE
     Support: YES
     Comment: Archive storage engine
Transactions: NO
	  	  XA: NO
  Savepoints: NO
*************************** 8. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
	  	  XA: YES
  Savepoints: YES
*************************** 9. row ***************************
      Engine: PERFORMANCE_SCHEMA
     Support: YES
     Comment: Performance Schema
Transactions: NO
	  	  XA: NO
  Savepoints: NO
2.4.常见的存储引擎
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO  //MyISAM这种存储引擎不支持事务。
	  	  XA: NO
  Savepoints: NO

   MyISAM是mysql最常用的存储引擎,但是这种存储引擎不是默认的。
   MyISAM采用三个文件组织一个表:
       xxx.frm(存储格式的文件)
   	   xxx.MYD(存储表中数据的文件)
       xxx.MYI(存储表中索引的文件)
       
   优点:可被压缩,节省存储空间。并且可以转换为只读表,提高检索效率。
   缺点:不支持事务。

  --------------------------------------------------------------------------
   
      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
	  	  XA: YES
  Savepoints: YES
   
   mysql默认使用的存储引擎是InnoDB方式。
   优点:支持事务、行级锁、外键等。这种存储引擎数据的安全得到保障。

   表的结构存储在xxx.frm文件中
   数据存储在tablespace这样的表空间中(逻辑概念),无法被压缩,无法转换成只读。
   这种InnoDB存储引擎在MySQL数据库崩溃之后提供自动恢复机制。
   InoDB支持级联删除和级联更新。

----------------------------------------------------------------------------------

      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
	  	  XA: NO
  Savepoints: NO

  缺点:不支持事务。数据容易丢失。因为所有数据和索引都是存储在内存当中的。
  优点:查询速度最快。
  以前叫做HEPA引擎。

3.事务(Transaction)

3.1.什么是事务?
一个事务是一个完整的业务逻辑单元,不可再分。

比如:银行账户,从A账户向B账户转账10000元,需要执行两条update语句:
   update t_act set balance = balance - 10000 where actno = 'act-001';
   update t_act set balance = balance + 10000 where actno = 'act-002';

   以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。

想要保证以上的两条DML语句同时成功或者同时失败,那么就要使用数据库的"事务机制"。

事务的主要语句:
	commit 提交
	rollback 回滚
3.2.和事务相关的语句只有:DML语句(insert delete update)
为什么?因为他们这三个语句都是和数据库表当中的"数据"相关的。
事务的存在是为了保证数据的完整性,安全性。
3.3.假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗?
不需要事务机制。
但实际情况不是这样的,通常一个"事儿(事务【业务】)"需要多条DML语句共同联合完成。
3.4.事务的原理

3.5.事务的特性
事务包括四大特性:ACID
A:原子性:事务是最小的工作单元,不可再分。
C:一致性:事务必须保证多条DML语句同时成功或者同时失败。
I:隔离性:事务A与事务B之间具有隔离。
D:持久性:持久性说的是最终数据必须持久化到硬盘中,事务才算成功结束。
3.6.关于事务之间的隔离性
事务1,事务2,事务1和事务2操作同一张员工表。

事务1操作员工表后事务2能否读到,事务2操作员工表后事务1能否读到
这就涉及到了事务之间的隔离性。(相当于多线程并发)

事务隔离性存在隔离级别,理论上隔离级别包括4个(实际上都从第二级别开始):
   第一级别:读未提交(read uncommitted)(级别低)
       对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
       读未提交存在脏读(Dirty Read) 现象:表示读到了脏数据。
       未提交,数据在缓存中还未在硬盘中,数据极其不稳定。
       
   第二级别:读已提交(read committed)
       对方事务提交之后的数据我方可以读取到。
       读已提交存在的问题是:不可重复读
       不可重复读(人家提交后我读了,人家改了再提交我就无法再读到第一次读到的数据了)
       这种隔离级别解决了:脏读现象。
       
   第三级别:可重复读(repeatable read)
   	   可重复读(只能读到别人第一次提交的数据,无法读到别人修改后再提交的数据)
       这种隔离级别解决了:不可重复读问题。
       这种隔离级别存在的问题是:读取到的数据是幻象。
       
   第四级别:序列化读/串行化读
       解决了所有问题。
       效率低,需要事务排队。
       该级别:两个事务无法并发,事务1没结束时事务2无法开启。

	//不懂就看下面对于两个事务的隔离的演示。

   Oracle数据库默认的隔离级别是:第二级别,读已提交。
   mysql数据库默认的隔离级别是:第三级别,可重复读。
3.7.演示事务
* mysql事务默认情况下是自动提交的。
	什么是自动提交?
		只要执行任意一条DML语句则提交一次。
    怎么关闭默认提交?
        start transaction;
---------------------------------------------------------------
演示事务:
* 建表:
   drop table if exists t_user;
   create table t_user(
       id int primary key auto_increment,
       username varchar(255)
   );
----------------------------------------------------------------
* 演示:mysql中的事务是支持自动提交的,只要执行一条DML语句,则提交一次。
   mysql> insert into t_user(username) values('zs');
   Querk OK, 1 row affected (0.03 sec)
   
   mysql> select * from t_user;
	+----+----------+
	| id | username |
	+----+----------+
	|  1 | zs       |
	+----+----------+
	
   mysql> rollback;
   Query OK, 0 rows affected (0.00 sec)

   mysql> select * from t_user;  //如果不是自动提交,回滚之后为Empty
	 +----+----------+
	 | id | username |
	 +----+----------+
	 |  1 | zs       |
	 +----+----------+
----------------------------------------------------------------
* 演示:使用start transaction; 关闭自动提交机制。
    mysql> select * from t_user;
	+----+----------+
	| id | username |
	+----+----------+
	|  1 | zs       |
	+----+----------+
	1 row in set (0.00 sec)

	mysql> start transaction;  //关闭自动提交机制
	Query OK, 0 rows affected (0.00 sec)

	mysql> insert into t_user(username) values("lisi");
	Query OK, 1 row affected (0.00 sec)

	mysql> select * from t_user;
	+----+----------+
	| id | username |
	+----+----------+
	|  1 | zs       |
	|  2 | lisi     |
	+----+----------+
	2 rows in set (0.00 sec)

	mysql> insert into t_user(username) values("wangwu");
	Query OK, 1 row affected (0.00 sec)

	mysql> select * from t_user;
	+----+----------+
	| id | username |
	+----+----------+
	|  1 | zs       |
	|  2 | lisi     |
	|  3 | wangwu   |
	+----+----------+
	3 rows in set (0.00 sec)

	mysql> rollback;    //回滚
	Query OK, 0 rows affected (0.00 sec)

	mysql> select * from t_user; //关闭自动提交机制,且未再提交,回滚到上一次提交处
	+----+----------+
	| id | username |
	+----+----------+
	|  1 | zs       |
	+----+----------+
	1 row in set (0.00 sec)

----------------------------------------------------------------
* 演示:使用start transaction; 关闭自动提交机制,再提交commit 
	//上一个事务rollback后,上一个事务就结束了,要重新关闭自动提交机制
	mysql> start transaction;
	Query OK, 0 rows affected (0.00 sec)

	mysql> insert into t_user(username) values("wangwu");
	Query OK, 1 row affected (0.00 sec)

	mysql> insert into t_user(username) values("object");
	Query OK, 1 row affected (0.00 sec)

	mysql> insert into t_user(username) values("joke");
	Query OK, 1 row affected (0.00 sec)

	mysql> insert into t_user(username) values("xiaozhaozhao");
	Query OK, 1 row affected (0.00 sec)

	mysql> select * from t_user;
	+----+--------------+
	| id | username     |
	+----+--------------+
	|  1 | zs           |
	|  4 | wangwu       |
	|  5 | object       |
	|  6 | joke         |
	|  7 | xiaozhaozhao |
	+----+--------------+
	5 rows in set (0.00 sec)

	mysql> commit;    //手动提交
	Query OK, 0 rows affected (0.00 sec)

	mysql> select * from t_user;
	+----+--------------+
	| id | username     |
	+----+--------------+
	|  1 | zs           |
	|  4 | wangwu       |
	|  5 | object       |
	|  6 | joke         |
	|  7 | xiaozhaozhao |
	+----+--------------+
	5 rows in set (0.00 sec)

	mysql> rollback;   //手动提交后,再回滚不变
	Query OK, 0 rows affected (0.00 sec)

	mysql> select * from t_user;
	+----+--------------+
	| id | username     |
	+----+--------------+
	|  1 | zs           |
	|  4 | wangwu       |
	|  5 | object       |
	|  6 | joke         |
	|  7 | xiaozhaozhao |
	+----+--------------+
	5 rows in set (0.00 sec)


----------------------------------------------------------------
rollback:回滚(回到上一个提交点,此次事务结束)
commit:提交(该事务结束)
start transaction:关闭自动提交机制。
savepoint+名字1:保存该点此处,rollback+名字1,就回到了该保存点处。
 
----------------------------------------------------------------
* 使用两个事务,演示隔离级别:

  使用两个事务,要开启两个DOS命令窗口,操作同一张表。
  事务1,事务2,表1。事务1和事务2同时操作表1.
  
	演示第1级别:读未提交(read uncommitted)
		设置事务的全局隔离级别:
			set global transaction isolation level read uncommitted;
		查看事务的全局隔离级别:
			select @@global.transaction_isolation;//mysql8.0+版本
		 	+--------------------------------+
			| @@global.transaction_isolation |
			+--------------------------------+
			| READ-UNCOMMITTED               |
			+--------------------------------+

		现象:对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
		事务1对表1增加1条数据,但未提交commit,但事务2可以查询到表1增加了1条数据。


    演示第二级别;读已提交(read committed)
       设置事务的全局隔离级别:
			set global transaction isolation level read committed;
		查看事务的全局隔离级别:
			select @@global.transaction_isolation;//mysql8.0+版本
		 	+--------------------------------+
			| @@global.transaction_isolation |
			+--------------------------------+
			| READCOMMITTED                  |
			+--------------------------------+
		
		现象:读已提交
		事务2对表1增加1条数据,事务2不提交,事务1查看不到新的数据
		只有事务2提交之后,事务1才能查看到新数据。
		
		
    演示第三级别:可重复读(repeatable read)
        设置事务的全局隔离级别:
			set global transaction isolation level repeatable read;
		查看事务的全局隔离级别:
			select @@global.transaction_isolation;//mysql8.0+版本
		 	+--------------------------------+
			| @@global.transaction_isolation |
			+--------------------------------+
			| REPEATABLE-READ                |
			+--------------------------------+
		
		现象:可重复读
		事务1对表1增加了1条数据,然后提交。事务2只能看到表1最初的数据,看不到新增的数据。
		无论事务1对表1进行怎样的操作,提交后,事务2只能看到表1最初的数据。


	演示第四级别:序列化读/串行化读(serializable)
	    设置事务的全局隔离级别:
			set global transaction isolation level serializable;
	    查看事务的全局隔离级别:
			select @@global.transaction_isolation;//mysql8.0+版本
			+--------------------------------+
			| @@global.transaction_isolation |
			+--------------------------------+
			| SERIALIZABLE                   |
			+--------------------------------+
		
		现象:事务1不结束,事务2无法对表1操作。
		事务1先操作表1,对表1新增1条数据(未提交);
		然后事务2查询表1:select * from 表1; 回车后光标会停在那;
		当事务1输入提交命令commit(代表事务1结束)时,事务2才出现查看结果。

4.索引

4.1.什么是索引?有什么用?
索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。

在数据库方面,查询一张表的时候有两种检索方式:
    第一种方式:全表扫描
    第二种方式:根据索引检索(效率很高)
    
索引为什么可以提高检索效率呢?
    其实最根本的原理是缩小了扫描的范围。

索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,也需要数据库不断的维护。是有维护成本的。
比如:表中的数据经常被修改,这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。

添加索引是给某一个字段,或者说某些字段添加索引。

select ename,sal from emp where ename = 'SMITH';
当ename字段没有添加索引的时候,以上sql语句会进行全表扫描,扫描ename字段中所有的值。
当ename字段添加索引的时候,以上sql语句会根据索引扫描,快速定位。
4.2.怎么创建索引对象?怎么删除索引对象?
创建索引对象:
    create index 索引名称 on 表名(字段名);
删除索引对象:
    drop index 索引名称 on 表名;
4.3.什么时候考虑给字段添加索引?(满足什么条件)
* 数据量庞大。(根据客户的需求,根据线上的环境)
* 该字段很少的DML操作。(因为字段进行修改操作,索引也需要维护)
* 该字段经常出现在where子句中。(经常根据哪个字段维护)
4.4.注意:主键和具有unique约束的字段会自动添加索引。
根据主键查询效率较高,尽量根据主键检索。
4.5.查看sql语句的执行计划
查看sql语句的执行计划:通过type ALL 知道是全表扫描(扫描了14次),不是根据索引扫描。
mysql> explain select ename,sal from emp where sal = 5000;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+


给薪资sal字段添加索引:
    create index emp_sal_index on emp(sal);
    
    
查看sql语句的执行计划:通过type ref 知道使用了索引,只扫描了1次。
mysql> explain select ename,sal from emp where sal = 5000;
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key           | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | emp_sal_index | emp_sal_index | 9       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
                                                                             rows检索次数减少了
4.6.索引底层采用的数据结构是:B + Tree
4.7.索引的实现原理

通过B Tree缩小扫描范围,底层索引进行了排序,分区,索引会携带数据在表中的"物理地址",最终通过索引检索到数据之后,获取到关联的物理地址,
通过物理索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率是最高的。
   select ename from emp where ename = 'SMITH';
   通过索引转换为:
   select ename from emp where 物理地址 = 0x3;
4.8.索引的分类
单一索引:给单个字段添加索引
复合索引:给多个字段联合起来添加一个索引
主键索引:主键上会自动添加索引
唯一索引:有unique约束的字段会自动添加索引

一个表中索引只有1个
......
4.9.索引什么时候失效?
select ename from emp where ename like ' %A% ';
就算ename加了索引,也不会使用索引检索,因为不知道%是啥,查不到。
第一个不是%,就会使用索引。
模糊查询的时候,第一个通配符使用的是%,这个时候索引是是失效的。

5.视图(view)

5.1.什么是视图?
站在不同的角度去看到数据(同一张表的数据,通过不同的角度去看待)
5.2.怎么创建视图?怎么删除视图?
创建视图:create view myview as select empno,ename from emp;
删除视图:drop view myview;

注意:只有DQL语句(select语句)才能以试图对象的方式创建出来。
5.3.对视图进行增删改查,会影响到原表数据
通过视图影响原表数据,不是直接操作的原表
可以对试图进行CRUD(增删改查)操作
5.4.面向视图操作
//创建视图myview
create view myview as select empno,ename from emp;

mysql> select * from myview;
+-------+--------+
| empno | ename  |
+-------+--------+
|  7369 | SMITH  |
|  7499 | ALLEN  |
|  7521 | WARD   |
|  7566 | JONES  |
|  7654 | MARTIN |
|  7698 | BLAKE  |
|  7782 | CLARK  |
|  7788 | SCOTT  |
|  7839 | KING   |
|  7844 | TURNER |
|  7876 | ADAMS  |
|  7900 | JAMES  |
|  7902 | FORD   |
|  7934 | MILLER |
+-------+--------+

//创建一个新表emp_bak
create table emp_bak as select * from emp;

//创建视图myview1
create view myview1 as select empno,ename,sal from emp_bak;

//通过视图修改原表数据
update myview1 set ename = 'hehe',sal = 1 where empno = 7369; 

//通过视图删除原表数据
delete from myview1 where empno = 7369; 
5.5.视图的作用
视图可以隐藏表的实现细节。
保密级别较高的系统,数据库只对外提供相关的视图,java程序员只对视图对象进行CRUD
CRUD增删改查

6.DBA命令

DBA:数据库管理员
6.1.把数据库当中的数据导出
在windows的DOS命令窗口中执行: (导出整个库)
    mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p999
    mysqldump 数据库名>把数据库导到哪个地方 -uroot -p密码
在windows的dos命令窗口中执行:(导出数据库中指定的表)
    mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p999
    mysqldump 数据库名 要导出的表名>把数据库导到哪个地方 -uroot -p密码
6.2.把数据导入数据库中
第一步:create database bjpowernode;  //创建数据库 bjpowernode
第二步:use bjpowernode;
第三步:source D:\bjpowernode.sql //source+文件路径

7.数据库设计三范式(重点内容,面试经常会问)

7.1.什么是设计范式?
设计表的依据。按照这三个范式设计的表不会出现数据冗余。
7.2.三范式都是哪些?
第一范式:任何一张表都应该有主键,并且每一个字段原子性不可再分。

------------------------------------------------------------------------
第二范式:建立在第一范式的基础上,所有非主键字段完全依赖主键,不能产生部份依赖。

上表中非主键字段对主键产生了部分依赖:
	该主键是复合主键
	学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号
	而教师姓名部分依赖了主键的一个字段教师编号,而没有依赖学生编号
	这就是第二范式部分依赖。
	
	这样无法明确表示关系,产生了冗余(也是为什么不推荐使用复合主键)

	解决办法:
	多对多关系:三张表,学生表,老师表,学生老师关系表(两个外键)
    这样就可以明确表示多对多关系(1个学生有多个老师,1个老师有多个学生)

	典型的多对多设计口诀:多对多?三张表,关系表两个外键。
    
    t_student学生表
    sno(pk)       sname
    ---------------------
     1             张三
     2             李四 
     3             王五

     t_teacher 讲师表
     tno(pk)      tname
     ----------------------
      1			王老师
      2			张老师
      3			李老师

      t_student_teacher_relation 学生讲师关系表
      id(pk)     sno(fk)          tno(fk)   //该表tno引用讲师表tno(fk)
      -------------------------------------------
       1	      1                 3
       2	      1					1
       3	      2					2	
       4	      2					3
       5	      3					1
       6	      3					3
       
	  以上是一种典型的“多对多”的设计
------------------------------------------------------------------------

第三范式:建立在第二范式的基础上,所有非主键字段直接依赖主键,不能产生传递依赖。

    一对多?两张表,班级表,学生表(加外键)(多的表加外键)
    一个班级对应多个学生

	典型的一对多设计口诀:一对多?两张表,多的表加外键。
    
    班级t_class
    cno(pk)          cname
    --------------------------
      1              班级1
      2              班级2

    学生t_student
    sno(pk)     sname       classno(fk)  //该表classno引用班级表cno(fk)
    --------------------------------------------
     101	     张1	      1
     102         张2	      2
     103	     张3	      2
     104	     张4	      1
     105	     张5	      2

提醒:在实际的开发中,以满足客户需求为主,有的时候会拿冗余换执行速度。
表连接越多,sql语句执行速度越慢,单表执行速度快。
7.3.一对一怎么设计?
一对一:一张表拆成两张表,两张表有关系

一对一设计有两种方案:主键共享
 
   t_user_login 用户登陆表
    id(pk)       username        password
    ----------------------------------------
     1             zs                123
     2             ls                456
     
 	t_user_detail 用户详细信息表  //该表id引用用户登陆表id(fk) 
  	id(pk+fk)        realname          tel          ...
 	----------------------------------------------------
     1              	张三            11111111112234
	 2	       			李四            12112523432412


一对一设计有两种方案:外键唯一

   t_user_login 用户登陆表
    id(pk)       username        password
    ----------------------------------------
     1             zs                123
     2             ls                456
 
 	t_user_detail 用户详细信息表
  	id(pk)         realname          tel        userid(fk+unique)//对外键添加唯一性,userid引用id(fk)
 	----------------------------------------------------
   	1                张三         111111114          1
   	2	        	 李四         121432412          2
7.4.数据库三范式总结
第一范式:任何一张表都应该有主键,并且每一个字段原子性不可再分。
第二范式:建立在第一范式的基础上,所有非主键字段完全依赖主键,不能产生部份依赖。
	典型的多对多设计口诀:多对多?三张表,关系表两个外键。
第三范式:建立在第二范式的基础上,所有非主键字段直接依赖主键,不能产生传递依赖。
	典型的一对多设计口诀:一对多?两张表,多的表加外键。

提醒:在实际的开发中,以满足客户需求为主,有的时候会拿冗余换执行速度。
表连接越多,sql语句执行速度越慢,单表执行速度快。

一对一设计有两种方案:
	-主键共享:若两张表,给第二张表的主键再添加一个外键
	-外键唯一:若两张表,给第二张表新加一个字段(该字段添加外键并添加唯一性约束)

课后习题

1.取得每个部门最高薪水的人员名称

第一步:取得每个部门的最高薪水
select deptno,max(sal) as maxsal from emp group by deptno;
	+--------+---------+
	| deptno | maxsal  |
	+--------+---------+
	|     20 | 3000.00 |
	|     30 | 2850.00 |
	|     10 | 5000.00 |
	+--------+---------+
第二步:将以结果作为临时表t,t表和emp表进行连接,
条件是:t.deptno = e.deptno and t.maxsal = e.sal

select 
	e.ename,t.*
from 
	emp e
join 
	(select deptno,max(sal) as maxsal from emp group by deptno) t
on
	t.deptno = e.deptno and t.maxsal = e.sal;
	
	+-------+--------+---------+
	| ename | deptno | maxsal  |
	+-------+--------+---------+
	| BLAKE |     30 | 2850.00 |
	| SCOTT |     20 | 3000.00 |
	| KING  |     10 | 5000.00 |
	| FORD  |     20 | 3000.00 |
	+-------+--------+---------+

注意:因为group by分组了,所以select后面只能跟分组函数和参与分组的字段(不能写ename)

2.哪些人的薪水在部门的平均薪水之上

第一步:求部门的平均薪水
select deptno,avg(sal) as avgsal from emp group by deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

第二步:每个部门中,哪些员工的薪水>该部门的平均薪水
将以上查询结果作为t表,t表与emp表连接
条件:部门编号相同,并且emp的sal大于t表的avgsal
select
	e.deptno,e.ename,e.sal 
from 
	emp e 
join 
	(select deptno,avg(sal) as avgsal from emp group by deptno) t 
on 
	e.deptno = t.deptno and e.sal>t.avgsal;
	
+--------+-------+---------+
| deptno | ename | sal     |
+--------+-------+---------+
|     30 | ALLEN | 1600.00 |
|     20 | JONES | 2975.00 |
|     30 | BLAKE | 2850.00 |
|     20 | SCOTT | 3000.00 |
|     10 | KING  | 5000.00 |
|     20 | FORD  | 3000.00 |
+--------+-------+---------+

3.取得部门中(所有人的)平均的薪水等级

问题要求的是:平均的薪水等级:
第一步:查询所有员工的薪水等级
select e.deptno,e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and hisal;
+--------+--------+-------+
| deptno | ename  | grade |
+--------+--------+-------+
|     20 | SMITH  |     1 |
|     30 | ALLEN  |     3 |
|     30 | WARD   |     2 |
|     20 | JONES  |     4 |
|     30 | MARTIN |     2 |
|     30 | BLAKE  |     4 |
|     10 | CLARK  |     4 |
|     20 | SCOTT  |     4 |
|     10 | KING   |     5 |
|     30 | TURNER |     3 |
|     20 | ADAMS  |     1 |
|     30 | JAMES  |     1 |
|     20 | FORD   |     4 |
|     10 | MILLER |     2 |
+--------+--------+-------+

第二步:将以上查询结果作为t表,按部门分组,求每个部门薪水等级的平均值
select 
	t.deptno,avg(t.grade) 
from 
	(select e.deptno,e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and hisal) t 
group by 
	t.deptno;
	
+--------+--------------+
| deptno | avg(t.grade) |
+--------+--------------+
|     20 |       2.8000 |
|     30 |       2.5000 |
|     10 |       3.6667 |
+--------+--------------+




若为平均薪水的等级:
第一步:取得每个部门的平均薪水
select e.deptno,avg(sal) as avgsal from emp e group by e.deptno
+--------+-------------+
| deptno | avg(sal)    |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

第二步:将以上查询结果作为t表,与salgrade表连接,查平均薪水的等级
select
	t.deptno,s.grade 
from 
	(select e.deptno,avg(sal) as avgsal from emp e group by e.deptno) t 
join 
	salgrade s 
on t.avgsal between s.losal and s.hisal

4.不准用分组函数(Max),取得最高薪水

第一种方法:降序
select e.ename,e.sal from emp e order by e.sal desc limit 0,1;
//order by e.sal desc 按照薪资降序排列 取第一个
//limit 0,1 从0开始取1个
+-------+---------+
| ename | sal     |
+-------+---------+
| KING  | 5000.00 |
+-------+---------+

第二种方法:使用表的自连接
a表
+---------+
| sal     |
+---------+
|  800.00 |
| 1600.00 |
| 1250.00 |
| 2975.00 |
| 1250.00 |
| 2850.00 |
| 2450.00 |
| 3000.00 |
| 5000.00 |
| 1500.00 |
| 1100.00 |
|  950.00 |
| 3000.00 |
| 1300.00 |
+---------+

b表
+---------+
| sal     |
+---------+
|  800.00 |
| 1600.00 |
| 1250.00 |
| 2975.00 |
| 1250.00 |
| 2850.00 |
| 2450.00 |
| 3000.00 |
| 5000.00 |
| 1500.00 |
| 1100.00 |
|  950.00 |
| 3000.00 |
| 1300.00 |
+---------+

第一步:a表中每一个数据(除最大值5000)都能在b表中找到一个大于它的
select a.sal from emp a join emp b on a.sal < b.sal;

第二步:对第一步的结果去重(只有5000不在该表中)
select distinct a.sal from emp a join emp b on a.sal < b.sal;
+---------+
| sal     |
+---------+
| 1300.00 |
|  950.00 |
| 1100.00 |
| 1500.00 |
| 1250.00 |
|  800.00 |
| 2450.00 |
| 2850.00 |
| 1600.00 |
| 2975.00 |
| 3000.00 |
+---------+

第三步:not in 找到不在表中的5000
select 
	sal
from
	emp
where
	sal
not in
	(select distinct a.sal from emp a join emp b on a.sal < b.sal);

第三种方法:直接max
select max(sal) from emp e;
+----------+
| max(sal) |
+----------+
|  5000.00 |
+----------+

5.取得平均薪水最高的部门的部门编号

第一种方法:
第一步:求每个部门的平均薪水(部门编号+每个部门的平均薪水)
select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

第二步:在第一步的基础上,降序desc排列,limit 0,1 取第一个
select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno order by avgsal desc limit 0,1;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     10 | 2916.666667 |
+--------+-------------+


第二种方法:max
第一步:求每个部门的平均薪水
select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

第二步:
select max(t.avgsal) from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t;
+---------------+
| max(t.avgsal) |
+---------------+
|   2916.666667 |
+---------------+

第三步:
select 
	deptno,avg(sal) as avgsal 
from 
	emp 
group by 
	deptno 
having 
	avgsal = (select max(t.avgsal) from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t);
	
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     10 | 2916.666667 |
+--------+-------------+

6.取得平均薪水最高的部门的部门名称

第一步:求每个部门的平均薪水(部门编号+平均薪水)
select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno;

+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

第一步:将部门编号改为部门名称(以上结果为t表,与dept表连接)
select 
	d.dname,t.avgsal 
from 
	dept d 
join 
	(select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t 
on 
	d.deptno = t.deptno;
	
+------------+-------------+
| dname      | avgsal      |
+------------+-------------+
| ACCOUNTING | 2916.666667 |
| RESEARCH   | 2175.000000 |
| SALES      | 1566.666667 |
+------------+-------------+

第三步:在第二步的基础上,降序排列,取第一个。
select 
	d.dname,t.avgsal 
from 
	dept d 
join 
	(select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t 
on 
	d.deptno = t.deptno 
order by 
	t.avgsal desc limit 0,1;
	
+------------+-------------+
| dname      | avgsal      |
+------------+-------------+
| ACCOUNTING | 2916.666667 |
+------------+-------------+

7.求平均薪水的等级最低的部门的部门名称

第一步:每个部门的平均薪水(部门编号+平均薪水)
select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

第二步:每个部门平均薪水的等级(部门编号+平均薪水)
将上表作为t表,与salgrade表连接
select 
	t.*,s.grade
from 
	(select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t
join 
	salgrade s
on
	t.avgsal between s.losal and s.hisal;
	
+--------+-------------+-------+
| deptno | avgsal      | grade |
+--------+-------------+-------+
|     20 | 2175.000000 |     4 |
|     30 | 1566.666667 |     3 |
|     10 | 2916.666667 |     4 |
+--------+-------------+-------+

第三步:注意:平均薪水等级最低的部门可能不止一个
通过min找出最低平均薪水等级,把第二步的结果作为p表
select 
	min(p.grade) 
from 
	(select t.*,s.grade from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join salgrade s on t.avgsal between s.losal and s.hisal) p;
	
+--------------+
| min(p.grade) |
+--------------+
|            3 |
+--------------+

第四步:从p表中找出和第三步结果相同的部门
select 
	p.* 
from 
	(select t.*,s.grade from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join salgrade s on t.avgsal between s.losal and s.hisal) p 
where 
	p.grade = (select min(p.grade) from (select t.*,s.grade from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join salgrade s on t.avgsal between s.losal and s.hisal) p);
	
+--------+-------------+-------+
| deptno | avgsal      | grade |
+--------+-------------+-------+
|     30 | 1566.666667 |     3 |
+--------+-------------+-------+

第五步:将部门编号改为部门名称
将第四步的结果作为q表,与dept表连接
select 
	d.dname,q.* 
from 
	(select p.* from (select t.*,s.grade from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join salgrade s on t.avgsal between s.losal and s.hisal) p where p.grade = (select min(p.grade) from (select t.*,s.grade from (select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno) t join salgrade s on t.avgsal between s.losal and s.hisal) p)) q 
join 
	dept d 
on 
	d.deptno = q.deptno;
	
+-------+--------+-------------+-------+
| dname | deptno | avgsal      | grade |
+-------+--------+-------------+-------+
| SALES |     30 | 1566.666667 |     3 |
+-------+--------+-------------+-------+

------------------------------------------------------------------
第二种方法:在于第三步的不同
平均薪水等级最低的部门可能不止一个
通过limit找出最低平均薪资,再找出对应的薪资等级,然后找出所有与之薪资等级相同的部门

第一步:每个部门的平均薪水(部门编号+平均薪水)
select e.deptno,avg(e.sal) as avgsal from emp e group by e.deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     20 | 2175.000000 |
|     30 | 1566.666667 |
|     10 | 2916.666667 |
+--------+-------------+

将部门编号换为部门名称:
select 
	d.dname,avg(e.sal) as avgsal 
from 
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno 
group by 
	d.dname;
	
+------------+-------------+
| dname      | avgsal      |
+------------+-------------+
| RESEARCH   | 2175.000000 |
| SALES      | 1566.666667 |
| ACCOUNTING | 2916.666667 |
+------------+-------------+

第二步:求每个部门平均薪水的等级 
将以上结果作为t表,与salgrade表连接
select 
	t.*,s.grade 
from 
	(select d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by d.dname) t 
join 
	salgrade s 
on 
	t.avgsal between s.losal and s.hisal;
	
+------------+-------------+-------+
| dname      | avgsal      | grade |
+------------+-------------+-------+
| RESEARCH   | 2175.000000 |     4 |
| SALES      | 1566.666667 |     3 |
| ACCOUNTING | 2916.666667 |     4 |
+------------+-------------+-------+

第三步:
1.通过limit找出最低平均薪资:
select avg(sal) as avgsal from emp group by deptno order by avgsal asc limit 0,1; 
+-------------+
| avgsal      |
+-------------+
| 1566.666667 |
+-------------+

2.再找出最低平均薪资对应的薪资等级
select 
	grade 
from 
	salgrade 
where 
	(select avg(sal) as avgsal from emp group by deptno order by avgsal asc limit 0,1) between losal and hisal;
	
+-------+
| grade |
+-------+
|     3 |
+-------+

3.基于第二步,然后找出所有与之薪资等级相同的部门
select 
	t.*,s.grade 
from 
	(select d.dname,avg(e.sal) as avgsal from emp e join dept d on e.deptno = d.deptno group by d.dname) t 
join 
	salgrade s 
on 
	t.avgsal between s.losal and s.hisal 
where 
	s.grade = (select grade from salgrade where (select avg(sal) as avgsal from emp group by deptno order by avgsal asc limit 0,1) between losal and hisal);
	
+-------+-------------+-------+
| dname | avgsal      | grade |
+-------+-------------+-------+
| SALES | 1566.666667 |     3 |
+-------+-------------+-------+

8.取得比普通员工(员工代码没有在mgr字段上出现的)的最高薪水还要高的领导人姓名

mgr为领导字段

select distinct mgr from emp; //所有的领导代号 原领导表中有重复的代码
+------+
| mgr  |
+------+
| 7902 |
| 7698 |
| 7839 |
| 7566 |
| NULL |
| 7788 |
| 7782 |
+------+

//看见有NULL要注意,如果有NULL,not in(...)所有的结果都是NULL,所以要排除NULL
select distinct mgr from emp where mgr is not NULL;
+------+
| mgr  |
+------+
| 7902 |
| 7698 |
| 7839 |
| 7566 |
| 7788 |
| 7782 |
+------+


第一步:找出员工代码没有在mgr字段上出现的员工 的 最高薪水
select max(sal) from emp where empno not in(select distinct mgr from emp where mgr is not NULL);
+----------+
| max(sal) |
+----------+
|  1600.00 |
+----------+

第二步:找出薪水 比 普通员工的最高薪水 还要高 的领导
直接sal>1600就好了
就算有的领导薪水比员工低 也没关系 细品
员工代码没有在领导字段mgr出现,说明该员工是普通员工,不是领导
select empno,ename from emp where sal>(select max(sal) from emp where empno not in(select distinct mgr from emp where mgr is not NULL));
+-------+-------+
| empno | ename |
+-------+-------+
|  7566 | JONES |
|  7698 | BLAKE |
|  7782 | CLARK |
|  7788 | SCOTT |
|  7839 | KING  |
|  7902 | FORD  |
+-------+-------+

9.取得薪水最高的前五名员工

select ename,sal from emp order by sal desc limit 0,5;
+-------+---------+
| ename | sal     |
+-------+---------+
| KING  | 5000.00 |
| SCOTT | 3000.00 |
| FORD  | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+

//此题没有考虑薪资一样的情况,可能第六名也是2850,不要深究了

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 |
+--------+---------+

11.取得最后入职的5名员工

//日期也可以升序降序排列
select ename,hiredate from emp order by hiredate desc limit 0,5;
+--------+------------+
| ename  | hiredate   |
+--------+------------+
| ADAMS  | 1987-05-23 |
| SCOTT  | 1987-04-19 |
| MILLER | 1982-01-23 |
| JAMES  | 1981-12-03 |
| FORD   | 1981-12-03 |
+--------+------------+

12.取得每个薪水等级有多少员工

第一步:找出每个员工的薪水等级
select 
	e.ename,s.grade 
from 
	emp e 
join 
	salgrade s 
on 
	e.sal between s.losal and s.hisal;
+--------+-------+
| ename  | grade |
+--------+-------+
| SMITH  |     1 |
| ALLEN  |     3 |
| WARD   |     2 |
| JONES  |     4 |
| MARTIN |     2 |
| BLAKE  |     4 |
| CLARK  |     4 |
| SCOTT  |     4 |
| KING   |     5 |
| TURNER |     3 |
| ADAMS  |     1 |
| JAMES  |     1 |
| FORD   |     4 |
| MILLER |     2 |
+--------+-------+

第二步:将以上结果继续按照grade分组统计count
select 
	s.grade,count(*)    //count(*) 代表 记录每组有多少数据条数,也可以count(e.ename)/count(s.grade)
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 |
+-------+----------+

13.面试题

有3个表S(学生表),C(课程表),SC(学生选课表)
S(SNO,SNAME)代表(学号,姓名)  
C(CNO,CNAME,CTEACHER)代表(课号,课名,教师)
SC(SNO,CNO,SCGRADE)代表(学号,课号,成绩)
问题:
1,找出没选过“黎明”老师的所有学生姓名。
2,列出2门以上(含2门)不及格学生姓名及平均成绩。
3,即学过1号课程又学过2号课所有学生的姓名。
请用标准SQL语言写出答案,方言也行(请说明是使用什么方言)

首先将三张表创建出来:
CREATE TABLE SC
(
  SNO      VARCHAR(200),
  CNO      VARCHAR(200),
  SCGRADE  VARCHAR(200)
);

CREATE TABLE S
(
  SNO    VARCHAR(200 ),
  SNAME  VARCHAR(200)
);

CREATE TABLE C
(
  CNO       VARCHAR(200),
  CNAME     VARCHAR(200),
  CTEACHER  VARCHAR(200)
);

INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '1', '语文', '张'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '2', '政治', '王'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '3', '英语', '李'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '4', '数学', '赵'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '5', '物理', '黎明'); 
commit;
 
INSERT INTO S ( SNO, SNAME ) VALUES ( '1', '学生1'); 
INSERT INTO S ( SNO, SNAME ) VALUES ( '2', '学生2'); 
INSERT INTO S ( SNO, SNAME ) VALUES ( '3', '学生3'); 
INSERT INTO S ( SNO, SNAME ) VALUES ( '4', '学生4'); 
commit;

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '1', '40'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '2', '30'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '3', '20'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '4', '80'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '5', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '1', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '2', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '3', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '4', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '5', '40'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '1', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '3', '80'); 
commit;

S(SNO,SNAME)代表(学号,姓名)  
C(CNO,CNAME,CTEACHER)代表(课号,课名,教师)
SC(SNO,CNO,SCGRADE)代表(学号,课号,成绩)

select * from s;  //学生表
+------+---------+
| SNO  | SNAME   |
+------+---------+
| 1    | 学生1   |
| 2    | 学生2   |
| 3    | 学生3   |
| 4    | 学生4   |
+------+---------+

select * from c;  //课程表
+------+--------+----------+
| CNO  | CNAME  | CTEACHER |
+------+--------+----------+
| 1    | 语文   | 张       |
| 2    | 政治   | 王       |
| 3    | 英语   | 李       |
| 4    | 数学   | 赵       |
| 5    | 物理   | 黎明     |
+------+--------+----------+

select * from sc;  //学生选课表
+------+------+---------+
| SNO  | CNO  | SCGRADE |
+------+------+---------+
| 1    | 1    | 40      |
| 1    | 2    | 30      |
| 1    | 3    | 20      |
| 1    | 4    | 80      |
| 1    | 5    | 60      |
| 2    | 1    | 60      |
| 2    | 2    | 60      |
| 2    | 3    | 60      |
| 2    | 4    | 60      |
| 2    | 5    | 40      |
| 3    | 1    | 60      |
| 3    | 3    | 80      |
+------+------+---------+


问题1:找出没选过“黎明”老师的所有学生姓名
//第一步:找出黎明老师所教课的课编号
select cno from c where cteacher = '黎明';
+------+
| cno  |
+------+
| 5    |
+------+

//第二步:找出哪些学生上过黎明老师的课
 select 
 	sno 
 from 
 	sc 
 where 
 	cno = ( select cno from c where cteacher = '黎明');
+------+
| sno  |
+------+
| 1    |
| 2    |
+------+

//第三步:没上过黎明老师的课的学生
select 
	sname 
from 
	s 
where 
	sno not in(select sno from sc where cno = ( select cno from c where cteacher = '黎明'));
+---------+
| sname   |
+---------+
| 学生3   |
| 学生4   |
+---------+


问题2:列出2门以上(含2门)不及格学生姓名及平均成绩。
//a表 平均成绩
select sno,avg(scgrade) as avgsal from sc group by sno;
+------+--------+
| sno  | avgsal |
+------+--------+
| 1    |     46 |
| 2    |     56 |
| 3    |     70 |
+------+--------+

//b表 2门以上(含2门)不及格学生姓名
select 
	s1.sno,s1.sname 
from 
	s s1 
join 
	(select sno,count(sno) as lowcount from sc where scgrade < 60 group by sno) t 
on 
	s1.sno = t.sno and t.lowcount >= 2;
+------+---------+
| sno  | sname   |
+------+---------+
| 1    | 学生1   |
+------+---------+

//a表b表连接
select 
	b.sname,a.avgsal 
from 
	(select sno,avg(scgrade) as avgsal from sc group by sno) a 
join 
	(select s1.sno,s1.sname from s s1 join (select sno,count(sno) as lowcount from sc where scgrade < 60 group by sno) t on s1.sno = t.sno and t.lowcount >= 2) b 
on 
	a.sno = b.sno;
+---------+--------+
| sname   | avgsal |
+---------+--------+
| 学生1   |     46 |
+---------+--------+


问题3:既学过1号课程又学过2号课所有学生的姓名
//上过1号课程的学生名单
select sno from sc where cno = 1;
+------+
| sno  |
+------+
| 1    |
| 2    |
| 3    |
+------+
3 rows in set (0.00 sec)

//上过2号课程的学生名单
select sno from sc where cno = 2;
+------+
| sno  |
+------+
| 1    |
| 2    |
+------+
2 rows in set (0.00 sec)

//既上过1号课程又上过2号课程的学生名单
select 
	sname 
from 
	s 
where 
	sno in(select sno from sc where cno = 1) and sno in(select sno from sc where cno = 2);
+---------+
| sname   |
+---------+
| 学生1   |
| 学生2   |
+---------+

14.列出所有员工及领导的姓名

左外连接(用自连接没有king)
select a.ename as '员工',b.ename as '领导' from emp a left join emp b on a.mgr = b.empno;
+--------+--------+
| 员工   | 领导   |
+--------+--------+
| SMITH  | FORD   |
| ALLEN  | BLAKE  |
| WARD   | BLAKE  |
| JONES  | KING   |
| MARTIN | BLAKE  |
| BLAKE  | KING   |
| CLARK  | KING   |
| SCOTT  | JONES  |
| KING   | NULL   |
| TURNER | BLAKE  |
| ADAMS  | SCOTT  |
| JAMES  | BLAKE  |
| FORD   | JONES  |
| MILLER | CLARK  |
+--------+--------+

15.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称

自连接
emp a 员工表
emp b 领导表

select
	a.ename as '员工',a.hiredate,b.ename as '领导', b.hiredate,d.dname
from
	emp a
join
	emp b
on
	a.mgr = b.empno  //直接上级
join 
	dept d
on
	a.deptno = d.deptno
where
	a.hiredate < b.hiredate;  //早于
	
+--------+------------+--------+------------+------------+
| 员工   | hiredate   | 领导   | hiredate   | dname      |
+--------+------------+--------+------------+------------+
| SMITH  | 1980-12-17 | FORD   | 1981-12-03 | RESEARCH   |
| ALLEN  | 1981-02-20 | BLAKE  | 1981-05-01 | SALES      |
| WARD   | 1981-02-22 | BLAKE  | 1981-05-01 | SALES      |
| JONES  | 1981-04-02 | KING   | 1981-11-17 | RESEARCH   |
| BLAKE  | 1981-05-01 | KING   | 1981-11-17 | SALES      |
| CLARK  | 1981-06-09 | KING   | 1981-11-17 | ACCOUNTING |
+--------+------------+--------+------------+------------+

16.列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门

外连接 emp表和dept表  
同时列出那些没有员工的部门,有NULL得外连接,内连接显示不出没有员工的部门

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 |
+-------+--------+-----------+------+------------+---------+---------+--------+------------+

17.列出至少有5个员工的所有部门

select 
	d.dname,t.count 
from 
	(select e.deptno,count(*) as count from emp e group by e.deptno) t 
join 
	dept d 
on 
	t.deptno = d.deptno and t.count>=5;
	
+----------+-------+
| dname    | count |
+----------+-------+
| RESEARCH |     5 |
| SALES    |     6 |
+----------+-------+

另一种方法:
select deptno from emp group by deptno having count(*)>=5;
+--------+
| deptno |
+--------+
|     20 |
|     30 |
+--------+

18.列出薪金比"SMITH"多的所有员工信息

select sal from emp where ename = 'SMITH';
+--------+
| sal    |
+--------+
| 800.00 |
+--------+

select * from emp where sal>(select sal from emp where ename = 'SMITH');
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  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 |
+-------+--------+-----------+------+------------+---------+---------+--------+

19.列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数

select 
	e.ename,e.job,d.dname,d.deptno
from 
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno 
where 
	e.job = 'CLERK';
+--------+-------+------------+--------+
| ename  | job   | dname      | deptno |
+--------+-------+------------+--------+
| SMITH  | CLERK | RESEARCH   |     20 |
| ADAMS  | CLERK | RESEARCH   |     20 |
| JAMES  | CLERK | SALES      |     30 |
| MILLER | CLERK | ACCOUNTING |     10 |
+--------+-------+------------+--------+

//每个部门的人数?
 select deptno,count(*) as deptcount from emp group by deptno;
+--------+-----------+
| deptno | deptcount |
+--------+-----------+
|     20 |         5 |
|     30 |         6 |
|     10 |         3 |
+--------+-----------+

//两表连接 第一张表t1 第二张表t2
select 
	t1.*,t2.deptcount 
from 
	(select e.ename,e.job,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  | job   | dname      | deptno | deptcount |
+--------+-------+------------+--------+-----------+
| SMITH  | CLERK | RESEARCH   |     20 |         5 |
| ADAMS  | CLERK | RESEARCH   |     20 |         5 |
| JAMES  | CLERK | SALES      |     30 |         6 |
| MILLER | CLERK | ACCOUNTING |     10 |         3 |
+--------+-------+------------+--------+-----------+

20.列出最低薪金大于1500的各种工作及从事此工作的全部雇员人数

select job,min(sal),count(*) from emp group by job having min(sal)>1500;
+-----------+----------+----------+
| job       | min(sal) | count(*) |
+-----------+----------+----------+
| MANAGER   |  2450.00 |        3 |
| ANALYST   |  3000.00 |        2 |
| PRESIDENT |  5000.00 |        1 |
+-----------+----------+----------+
//按照job分组,找出每组中最低薪金min(sal)>1500的,输出job和count(*)条数

21.列出在部门"SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号

//查出部门编号
select deptno from dept where dname = 'SALES';

select ename from emp where deptno = (select deptno from dept where dname = 'SALES);
+--------+
| ename  |
+--------+
| ALLEN  |
| WARD   |
| MARTIN |
| BLAKE  |
| TURNER |
| JAMES  |
+--------+

22.列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,雇员的工资等级

select 
	e.ename as '员工',d.dname,l.ename as '领导',s.grade 
from 
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno 
left join   //内连会失去king,所以左外连
	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) as avgsal 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 |
+--------+------------+--------+-------+

23.列出与"SCOTT"从事相同工作的所有员工及部门名称

select 
	d.dname,e.ename,e.job 
from 
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno 
where 
	job = (select job from emp where ename = 'SCOTT');
+----------+-------+---------+
| dname    | ename | job     |
+----------+-------+---------+
| RESEARCH | SCOTT | ANALYST |
| RESEARCH | FORD  | ANALYST |
+----------+-------+---------+

24.列出薪金等于部门30中员工的薪金的其他员工的姓名和薪金

//部门编号30中的员工薪金
select sal from emp where deptno = 30;
+---------+
| sal     |
+---------+
| 1600.00 |
| 1250.00 |
| 1250.00 |
| 2850.00 |
| 1500.00 |
|  950.00 |
+---------+

第一种:select e.ename,e.sal from emp e join (select sal from emp where deptno = 30) t on e.sal = t.sal and e.deptno<>30;
第二种:
select 
	ename,sal 
from 
	emp 
where 
	sal in(select sal from emp where deptno = 30) and deptno <> 30;
结果是没有

25.列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金.部门名称

//部门30员工的最高薪金
select max(sal) from emp where deptno = 30;
+----------+
| max(sal) |
+----------+
|  2850.00 |
+----------+


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   |
+-------+---------+------------+

26.列出在每个部门工作的员工数量,平均工资和平均服务期限

select deptno,count(*),avg(sal) from emp group by deptno;
+--------+----------+-------------+
| deptno | count(*) | avg(sal)    |
+--------+----------+-------------+
|     20 |        5 | 2175.000000 |
|     30 |        6 | 1566.666667 |
|     10 |        3 | 2916.666667 |
+--------+----------+-------------+

注意:部门40没有人
平均服务期限:服务期限是系统当前时间-入职时间

在mysql中如何计算两个日期的年差,差了多少年?=前一个日期-后一个日期
使用函数TimeStampDiff(间隔类型,前一个日期,后一个日期)
	timestampdiff(YEAR,hiredate,now())
		
	间隔类型:
		SECOND 秒
		MINUTE 分钟
		HOUR 小时
		DAY 天
		WEEK 星期
		MONTH 月
		QUARTER 季度
		YEAR 年
		
select 
	d.deptno,count(e.ename),ifnull(avg(e.sal),0) as avgsal,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;
	
+--------+----------------+-------------+----------------+
| deptno | count(e.ename) | avgsal      | avgservicetime |
+--------+----------------+-------------+----------------+
|     10 |              3 | 2916.666667 |        40.0000 |
|     20 |              5 | 2175.000000 |        37.8000 |
|     30 |              6 | 1566.666667 |        40.0000 |
|     40 |              0 |    0.000000 |         0.0000 |
+--------+----------------+-------------+----------------+

//因为部门40没人,但要把部门40带上,就要使用右外连接,否则看不到部门40这条数据
ifnull(可能为null的字段,若为null设置为什么)

注意:count(*) 代表的是有几条数据(可能=要统计的个数,也可能不等于)
比如此题要统计每个部门的员工数目,40部门没有员工
使用count(*) 显示为1,有一条数据但不代表有一个员工
所以这里不能使用count(*),要使用count(e.ename)

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 |
+--------+------------+---------+

28.列出所有部门的详细信息和人数

select 
	d.deptno,d.dname,d.loc,count(e.ename) 
from 
	emp e 
right join 
	dept d 
on 
	e.deptno = d.deptno 
group by 
	d.deptno,d.dname,d.loc;  //按照这三个字段分组,select后面就可以写这三个字段
+--------+------------+----------+----------------+
| deptno | dname      | loc      | count(e.ename) |
+--------+------------+----------+----------------+
|     10 | ACCOUNTING | NEW YORK |              3 |
|     20 | RESEARCH   | DALLAS   |              5 |
|     30 | SALES      | CHICAGO  |              6 |
|     40 | OPERATIONS | BOSTON   |              0 |
+--------+------------+----------+----------------+

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 |
+--------+-----------+---------+

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 |
+--------+----------+

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 |
+--------+----------+

32.求出员工领导的薪水超过3000的员工名称与领导名称

自连接:emp a员工表  emp b领导表
将a表看作是员工表,b表看作是领导表
输出员工名和领导名即:a.ename,b.ename
a表和b表的关系就是员工领导关系,所以on后面写:a.mgr = b.empno a表中的员工是b表中的领导
条件是领导的薪水>3000,即b.sal>3000

select 
	a.ename as '员工',b.ename as '领导' 
from 
	emp a 
join 
	emp b 
on 
	a.mgr = b.empno 
where 
	b.sal>3000;
+-------+-------+
| 员工  |  领导  |
+-------+-------+
| JONES | KING  |
| BLAKE | KING  |
| CLARK | KING  |
+-------+-------+

33.求出部门名称中,带’S’字符的部门员工的工资合计、部门人数

select 
	d.deptno,d.dname,d.loc,count(e.ename),ifnull(sum(e.sal),0) as sumsal
from 
	emp e 
right join   //右外连接,否则部门40的数据被舍去
	dept d 
on 
	e.deptno=d.deptno 
where 
	d.dname like '%S%'   //部门名称中带'S'字符
group by 
	d.deptno,d.dname,d.loc;
//按照d.deptno,d.dname,d.loc分组,分组之后查出来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 |
+--------+------------+---------+----------------+----------+

34.给任职日期超过30年的员工加薪10%

update emp set sal = sal*1.1 where timestampdiff(YEAR,hiredate,now())>30;

select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  880.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1760.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1375.00 |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 3272.50 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1375.00 | 1400.00 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 3135.00 |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2695.00 |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3300.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5500.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1650.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1210.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 | 1045.00 |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3300.00 |    NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1430.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+

注:该文章部分转载自动力节点

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