mysql数据库

1、学习方法

模仿优秀的代码思想,写出自己的代码解释,关掉模仿代码,自己按照自己解释的思路去实现。

2、安装MySQL数据库管理系统

* ip : 计算机在网络中的唯一标识
* port : 计算机当中某个服务的唯一标识

正常情况下MySQL端口号:3306

* MySQL字符集统一设置为:UTF-8编码
* UTF-8: Unicode编码的一种具体实现(Java语言采用的是unicode编码)

* 指定MySQL的service name : 默认是MySQL(该服务的端口:3306)

* 最好自动配置环境变量PATH=C:Program Files (x86)MySQLMySQL Server 5.5in

* 指定用户名和密码:
	MySQL管理员用户名:root
	我们这里MySQL的密码统一:root

* 卸载:
	- 找到安装程序,运行:remove
	- 删除:C:Program Files (x86)MySQL
	- 删除:C:Program DataMySQL(这是一个隐藏文件夹)

3、关于数据库相关的术语:

* 什么是数据库?

	* 数据库当然就是存储数据的仓库,数据库的英文单词:DataBase,简称DB

	* 存储在数据库当中的数据当关闭计算机,再重新打开的时候数据库当中的数据不会丢失,
	可见,数据库实际上也是一个硬盘上的文件。

	* 只不过数据库文件中存储的数据具有一定的规则,可以很好被数据库管理系统进行操作。

* 什么是数据库管理系统?
	
	* 数据库管理系统英文单词:DataBase Management System,简称:DBMS

	* MySQL严格意义上来说,不能把MySQL叫做数据库,实际上MySQL这个软件是一个DBMS。

	* DBMS是管理DB的。

	* 常见的DBMS有哪些?
		Oracle
		DB2
		MySQL
		SqlServer
		Sybase
		......
	
	* 在MySQL数据库管理系统当中可以创建数据库DB,在数据库当中可以创建表table,
	然后在table当中存储数据,DBMS操作DB当中table里面的数据。

* 什么是SQL?
	* SQL是一种语言,是一种标准通用的结构化查询语言。
	* SQL这种语言由程序员来编写。程序员编写SQL语句,DBMS
	先将SQL语言进行编译,然后DBMS执行SQL语句,通过执行SQL
	语句来对数据库表当中的数据进行:增删改查操作。

* DBMS DB SQL之间的关系?
	DBMS --> SQL --> DB

* SQL语句大部分是通用的,但是每个数据库都有自己的特色,所以说SQL不是百分百通用。
但是在开发当中,java程序编写的SQL语句最好是标准通用的。why? 数据库可移植

4、关于表格table

* 数据库当中最基本的单元是表格,数据库采用表格进行数据组织。因为表格比较直观

* 表格由行和列组成

* 每一列(column)我们可以成为字段(field)

* 每一行就是数据(主要是对这些数据进行增删改查)

* 以下是一个表格:
	name	age	grade	
	-------------------------
	张三	20	本科
	张三	20	本科
	张三	20	本科
	张三	20	本科
	张三	20	本科

* 姓名是一个字段,该字段当中所有的数据都表示一个人的名字。

* 每一个字段包括哪些属性呢?
	- 每一个字段都有数据类型(后面详细讲解)
	- 每一个字段都有名字
	- 每一个字段都有约束(后面讲解)

* 目前只提出几个常用的数据类型:
	- varchar	字符串(可变长)(String)
	- char		字符串(定长)(String)
	- int		整数型(int)
	- bigint	长整型(long)
	- date		日期类型(java.sql.Date)

	int(4)		后面的数字是长度,表示最大值9999
	varchar(10)
	date
	double(7,2)

5、我们重点学习的是MySQL当中的SQL语句,为了方便大家的记忆,将SQL语句进行了分类:

* DQL
	数据查询语言(带有select关键字的SQL语句,专门用来查询数据的SQL语句)
* DML
	数据操作语言(带有insert delete update关键字的SQL语句,专门用来完成数据库
	表中数据的增删改操作的SQL语句)
* DDL
	数据定义语言(带有create alter关键字的SQL语句,专门完成对表结构进行增删改的
	SQL语句。)
* DCL
	数据控制语言(带有grant:授权 revoke:撤销权限 关键字的SQL语句,专门完成数据库用户
	的授权操作的SQL语句)
* TCL
	事务控制语言(带有commit rollback关键字的SQL语句,表示事务提交和回滚)

6、登录MySQL:

* 打开DOS命令窗口

* mysql -uroot -proot
	出现:mysql > 表示登录成功

* 退出mysql:exit/quit

7、在MySQL当中常用的SQL语句:

* 创建数据库
	create database bjpowernode;
	表示创建一个数据库,起名bjpowernode

* 查看当前有哪些数据库?
	show databases;

* 默认情况下MySQL提供了四个数据库?
	+--------------------+
	| Database           |
	+--------------------+
	| information_schema |
	| mysql              |
	| performance_schema |
	| test               |
	+--------------------+

* 使用数据库
	use bjpowernode;

* 查看当前使用的是哪个数据库?
	mysql> select database();
	+-------------+
	| database()  |
	+-------------+
	| bjpowernode |
	+-------------+
	1 row in set (0.00 sec)

* 删除数据库:
	drop database mydb;

* 查看当前数据库下有哪些表?
	show tables;

* 

8、常见命令:

* 查看mysql版本:
	C:UsersAdministrator>mysql --version
	mysql  Ver 14.14 Distrib 5.5.36, for Win32 (x86)

* c 终止一条SQL语句的编写

* 执行SQL脚本的命令:
	source SQL脚本文件路径

* 查看表结构
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    |       |
+--------+-------------+------+-----+---------+-------+

9、学习使用的数据库表以及数据初始化到数据库当中:

* mysql > create database bjpowernode;
* mysql > use bjpowernode;
* mysql> source D:course4-MySQLdocumentjpowernode.sql

bjpowernode.sql这种扩展名以.sql结尾的文件称为:SQL脚本
SQL脚本中有大量的SQL语句,执行SQL脚本文件就相当于批量执行SQL语句。

10、查看表格中所有的数据?

mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
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 salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+

11、简单查询(从这里开始正式学习DQL语句的编写)

* SQL语句尤其是DQL语句最为重要,负责查询/检索表当中的数据,并且将查询结果输出到控制台

* SQL术语高级编程语言,要执行也需要提前先编译才能执行,DBMS负责编译并且执行

* SQL语句以";"结尾

* SQL语句不区分大小写,随意(注意:数据库表当中存储的ABC和abc是不一样的,因为这是具体的数值)

* SQL语句也是由很多关键字组成的:
	select 查询
	from	从哪里

* 最简单的DQL语句语法结构:
	select 
		字段名
	from
		表名

* 查询一个字段
	select empno from emp;
	select ename from emp;

* 查询多个字段(字段之间使用逗号隔开)
	select empno,ename from emp;

* 查询所有字段

	select empno,ename,job,mgr,sal,comm,deptno,hiredate from emp;
	select * from emp;

	使用“*”有两个缺点:
		- 可读性差
		- 在编译的时候,DBMS会将*转换成字段,效率低
	使用“*”的优点:
		- 快速编写

* 查询员工的年薪
	mysql> select empno,ename,sal*12 from emp;
	+-------+--------+-----------+
	| empno | ename  | sal*12    |
	+-------+--------+-----------+
	|  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 |
	|  7999 | BOSS   | 120000.00 |
	+-------+--------+-----------+
	说明:字段可以参与数学运算

* 别名
	select empno,ename,sal*12 as 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 |
	|  7999 | BOSS   | 120000.00 |
	+-------+--------+-----------+
	select empno,ename,sal*12 as 年薪 from emp; //报错(别名中文必须用单引号括起来)
	select empno,ename,sal*12 as '年薪' from emp;  //这个标准的,字符串使用单引号括起来
	select empno,ename,sal*12 as "年薪" from emp;  // mysql特有的,字符串可以使用双引号括起来

	注意:MySQL当中的字符串使用单引号或者双引号括起来,但是对于标准的SQL语句来说,
	只能使用单引号。尤其是在Oracle数据库当中,字符串绝对不允许使用双引号,只能使用
	单引号,所以以后为了SQL语句的通用性,建议字符串使用单引号括起来。

	注意:MySQL的语法松散,不严格,Oracle的语法非常严格。

	注意:别名 as 关键字可以省略。

12、条件查询

* 什么是条件查询?
	查询语句当没有条件的时候会将表当中所有的数据全部检索出来。
	但是大多数情况下我们可能只需要找到符合某个条件的记录,此时
	使用条件查询。

* 条件查询的语法格式:
	select 
		字段名,字段名,...
	from
		表名
	where
		条件
	
	以上SQL语句的执行顺序是什么?
		先执行from后面的
		再执行where后面的
		最后执行select

* 都有哪些条件?
	=
	<> 或 !=
	<
	<=
	>
	>=
	between...and...
	is null/is not null
	and
	or
	and和or的优先级
	in
	not in
	like

	ifnull(可能为NULL的字段,具体值)函数

* = (找出薪资等于5000的员工)
	select empno,ename,sal from emp where sal = 5000;
	select empno,ename,sal from emp where sal = '5000';
	+-------+-------+---------+
	| empno | ename | sal     |
	+-------+-------+---------+
	|  7839 | KING  | 5000.00 |
	+-------+-------+---------+

* = (找出员工SMITH的编号和月薪)
	select empno,sal from emp where ename = 'SMITH';
	select empno,sal from emp where ename = "SMITH"; //不建议
	select empno,sal from emp where ename = 'smith'; //在mysql当中可以,在oracle中不可以
	+-------+--------+
	| empno | sal    |
	+-------+--------+
	|  7369 | 800.00 |
	+-------+--------+

	SQL语句不区分大小写,但是数据库表中具体存储的值,是大写就是大写,
	是小写就是小写,严格区分大小写,这是针对于表中具体存储的值。
	但是在mysql当中语法松散,mysql认为'smith'和'SMITH'一样。
	在Oracle数据库当中'smith'和'SMITH'完全不同。

* <> 或者 != (找出工资不是5000的员工)
	select empno,ename,sal from emp where sal <> 5000;
	+-------+--------+----------+
	| empno | ename  | sal      |
	+-------+--------+----------+
	|  7369 | SMITH  |   800.00 |
	|  7499 | ALLEN  |  1600.00 |
	|  7521 | WARD   |  1250.00 |
	|  7566 | JONES  |  2975.00 |
	|  7654 | MARTIN |  1250.00 |
	|  7698 | BLAKE  |  2850.00 |
	|  7782 | CLARK  |  2450.00 |
	|  7788 | SCOTT  |  3000.00 |
	|  7844 | TURNER |  1500.00 |
	|  7876 | ADAMS  |  1100.00 |
	|  7900 | JAMES  |   950.00 |
	|  7902 | FORD   |  3000.00 |
	|  7934 | MILLER |  1300.00 |
	|  7999 | BOSS   | 10000.00 |
	+-------+--------+----------+

* < <= > >=
	select empno,ename,sal from emp where sal < 3000;
	select empno,ename,sal from emp where sal <= 3000;
	select empno,ename,sal from emp where sal > 3000;
	select empno,ename,sal from emp where sal >= 3000;

	mysql> select empno,ename,sal,hiredate from emp where hiredate > '1981-05-05';
	+-------+--------+---------+------------+
	| empno | ename  | sal     | hiredate   |
	+-------+--------+---------+------------+
	|  7654 | MARTIN | 1250.00 | 1981-09-28 |
	|  7782 | CLARK  | 2450.00 | 1981-06-09 |
	|  7788 | SCOTT  | 3000.00 | 1987-04-19 |
	|  7839 | KING   | 5000.00 | 1981-11-17 |
	|  7844 | TURNER | 1500.00 | 1981-09-08 |
	|  7876 | ADAMS  | 1100.00 | 1987-05-23 |
	|  7900 | JAMES  |  950.00 | 1981-12-03 |
	|  7902 | FORD   | 3000.00 | 1981-12-03 |
	|  7934 | MILLER | 1300.00 | 1982-01-23 |
	+-------+--------+---------+------------+

* between ... and ... (闭区间,左和右都是包含)

	select empno,ename,sal from emp where sal between 3000 and 5000;
	mysql> select empno,ename,sal from emp where sal between 950 and 5000;
	+-------+--------+---------+
	| empno | ename  | sal     |
	+-------+--------+---------+
	|  7499 | ALLEN  | 1600.00 |
	|  7521 | WARD   | 1250.00 |
	|  7566 | JONES  | 2975.00 |
	|  7654 | MARTIN | 1250.00 |
	|  7698 | BLAKE  | 2850.00 |
	|  7782 | CLARK  | 2450.00 |
	|  7788 | SCOTT  | 3000.00 |
	|  7839 | KING   | 5000.00 |
	|  7844 | TURNER | 1500.00 |
	|  7876 | ADAMS  | 1100.00 |
	|  7900 | JAMES  |  950.00 |
	|  7902 | FORD   | 3000.00 |
	|  7934 | MILLER | 1300.00 |
	+-------+--------+---------+

	mysql> select empno,ename,sal from emp where sal between 5000 and 3000;
	Empty set (0.00 sec)

	说明(必须的):between 小 and 大

	只能用在数值方面吗?不是,可以使用在字符方面,但是字符左闭右开
	select ename from emp where ename between 'A' and 'C';
	select ename from emp where ename between 'A' and 'K';

	between .. and ..等同于:>= and <=

	and 表示:并且

* is null(在SQL语句方面,判断某个数据是否为空,不能用“=”,只能用is null / is not null)
	mysql> select empno,ename,sal,comm from emp where comm = null;
	Empty set (0.00 sec)

	mysql> select empno,ename,sal,comm from emp where comm is null;
	+-------+--------+---------+------+
	| empno | ename  | sal     | comm |
	+-------+--------+---------+------+
	|  7369 | SMITH  |  800.00 | NULL |
	|  7566 | JONES  | 2975.00 | NULL |
	|  7698 | BLAKE  | 2850.00 | NULL |
	|  7782 | CLARK  | 2450.00 | NULL |
	|  7788 | SCOTT  | 3000.00 | NULL |
	|  7839 | KING   | 5000.00 | NULL |
	|  7876 | ADAMS  | 1100.00 | NULL |
	|  7900 | JAMES  |  950.00 | NULL |
	|  7902 | FORD   | 3000.00 | NULL |
	|  7934 | MILLER | 1300.00 | NULL |
	+-------+--------+---------+------+

	在SQL语句当中NULL这种数据代表什么也没有,真正的空,不是一个值,所以不能用“=”
	“=”只能判断值是否相等。所以MYSQL当中判断是否等于空必须使用:is null

	NULL和0.0不同:NULL代表什么也没有,0.0代表数字0

* is not null 不为空
	找出补助不为空的员工
	select empno,ename,sal,comm from emp where comm is not null;
	+-------+--------+---------+---------+
	| empno | ename  | sal     | comm    |
	+-------+--------+---------+---------+
	|  7499 | ALLEN  | 1600.00 |  300.00 |
	|  7521 | WARD   | 1250.00 |  500.00 |
	|  7654 | MARTIN | 1250.00 | 1400.00 |
	|  7844 | TURNER | 1500.00 |    0.00 |
	+-------+--------+---------+---------+

* and 和 or
	and 并且
	or  或者

	找出20部门中工资大于2000的员工
	select empno,ename,sal,deptno from emp where deptno = 20 and sal > 2000;

	mysql> select empno,ename,sal,deptno from emp where deptno = 20 or sal > 2000;
	+-------+-------+---------+--------+
	| empno | ename | sal     | deptno |
	+-------+-------+---------+--------+
	|  7369 | SMITH |  800.00 |     20 |
	|  7566 | JONES | 2975.00 |     20 |
	|  7698 | BLAKE | 2850.00 |     30 |
	|  7782 | CLARK | 2450.00 |     10 |
	|  7788 | SCOTT | 3000.00 |     20 |
	|  7839 | KING  | 5000.00 |     10 |
	|  7876 | ADAMS | 1100.00 |     20 |
	|  7902 | FORD  | 3000.00 |     20 |
	+-------+-------+---------+--------+

	找出从事工作岗位是MANAGER和SALESMAN的员工
	select empno,ename,job from emp where job = 'MANAGER' or job = 'SALESMAN'; 
	select empno,ename,job from emp where job in('MANAGER','SALESMAN');
	+-------+--------+----------+
	| empno | ename  | job      |
	+-------+--------+----------+
	|  7499 | ALLEN  | SALESMAN |
	|  7521 | WARD   | SALESMAN |
	|  7566 | JONES  | MANAGER  |
	|  7654 | MARTIN | SALESMAN |
	|  7698 | BLAKE  | MANAGER  |
	|  7782 | CLARK  | MANAGER  |
	|  7844 | TURNER | SALESMAN |
	+-------+--------+----------+
	select empno,ename,sal from emp where sal in(950,3000); //in(这里是每一个具体的值,不表示区间)
	select empno,ename,sal from emp where sal = 950 or sal = 3000;

	关于优先级:and比or优先级高
	查询薪水大于1800,并且部门代码为20或30的员工
	错误的写法:
	select ename,sal,deptno from emp where sal > 1800 and deptno = 20 or deptno = 30;
	错误的写法:
	select ename,sal,deptno from emp where (sal > 1800 and deptno = 20) or deptno = 30;
	正确的写法:
	select ename,sal,deptno from emp where sal > 1800 and (deptno = 20 or deptno = 30);

* in 和 not in
	select ename,sal from emp where sal not in(3000,5000);
	select ename,sal from emp where sal <> 3000 and sal <> 5000;

	select ename,sal from emp where sal = 3000 or sal = 5000;
	select ename,sal from emp where sal in(3000,5000);

* 空值处理函数(ifnull函数,用法ifnull(可能为空的字段,具体的值))
	要求显示所有员工的薪水和补助,补助为空的显示为0
	select ename,sal,comm from emp;
	select ename,sal,ifnull(comm,0) as comm from emp;

	注意:在MySQL当中,只要有NULL参与运算,结果一定是NULL
	要求计算所有员工的年薪(年薪=(月薪+月补助)*12)
	mysql> select ename,(sal+comm)*12 as yearsal from emp;
	+--------+----------+
	| ename  | yearsal  |
	+--------+----------+
	| SMITH  |     NULL |
	| ALLEN  | 22800.00 |
	| WARD   | 21000.00 |
	| JONES  |     NULL |
	| MARTIN | 31800.00 |
	| BLAKE  |     NULL |
	| CLARK  |     NULL |
	| SCOTT  |     NULL |
	| KING   |     NULL |
	| TURNER | 18000.00 |
	| ADAMS  |     NULL |
	| JAMES  |     NULL |
	| FORD   |     NULL |
	| MILLER |     NULL |
	+--------+----------+
	14 rows in set (0.00 sec)

	mysql> select ename,(sal + ifnull(comm,0))*12 as yearsal from emp;
	+--------+----------+
	| ename  | yearsal  |
	+--------+----------+
	| SMITH  |  9600.00 |
	| ALLEN  | 22800.00 |
	| WARD   | 21000.00 |
	| JONES  | 35700.00 |
	| MARTIN | 31800.00 |
	| BLAKE  | 34200.00 |
	| CLARK  | 29400.00 |
	| SCOTT  | 36000.00 |
	| KING   | 60000.00 |
	| TURNER | 18000.00 |
	| ADAMS  | 13200.00 |
	| JAMES  | 11400.00 |
	| FORD   | 36000.00 |
	| MILLER | 15600.00 |
	+--------+----------+
	14 rows in set (0.00 sec)


* like:模糊查询
	%和_
	%代表任意多个字符
	_代表任意一个字符

	要求找出所有员工姓名以S开始的
	select ename from emp where ename like 'S%';

	要求找出所有员工姓名中含有O的
	select ename from emp where ename like '%O%';

	要求找出所有员工姓名中第二个字母是A的
	select ename from emp where ename like '_A%';

	作业:要求找出所有商品名称中第二个字母是“_”的??????

* 注意:所有的DQL语句只是将数据查询并显示,不会修改数据库当中的任何数据。

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

* 指定以升序的方式排列
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 2;
select ename,sal from emp order by 1;
select ename,sal from emp order by 1 desc;

select * from emp order by 6;

* 按照工资升序排列,工资相同的话再按照姓名降序排列
select ename,sal from emp order by sal asc , ename desc; //当工资sal不同的时候,ename不会起作用

14、总结:简单查询、条件查询、排序

select
	...
from
	...
where
	...
order by
	...

执行顺序:
	先from
	再where
	再select
	最后order by

题目:找出工作岗位是MANAGER的员工,并且按照其工资降序排序
select 
	ename,job,sal 
from 
	emp 
where 
	job = 'MANAGER' 
order by 
	sal desc;

select 
	ename,job,sal as yuexin 
from 
	emp 
where 
	job = 'MANAGER' 
order by 
	yuexin desc;

15、数据处理函数/单行处理函数(MySQL特有的,不具备通用性,可能个别函数具有通用性)

* lower 转换为小写
	select ename from emp;
	mysql> select lower(ename) as ename from emp;
	+--------+
	| ename  |
	+--------+
	| smith  |
	| allen  |
	| ward   |
	| jones  |
	| martin |
	| blake  |
	| clark  |
	| scott  |
	| king   |
	| turner |
	| adams  |
	| james  |
	| ford   |
	| miller |
	+--------+

* upper 转换为大写
	mysql> select upper('abc');
	+--------------+
	| upper('abc') |
	+--------------+
	| ABC          |
	+--------------+

* substr(被截取的字符串,开始下标,长度) 开始下标从1开始
	mysql> select substr('abcdeffdsafdsafdasfdsafdas',6,2) as ename;
	+-------+
	| ename |
	+-------+
	| ff    |
	+-------+

* length
	select length(ename) as enamesize from emp;
	+-----------+
	| enamesize |
	+-----------+
	|         5 |
	|         5 |
	|         4 |
	|         5 |
	|         6 |
	|         5 |
	|         5 |
	|         5 |
	|         4 |
	|         6 |
	|         5 |
	|         5 |
	|         4 |
	|         6 |
	+-----------+
* trim
	select trim('          abc def            ');
	select concat('--',trim('          abc def            '),'--')
* concat
	mysql> select concat('abc','def','test');
	+----------------------------+
	| concat('abc','def','test') |
	+----------------------------+
	| abcdeftest                 |
	+----------------------------+
* round
	mysql> select round(123.456);
	+----------------+
	| round(123.456) |
	+----------------+
	|            123 |
	+----------------+

	select round(123.456,0);
	select round(123.456,1);
	select round(123.456,2);
	select round(123.456,-1);
	select round(125.456,-1);

* rand()
	select rand();

* case.. when.. then.. when.. then.. when.. then.. else.. end

需求:查询每个员工的薪水,MANAGER岗位工资上调10%,SALESMAN岗位工资上调20%,其他员工照旧。

select 
	ename,job,sal,
	(case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.2 else sal end) newsal 
from 
	emp;

* ifnull

* now()
	mysql> select now();
	+---------------------+
	| now()               |
	+---------------------+
	| 2017-04-28 14:49:57 |
	+---------------------+

* str_to_date
	
	* str_to_date函数的作用:将字符串日期转换成日期类型的数据(varchar --> date)

	* varchar是字符串类型,date是日期类型

	* str_to_date函数的语法格式:
		str_to_date('字符串日期','日期格式')
		整体的运算结果是date类型

	* 日期格式怎么写?
		Java中的日期格式:
			yyyy
			MM
			dd
			HH
			mm
			ss
			SSS

		MySQL中的日期格式:
			%Y	年(四位) %y(两位年)
			%m	月
			%d	日
			%H	时
			%i	分
			%s	秒
		
	* str_to_date函数主要使用在哪里?

		create table t_student(
			name varchar(32),
			birth date
		);

		mysql> insert into t_student(name,birth) values('jack','10-08-2017'); //失败
		ERROR 1292 (22007): Incorrect date value: '10-08-2017' for column 'birth' at row 1

		insert into t_student(name,birth) values('jack',str_to_date('10-08-2017','%d-%m-%Y')); //成功

		注意:当日期格式是%Y-%m-%d的时候,字符串varchar会自动转换成date
		mysql> insert into t_student(name,birth) values('jack','2017-08-10');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_student(name,birth) values('jack',str_to_date('2017-08-10','%Y-%m-%d'));

		说明mysql默认的日期格式:%Y-%m-%d

		主要用在哪里?
			当数据库表中某个字段的数据类型是date的时候,
			我们不能将一个字符串直接插入到这个字段上,
			这个时候需要手动调用str_to_date函数将其转换
			成date类型再插入数据。

			除非你给定的日期字符串的格式符合'%Y-%m-%d',这个会自动类型转换。


* date_format
	
	* date_format 日期格式化函数,可以将日期类型date转换成具有某个特定格式的日期字符串varchar

	* date_format函数语法格式:

		date_format(日期类型的数据,'日期格式')
		该函数的运算结果是varchar类型
	
	* date_format通常使用在select语句当中?展示日期的时候使用最多。
		需求:要求查询每个员工的雇佣日期,最终显示格式:月-日-年
		select ename,date_format(hiredate,'%m-%d-%Y') as hiredate from emp;

		mysql> select ename,hiredate from emp;
		mysql> select ename,date_format(hiredate,'%Y-%m-%d') as hiredate from emp;
		+--------+------------+
		| ename  | hiredate   |
		+--------+------------+
		| SMITH  | 1980-12-17 |
		| ALLEN  | 1981-02-20 |
		| WARD   | 1981-02-22 |
		| JONES  | 1981-04-02 |
		| MARTIN | 1981-09-28 |
		| BLAKE  | 1981-05-01 |
		| CLARK  | 1981-06-09 |
		| SCOTT  | 1987-04-19 |
		| KING   | 1981-11-17 |
		| TURNER | 1981-09-08 |
		| ADAMS  | 1987-05-23 |
		| JAMES  | 1981-12-03 |
		| FORD   | 1981-12-03 |
		| MILLER | 1982-01-23 |
		+--------+------------+
	
	select date_format(now(),'%y');

	mysql> select date_format(now(),'%Y-%m-%d %H:%i:%s');
	+----------------------------------------+
	| date_format(now(),'%Y-%m-%d %H:%i:%s') |
	+----------------------------------------+
	| 2017-04-28 15:58:15                    |
	+----------------------------------------+

* format
	(数字格式化使用的函数:可以将某个数字进行格式之后展示,10000(数字)格式化之后:10,000(字符串))
	自己研究

* 回顾Java中日期格式化:
	
	java.util.Date ---> java.lang.String

	Date nowTime = new Date();
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
	String strTime = sdf.format(nowTime);
	System.out.println(strTime);

	java.lang.String ---> java.util.Date

	String strTime = "1970-10-11";
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	Date time = sdf.parse(strTime);

16、分组函数/多行处理函数:

* count	统计总数
	select count(ename) from emp;

* sum	求和
	select sum(sal) from emp;

* avg	平均数
	select avg(sal) from emp;

* max	最大值
	select max(sal) from emp;

* min	最小值
	select min(sal) from emp;

* 注意:分组函数自动忽略NULL

* mysql> select count(comm) from emp;
+-------------+
| count(comm) |
+-------------+
|           4 |
+-------------+
以上语句的含义:统计comm字段中不是NULL的总数量

* mysql> select count(*) from emp;
+----------+
| count(*) |
+----------+
|       14 |
+----------+

count(具体字段)和count(*)的区别?
	count(具体字段):该字段当中不为NULL的总数量
	count(*):符合条件的“当前组”的记录行总数

	count(*)不针对某个字段,只统计总行数

* 先记住:分组函数不能直接使用到where条件当中(讲完group by之后可以解释)
	找出公司中薪水高于平均薪水的员工?
	mysql> select ename,sal from emp where sal > avg(sal);
	ERROR 1111 (HY000): Invalid use of group function

* distinct函数:去除重复记录
	mysql> select job from emp;
	+-----------+
	| job       |
	+-----------+
	| CLERK     |
	| SALESMAN  |
	| SALESMAN  |
	| MANAGER   |
	| SALESMAN  |
	| MANAGER   |
	| MANAGER   |
	| ANALYST   |
	| PRESIDENT |
	| SALESMAN  |
	| CLERK     |
	| CLERK     |
	| ANALYST   |
	| CLERK     |
	+-----------+

	mysql> select distinct job from emp;
	+-----------+
	| job       |
	+-----------+
	| CLERK     |
	| SALESMAN  |
	| MANAGER   |
	| ANALYST   |
	| PRESIDENT |
	+-----------+

	select count(distinct job) as total from emp;
	+-------+
	| total |
	+-------+
	|     5 |
	+-------+
	
	select ename,distinct job from emp; //语法错误(ename数量和去除重复的job数量不同)

	//语法:distinct只能出现在所有字段的最前面
	//以下语法什么含义:ename+job两个字段联合起来去除重复记录
	select distinct ename,job from emp; 

	mysql> select deptno,job from emp;
	+--------+-----------+
	| deptno | job       |
	+--------+-----------+
	|     20 | CLERK     |
	|     30 | SALESMAN  |
	|     30 | SALESMAN  |
	|     20 | MANAGER   |
	|     30 | SALESMAN  |
	|     30 | MANAGER   |
	|     10 | MANAGER   |
	|     20 | ANALYST   |
	|     10 | PRESIDENT |
	|     30 | SALESMAN  |
	|     20 | CLERK     |
	|     30 | CLERK     |
	|     20 | ANALYST   |
	|     10 | CLERK     |
	+--------+-----------+
	14 rows in set (0.00 sec)

	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     |
	+--------+-----------+
	9 rows in set (0.00 sec)

* 分组函数可以联合起来用:
	select count(*),sum(sal),max(sal),min(sal),avg(sal) from emp;
	+----------+----------+----------+----------+-------------+
	| count(*) | sum(sal) | max(sal) | min(sal) | avg(sal)    |
	+----------+----------+----------+----------+-------------+
	|       14 | 29025.00 |  5000.00 |   800.00 | 2073.214286 |
	+----------+----------+----------+----------+-------------+

1、关于分组查询:

* group by
* having

2、关于group by

* group by : 表示通过某个字段或者某些字段进行分组

3、取得每个工作岗位的工资合计,要求显示岗位名称和工资合计

mysql> select sum(sal) from emp; //所有员工的工资合计(没有指定分组,那么emp表所有数据自成一组)
+----------+
| sum(sal) |
+----------+
| 29025.00 |
+----------+

解题思路:先按照工作岗位分组,然后对每一组求工资和
select 
	job,sum(sal) 
from 
	emp 
group by 
	job;

分析以下语句存在的问题?

select 
	ename,job,sum(sal) 
from 
	emp 
group by 
	job;

以上SQL语句,在MySQL当中可以执行,在Oracle数据库当中报错。
Oracle比较严格,MySQL语法松散,其实以上的查询结果即使在MySQL当中可以显示记录,但是记录没有意义。
建议大家最好编写通用的SQL语句,给自己制定一个语法规则:只要DQL语句当中有group by语句,那么select
关键字后面只能是:分组函数或参与分组的字段名称。

4、找出每个工作岗位中最高薪资

select job,max(sal) from emp group by job;
select job,min(sal) from emp group by job;

5、找出每个部门的平均薪资

select deptno , avg(sal) as avgsal from emp group by deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     10 | 2916.666667 |
|     20 | 2175.000000 |
|     30 | 1566.666667 |
+--------+-------------+

6、找出不同部门的每个岗位的平均薪资

select deptno,job,avg(sal) as avgsal from emp group by deptno,job;

7、分析:为什么where子句当中不能直接使用分组函数?

select ...(4)
from...(1)
where..(这里为啥不能直接使用分组函数)..(2)
group by...(3)
order by....(5)

8、找出每个工作岗位的平均薪资,并且要求最终显示平均薪资>2000的数据。

select job,avg(sal) as avgsal from emp group by job;
+-----------+-------------+
| job       | avgsal      |
+-----------+-------------+
| ANALYST   | 3000.000000 |
| CLERK     | 1037.500000 |
| MANAGER   | 2758.333333 |
| PRESIDENT | 5000.000000 |
| SALESMAN  | 1400.000000 |
+-----------+-------------+

mysql> select job,avg(sal) as avgsal from emp where avg(sal) > 2000 group by job;
ERROR 1111 (HY000): Invalid use of group function

当进行分组,然后分组之后对这些数据再次过滤的时候,可以使用having子句
select 
	job,avg(sal) as avgsal 
from 
	emp 
group by 
	job 
having 
	avg(sal) > 2000;

+-----------+-------------+
| job       | avgsal      |
+-----------+-------------+
| ANALYST   | 3000.000000 |
| MANAGER   | 2758.333333 |
| PRESIDENT | 5000.000000 |
+-----------+-------------+

注意:以下语句在ORACLE数据库当中会报错,因为Oracle的语法严格,一定是having先执行,再执行select后面的
select 
	job,avg(sal) as avgsal 
from 
	emp 
group by 
	job 
having 
	avgsal > 2000;

以下是MySQL数据库当中执行的效果:
+-----------+-------------+
| job       | avgsal      |
+-----------+-------------+
| ANALYST   | 3000.000000 |
| MANAGER   | 2758.333333 |
| PRESIDENT | 5000.000000 |
+-----------+-------------+

9、having通常和group by联合使用:

group by 是按照某个或者某些字段分组
having 是过滤条件,但是这个过滤在分组之后再次过滤。

where和having选哪个?怎么选?
	* having离不开group by,having是专门为group by服务的。
	* where可以过滤,having也可以过滤,怎么选择?

案例:找出每个部门最高薪资,除20部门之外

	第一种方案:(先分组,最后过滤)

		select deptno,max(sal) as maxsal from emp group by deptno;
	
		+--------+---------+
		| deptno | maxsal  |
		+--------+---------+
		|     10 | 5000.00 |
		|     20 | 3000.00 |
		|     30 | 2850.00 |
		+--------+---------+

		select deptno,max(sal) as maxsal from emp group by deptno having deptno <> 20;
		+--------+---------+
		| deptno | maxsal  |
		+--------+---------+
		|     10 | 5000.00 |
		|     30 | 2850.00 |
		+--------+---------+

	第二种方案:(先过滤,再分组,此方式效率较高)
		select deptno,max(sal) as maxsal from emp where deptno <> 20 group by deptno;
		+--------+---------+
		| deptno | maxsal  |
		+--------+---------+
		|     10 | 5000.00 |
		|     30 | 2850.00 |
		+--------+---------+
	
案例:找出每个部门平均薪资,要求显示平均薪资高于2000的
	select deptno,avg(sal) as avgsal from emp group by deptno having avg(sal) > 2000;
		
	+--------+-------------+
	| deptno | avgsal      |
	+--------+-------------+
	|     10 | 2916.666667 |
	|     20 | 2175.000000 |
	+--------+-------------+

原则:能够在where条件中过滤的数据尽可能在where中过滤,越早过滤效率越高。
当然,有的情况下必须等待分组之后才能过滤,此时只能使用having...

10、找出除"MANAGER"之外的所有工作岗位的平均薪资,要求平均薪资>2000的,按照平均薪资降序排列。

select 
	job,avg(sal) as avgsal
from
	emp
where
	job <> 'MANAGER'
group by
	job
having
	avg(sal) > 2000
order by
	avgsal desc;

+-----------+-------------+
| job       | avgsal      |
+-----------+-------------+
| PRESIDENT | 5000.000000 |
| ANALYST   | 3000.000000 |
+-----------+-------------+

11、完整的DQL语句执行顺序:

select...(5)
from...(1)
where..(2)
group by..(3)
having..(4)
order by...(6)

-----------------------------------------------------------以上是单表的DQL语句,以下开始进入多表联合查询----------------------------------------------------------

1、连接查询

* 什么是连接查询?
	通常情况下,数据不是存储在一张表当中的,有很多数据是存在关系的,
	例如:一个部门对应多个员工,部门表存储部门,员工表存储员工,那么这个
	时候假设需要查询某个员工的部门信息的话,就需要让员工表和部门表进行
	联合查询,这种多张表联合查询被称为连接查询。

* 连接查询根据语法出现的年代怎么分类?
	SQL92:1992年之后出现的语法
	SQL99:1999年之后出现的语法

* 连接查询根据连接方式怎么分类?

	* 内连接
		- 等值连接
		- 非等值连接
		- 自连接

	* 外连接
		- 左外连接(左连接)
		- 右外连接(右连接)

2、当表进行连接查询的时候,没有任何条件限制的话,会出现什么问题?

t_user1

id name

1 zhangsan
2 lisi
3 wangwu

t_user2

id name

1 jack
2 lucy
3 james

select
u1.id,u1.name,u2.id,u2.name
from
t_user1 u1,t_user2 u2;

id name id name

1 zhangsan 1 jack
1 zhangsan 2 lucy
1 zhangsan 3 james
2 lisi 1 jack
2 lisi 2 lucy
2 lisi 3 james
3 wangwu 1 jack
3 wangwu 2 lucy
3 wangwu 3 james

案例:找出每个员工所在部门,要求显示员工名和部门名
mysql> select ename,deptno from emp;
+--------+--------+
| ename | deptno |
+--------+--------+
| SMITH | 20 |
| ALLEN | 30 |
| WARD | 30 |
| JONES | 20 |
| MARTIN | 30 |
| BLAKE | 30 |
| CLARK | 10 |
| SCOTT | 20 |
| KING | 10 |
| TURNER | 30 |
| ADAMS | 20 |
| JAMES | 30 |
| FORD | 20 |
| MILLER | 10 |
+--------+--------+
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+

好习惯:表别名(这样效率高)emp e , dept d

select
e.ename,d.dname
from
emp e, dept d;

结论:当两张表进行关联查询的时候,没有任何条件限制,那么会发生“笛卡尔积”现象。
所谓的笛卡尔积现象是什么?
最终查询结果记录条数是两张表条数的乘积。(14 * 4 = 56)

怎么避免笛卡尔积现象?添加过滤条件,过滤出合法的记录。

3、内连接

3.1、等值连接
	案例:找出每个员工所在部门,要求显示员工名与对应的部门名
	mysql> select ename,deptno from emp;
	+--------+--------+
	| ename  | deptno |
	+--------+--------+
	| SMITH  |     20 |
	| ALLEN  |     30 |
	| WARD   |     30 |
	| JONES  |     20 |
	| MARTIN |     30 |
	| BLAKE  |     30 |
	| CLARK  |     10 |
	| SCOTT  |     20 |
	| KING   |     10 |
	| TURNER |     30 |
	| ADAMS  |     20 |
	| JAMES  |     30 |
	| FORD   |     20 |
	| MILLER |     10 |
	+--------+--------+
	14 rows in set (0.00 sec)

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

	select 
		e.ename,d.dname
	from 
		emp e , dept d
	where
		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      |
	+--------+------------+

	
	SQL92:(内连接中的等值连接)
		select 
			e.ename,d.dname 
		from 
			emp e , dept d 
		where 
			e.deptno = d.deptno;

	SQL99:(内连接中的等值连接) 99语法的优势:表的连接条件和真正的where过滤条件分离,结构更清晰
		select 
			e.ename,d.dname 
		from 
			emp e 
		join 
			dept d 
		on 
			e.deptno = d.deptno;
		
		select 
			e.ename,d.dname 
		from 
			emp e 
		inner join 
			dept d 
		on 
			e.deptno = d.deptno;

3.2、非等值连接
	案例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级
	mysql> select ename,sal from emp;
	+--------+---------+
	| ename  | sal     |
	+--------+---------+
	| SMITH  |  800.00 |
	| ALLEN  | 1600.00 |
	| WARD   | 1250.00 |
	| JONES  | 2975.00 |
	| MARTIN | 1250.00 |
	| BLAKE  | 2850.00 |
	| CLARK  | 2450.00 |
	| SCOTT  | 3000.00 |
	| KING   | 5000.00 |
	| TURNER | 1500.00 |
	| ADAMS  | 1100.00 |
	| JAMES  |  950.00 |
	| FORD   | 3000.00 |
	| MILLER | 1300.00 |
	+--------+---------+
	mysql> select * from salgrade;
	+-------+-------+-------+
	| GRADE | LOSAL | HISAL |
	+-------+-------+-------+
	|     1 |   700 |  1200 |
	|     2 |  1201 |  1400 |
	|     3 |  1401 |  2000 |
	|     4 |  2001 |  3000 |
	|     5 |  3001 |  9999 |
	+-------+-------+-------+

	SQL92:(内连接中的非等值连接)
		select 
			e.ename,e.sal,s.grade
		from
			emp e , salgrade s
		where
			e.sal between s.losal and s.hisal;

	SQL99:(内连接中的非等值连接)
		select 
			e.ename,e.sal,s.grade
		from
			emp e 
		join
			salgrade s
		on
			e.sal between s.losal and s.hisal; //连接条件不是等量关系叫做非等值连接

3.3、自连接
	
	案例:找出每个员工的上级领导,要求显示员工名和对应的领导名
	mysql> select empno,ename,mgr from emp;
	+-------+--------+------+
	| empno | ename  | mgr  |
	+-------+--------+------+
	|  7369 | SMITH  | 7902 |
	|  7499 | ALLEN  | 7698 |
	|  7521 | WARD   | 7698 |
	|  7566 | JONES  | 7839 |
	|  7654 | MARTIN | 7698 |
	|  7698 | BLAKE  | 7839 |
	|  7782 | CLARK  | 7839 |
	|  7788 | SCOTT  | 7566 |
	|  7839 | KING   | NULL |
	|  7844 | TURNER | 7698 |
	|  7876 | ADAMS  | 7788 |
	|  7900 | JAMES  | 7698 |
	|  7902 | FORD   | 7566 |
	|  7934 | MILLER | 7782 |
	+-------+--------+------+

	将emp表看做两张表:员工表和领导表

	emp e1 员工表
	+-------+--------+------+
	| 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 e2 领导表
	+-------+--------+
	| empno | ename  |
	+-------+--------+
	|  7566 | JONES  |
	|  7698 | BLAKE  |
	|  7782 | CLARK  |
	|  7788 | SCOTT  |
	|  7839 | KING   |
	|  7902 | FORD   |
	+-------+--------+
	
	emp e1 员工表
	emp e2 领导表

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

	SQL92(内连接中的自连接):

		select 
			e1.ename,e2.ename as leadername
		from
			emp e1 , emp e2
		where
			e1.mgr = e2.empno;

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

	SQL99(内连接中的自连接):
		select 
			e1.ename,e2.ename as leadername
		from
			emp e1 
		join
			emp e2
		on
			e1.mgr = e2.empno;

4、外连接

4.1、案例:找出每一个员工所在的部门,要求显示员工名和部门名,要求显示那些没有员工的部门

mysql> select ename,deptno from emp;
+--------+--------+
| ename  | deptno |
+--------+--------+
| SMITH  |     20 |
| ALLEN  |     30 |
| WARD   |     30 |
| JONES  |     20 |
| MARTIN |     30 |
| BLAKE  |     30 |
| CLARK  |     10 |
| SCOTT  |     20 |
| KING   |     10 |
| TURNER |     30 |
| ADAMS  |     20 |
| JAMES  |     30 |
| FORD   |     20 |
| MILLER |     10 |
+--------+--------+
14 rows in set (0.00 sec)

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

select 
	e.ename,d.dname 
from 
	emp e 
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      |
+--------+------------+


SQL99:(内连接中的等值连接)

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

SQL99:(右外连接/右连接)

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

SQL99:(左外连接/左连接)

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

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

注意:任何一个左连接都有右连接的编写方式。任何一个右连接都有左连接的编写方式。

什么时候使用外连接?外连接和内连接的本质区别?
	需求中要求除了将符合条件的记录查询出来,额外又
	要求将某张表的数据无条件的全部查询出来,此时必须
	使用外连接。当外连接之后,其中一些记录全部展示,
	对方表没有与之匹配的记录,此时会自动模拟NULL与其匹配。


外连接的SQL92就不讲了。

5、案例:找出所有员工的上级领导,要求显示员工名和对应的领导名(注意:是所有员工)

emp e1 员工表
emp e2 领导表
e1.mgr = e2.empno

内连接:
select
e1.ename,e2.ename as leadername
from
emp e1
join
emp e2
on
e1.mgr = e2.empno;

外连接:

select
e1.ename,e2.ename as leadername
from
emp e1
left join
emp e2
on
e1.mgr = e2.empno;

6、三张表或者多张表连接该怎么做?
需求:找出每个员工的部门名称,并且找出每个员工的工资等级,要求显示员工名、薪资、薪资等级、部门名
emp e 员工表
dept d 部门表
salgrade s 工资等级表

a  join b join c 的执行原理:a先和b进行表连接,之后a再单独和c进行表连接

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

需求:找出每个员工的部门名称,并且找出每个员工的工资等级,上级领导名称,
要求显示员工名、薪资、薪资等级、部门名、领导名

select 
	e.ename,e.sal,s.grade,d.dname,e2.ename as leadername
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
	emp e2
on
	e.mgr = e2.empno;

-------------------------------------------------------以下为子查询语法---------------------------------------------------------------------

1、什么是子查询?

select语句当中嵌套使用select语句

案例:找出工资比平均工资高的员工,要求显示员工名、工资
select ename,sal from emp where sal > avg(sal);
ERROR 1111 (HY000): Invalid use of group function

思路:
	第一步:查询公司平均薪水
		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);

2、可以嵌套在哪里?
select ..(select).
from ..(select).
where .(select)..

3、关于where后面嵌套select语句
select ename,sal from emp where sal > (select avg(sal) from emp);

4、关于from后面嵌套select语句(非常重要,有技巧,临时表技巧)

案例:找出每个部门平均薪资的薪资等级

第一步:找出每个部门平均薪资(按照部门编号分组求sal平均值)
select deptno,avg(sal) as avgsal from emp group by deptno;
+--------+-------------+
| deptno | avgsal      |
+--------+-------------+
|     10 | 2916.666667 | 
|     20 | 2175.000000 |
|     30 | 1566.666667 |
+--------+-------------+

salgrade s
grade	losal	hisal
-----------------------

技巧:将上面的查询结果当做临时表t
t和s表连接条件:t.avgsal between s.losal and s.hisal

第二步:将上面的查询结果当做临时表t,t表和s表进行表连接
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 |
+--------+-------------+-------+

5、在select语句当中使用子查询(非重点,理解即可)
select e.deptno,e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;
+--------+--------+------------+
| deptno | ename | dname |
+--------+--------+------------+
| 20 | SMITH | RESEARCH |
| 30 | ALLEN | SALES |
| 30 | WARD | SALES |
| 20 | JONES | RESEARCH |
| 30 | MARTIN | SALES |
| 30 | BLAKE | SALES |
| 10 | CLARK | ACCOUNTING |
| 20 | SCOTT | RESEARCH |
| 10 | KING | ACCOUNTING |
| 30 | TURNER | SALES |
| 20 | ADAMS | RESEARCH |
| 30 | JAMES | SALES |
| 20 | FORD | RESEARCH |
| 10 | MILLER | ACCOUNTING |
+--------+--------+------------+

---------------------------------------------------union----------------------------------------------------------------------
1、union(可以将查询结果集相加)

* 查询工作岗位是MANAGER和SALESMAN的员工
	第一种方案:or
		select ename,job from emp where job = 'MANAGER' or job='SALESMAN';
	第二种方案:in
		select ename,job from emp where job in('MANAGER','SALESMAN');
	第三种方案:union
		select ename,job from emp where job = 'MANAGER'
		union
		select ename,job from emp where job = 'SALESMAN';

* union(主要使用union:将结果集相加)
	select ename from emp 
	union
	select dname from dept;

* union使用注意事项:
	
	select empno,ename from emp
	union
	select dname from dept;

	ERROR 1222 (21000): The used SELECT statements have a different number of columns

	select deptno from dept
	union
	select ename from emp;

	+--------+
	| deptno |
	+--------+
	| 10     |
	| 20     |
	| 30     |
	| 40     |
	| SMITH  |
	| ALLEN  |
	| WARD   |
	| JONES  |
	| MARTIN |
	| BLAKE  |
	| CLARK  |
	| SCOTT  |
	| KING   |
	| TURNER |
	| ADAMS  |
	| JAMES  |
	| FORD   |
	| MILLER |
	+--------+

	以上的SQL语句在Oracle数据库当中无法执行,报错。Oracle显然语法严格

* union的使用注意事项:相同的列数,对应相同的数据类型

--------------------------------------------------------重点:limit-----------------------------------------------------

1、使用limit关键字可以取出表当中的部分数据,通常使用在分页查询方面

2、limit出现在DQL语句的最后面,也就是order by的后面,并且limit也是DQL语句当中最后执行的。

select (5)
from (1)
where (2)
group by (3)
having (4)
order by (6)
limit (7)

3、limit具有mysql的特色,Oracle绝对不能用,Oracle中分页查询需要rownum(rownum是Oracle的特色)。

4、limit语法结构:

select ...
from....
....
limit startIndex , pageSize;

startIndex是起始下标,默认值从0开始

5、找出工资排名在前5名的员工

select ename,sal from emp order by sal desc;

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

6、找出工资排名在前3~5名的员工

select ename,sal from emp order by sal desc limit 2 , 3;

7、编写一条通用的分页SQL语句:

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

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

通用的分页SQL:
	int pageNo = 10; //第10页
	int pageSize = 8; //每页显示8条记录

	select ...
	from....
	....
	limit (pageNo - 1) * pageSize , pageSize;

8、有时间的话研究一下Oracle的rownum

-----------------------------------------------------------------表的创建(DDL)------------------------------------------------------------

1、创建表

* 项目开发当中,表的抽取很难,这属于系统设计功能领域。
	设计表:
		表名的设计
		表中字段名的设计
		表中字段的类型设计
		表中字段的长度设计
		表中字段的约束设计

* 创建表的基础语法:
	
	create table 表名(
		字段名1 数据类型(长度),
		字段名2 数据类型(长度),
		字段名3 数据类型(长度),
		字段名4 数据类型(长度),
		字段名5 数据类型(长度),
		...
		字段名6 数据类型(长度)
	);

* 关于MySQL当中常见的数据类型:

	数据库字段数据类型		java中的数据类型
	---------------------------------------------------
	- int(整数型)			int
	- bigint(长整型)		long

	- char(定长字符串)		String
	- varchar(可变长字符串)		String

	- double(浮点型数据)		double
	- float(浮点型数据)		float
	
	- date(日期类型)		java.sql.Date

	- BLOB(二进制大对象 Binary Large OBject):这种类型的字段专门用来存储图片、流媒体、声音、视频....

	- CLOB(字符大对象 Character Larget OBject):支持大文本

	注意:日期处理在实际开发中date使用很少,因为日期的处理比较麻烦,每一个数据库的函数都不是通用的,
	所以建议将日期存储为字符串类型。

* char和varchar的区别?
	char是长度不可变的字符串
	varchar是长度可变的字符串

	create table t_1(
		name varchar(10)
	);

	insert into t_1 (name) values('jack');

	create table t_2(
		name char(10)
	);

	insert into t_2 (name) values('jack');

	char和varchar的选用原则?
		当数据库表中某个字段中的值,所有的值长度都是固定不变的,使用char
		长度经常发生改变的使用varchar

	哪些字段通常使用char?
		日期
		性别
		....

* 创建表(实际开发中,表名一般都是以 t_ 或者 tbl_ 开始)
	
	create table t_student(
		sno int(4),
		sname varchar(32),
		sex char(1),
		birth date,
		height double(3,2)
	);

	insert into t_student(sno,sname,sex,birth,height) values(1110,'jackson','m','1970-10-11',2);

	create table t_product(
		no bigint(10),
		name varchar(32),
		price double(3,2)
	);

	insert into t_product(no,name,price) values(110,'apple',1220);
	ERROR 1264 (22003): Out of range value for column 'price' at row 1

	insert into t_product(no,name,price) values(110,'apple',122);
	ERROR 1264 (22003): Out of range value for column 'price' at row 1

	insert into t_product(no,name,price) values(110,'apple',12);
	ERROR 1264 (22003): Out of range value for column 'price' at row 1

	insert into t_product(no,name,price) values(110,'apple',1);

	double(有效数字的个数,小数位的个数)

	insert into t_product(no,name,price) values(110,'apple',0.9999999);

	create table t_student2(
		sno int(4),
		sname varchar(32),
		sex char(1) default 'm',
		birth date,
		height double(3,2)
	);

	insert into t_student2(sno,sname,birth) values(2220,'lucy','1980-12-11');

	删除表:
		drop table t_student2;
		drop table if exists t_student2; //mysql特有的,不通用

----------------------------------------------------DML语句:insert------------------------------------------------------------------------

1、DML语句包含:insert update delete(对表中数据的增删改,必须掌握)

2、insert语法结构:

insert into 表名(字段名1,字段名2....) values(值1,值2....);

"字段名"和"值"要一一对应。
字段的数量和值得数量要相同。
字段需要的数据类型和值的数据类型要相同。

insert语句只要执行成功,表中必然会多一条记录。

当“值”的数量+顺序 和 表本身所有字段数量+顺序 相同时字段名可以省略不写。

insert into t_student values(3330,'zhangsan','m','1960-12-11',1.8);

mysql> insert into t_student values(3330,'zhangsan','m','1960-12-11');
ERROR 1136 (21S01): Column count doesn't match value count at row 1


insert into t_student(sno,sname,sex,birth) values(3330,'zhangsan','m','1960-12-11');

------------------------------------------------------DML语句:update-------------------------------------------------------------------------

1、update语句必须掌握,非常重要的内容,语法结构:

update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , 字段名3 = 值3 where 条件;

mysql> update t_student set sname='lisi',sex='m',birth='2010-11-12',height=1.5 where sno=2220;

-------------------------------------------------------DML语句:delete------------------------------------------------------------------------

1、delete语句必须掌握,非常重要,语法结构:

delete from 表名 where 条件;

注意:where条件没有的话,以上语句会将表当中所有的记录全部删除。

delete from t_student where sno is null;

delete from t_student where sno = 2220;

2、练习题:删除一个表当中重复的记录。

t_student

sno	sname
------------------------------
1	zhangsan
2	zhangsan
3	zhangsan
4	lisi
5	lisi
6	lisi

执行删除之后最终表留下的数据:

sno	sname
-------------------------
1	zhangsan
4	lisi

1、删除表中重复记录

create table t_user(
	id int(5),
	name varchar(32)
);

insert into t_user(id,name) values(1,'zhangsan');
insert into t_user(id,name) values(2,'zhangsan');
insert into t_user(id,name) values(3,'lisi');
insert into t_user(id,name) values(4,'lisi');
insert into t_user(id,name) values(5,'lisi');

t_user

id(pk)	name
------------------
1	zhangsan
2	zhangsan
3	lisi
4	lisi
5	lisi

第一种方案:
delete from t_user where id not in(select t.id from (select min(id) as id from t_user group by name) t);

delete from t_user where id not in(select min(id) as id from t_user group by name);
解释:更新数据时使用了查询,而查询的数据又做了更新的条件,mysql不支持这种方式。


第二种方案:(通过表连接的方式删除重复记录)
delete a from t_user a , (select min(id) as id,name from t_user group by name) b where a.id <> b.id and a.name = b.name;

delete a from t_user a join (select min(id) as id,name from t_user group by name) b on a.id <> b.id and a.name = b.name;

注意:Oracle中没有以上的写法,Oracle中可以使用第一种方案,其它方案只能靠:rowid了。

2、关于约束

2.1、约束对应的英语单词是:constraint

2.2、什么是约束?创建表的时候为什么要给字段添加约束呢?
	约束存在的意义是为了保证该字段中的数据具有有效性和完整性。

2.3、常见的约束包括哪些?
	NOT NULL : 非空约束:不能为NULL
	Unique:唯一性约束:不能重复,但是可以为NULL
	Primary Key:主键约束:不能为NULL,也不能重复
	Foreign Key:外键约束:该字段中的数据必须来自于某张表的某个字段中的数据

	检查约束(目前MySQL还不支持该约束,Oracle支持该约束)

2.4、非空约束
	
	* NOT NULL约束的字段不能为NULL

	* 怎么添加NOT NULL约束?
		create table t_user1(
			id int(3),
			name varchar(32) not null
		);

		mysql> insert into t_user1(id) values(1);
		ERROR 1364 (HY000): Field 'name' doesn't have a default value
		以上报错的原因:name字段有not null约束

		mysql> insert into t_user1(name) values('zhangsan');
		Query OK, 1 row affected (0.01 sec)

	* not null约束只能添加在某个字段的后面

2.5、unique约束
	
	* unique约束的字段不能重复,但是可以为NULL

	* 创建表:t_user2
		create table t_user2(
			id int(3) unique,
			name varchar(32)
		);

		mysql> insert into t_user2(id,name) values(1,'jack');
		Query OK, 1 row affected (0.01 sec)

		mysql> insert into t_user2(id,name) values(1,'jack2');
		ERROR 1062 (23000): Duplicate entry '1' for key 'id'

		mysql> insert into t_user2(name) values('lisi');
		Query OK, 1 row affected (0.00 sec)

		mysql> select * from t_user2;
		+------+------+
		| id   | name |
		+------+------+
		|    1 | jack |
		| NULL | lisi |
		+------+------+

		以上添加约束的方式是在字段的后面直接添加unique,这种方式被称为:列级约束
	
	* 创建表:t_user3
		
		create table t_user3(
			id int(3) ,
			name varchar(32),
			unique(id,name)
		);

		以上添加约束的方式被称为:表级约束,表示id+name两个字段联合唯一(这种情况很少)

		mysql> insert into t_user3(id,name) values(1,'jack');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user3(id,name) values(2,'jack');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user3(id,name) values(3,'jack');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user3(id,name) values(1,'jack1');
		Query OK, 1 row affected (0.01 sec)

		mysql> insert into t_user3(id,name) values(1,'jack2');
		Query OK, 1 row affected (0.01 sec)

		mysql> insert into t_user3(id,name) values(1,'jack3');
		Query OK, 1 row affected (0.01 sec)

		mysql> select * from t_user3;
		+------+-------+
		| id   | name  |
		+------+-------+
		|    1 | jack  |
		|    1 | jack1 |
		|    1 | jack2 |
		|    1 | jack3 |
		|    2 | jack  |
		|    3 | jack  |
		+------+-------+
		6 rows in set (0.00 sec)

		mysql> insert into t_user3(id,name) values(1,'jack');
		ERROR 1062 (23000): Duplicate entry '1-jack' for key 'id'
	
	* 创建表:t_user4
		create table t_user4(
			id int(3),
			name varchar(32),
			constraint t_user4_id_name_unique unique(id,name)
		);

		给唯一性约束起名:
			constraint 约束名
			这种方式只适合于表级约束
		
2.6、主键约束(primary key)
	
	* 主键约束简称PK

	* 主键约束的作用:该字段不能为NULL,同时也不能重复

	* 什么主键?什么是主键字段?什么是主键约束?主键存在的意义是什么?
		主键字段中的每一个数据都不为NULL,并且也是唯一的,
		主键字段中的每一个值都是当前行记录的唯一标识
		即使两条记录完全相同,只要主键值不同,那么这两条记录就是
		完全不同的记录。
		
		数据库设计三范式中第一范式就要求:任何一张表都应该有主键字段,若没有则无效。
	
	* 创建表:t_user5
		create table t_user5(
			id int(3) primary key, /*列级约束*/
			name varchar(32)
		);

		insert into t_user5(id,name) values(1,'zhangsan'); //success
		insert into t_user5(id,name) values(2,'lisi'); //success
		insert into t_user5(id,name) values(1,'wangwu'); //error
		insert into t_user5(name) values('zhangfei'); //error
	
	* 创建表:t_user6
		
		create table t_user6(
			id int(3),
			name varchar(32),
			constraint t_user6_id_pk primary key(id)
		);

		以上的约束属于表级约束

	* 联合主键(比较少,可以同时给多个字段添加主键约束)
		
		create table t_user7(
			id int(3),
			name varchar(32),
			age int(3),
			constraint t_user7_id_name_pk primary key(id,name)
		);

		mysql> insert into t_user7(id,name) values(1,'abc');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user7(id,name) values(2,'abc');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user7(id,name) values(1,'abcd');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user7(id,name) values(1,'abcf');
		Query OK, 1 row affected (0.00 sec)

		mysql> insert into t_user7(id,name) values(1,'abc');
		ERROR 1062 (23000): Duplicate entry '1-abc' for key 'PRIMARY'
		mysql> insert into t_user7(age) values(10);
		Query OK, 1 row affected (0.00 sec)

		mysql> select * from t_user7;
		+----+------+------+
		| id | name | age  |
		+----+------+------+
		|  0 |      |   10 |
		|  1 | abc  | NULL |
		|  1 | abcd | NULL |
		|  1 | abcf | NULL |
		|  2 | abc  | NULL |
		+----+------+------+

		mysql> insert into t_user7(age) values(10);
		ERROR 1062 (23000): Duplicate entry '0-' for key 'PRIMARY'

2.7、外键约束:foreign key (FK)
	
	* 场景:
		请自行设计数据库表,用来存储班级和学生的信息
	
	* 第一种方案:班级和学生存储到一张表中。

		t_student
		id	name	classno		classname
		----------------------------------------------------------------------------------
		1	a	100		北京市大兴区亦庄北京小学三年2班
		2	b	100		北京市大兴区亦庄北京小学三年2班
		3	c	100		北京市大兴区亦庄北京小学三年2班
		4	d	101		北京市大兴区亦庄北京小学三年3班
		5	e	101		北京市大兴区亦庄北京小学三年3班
		6	f	101		北京市大兴区亦庄北京小学三年3班
		7	g	101		北京市大兴区亦庄北京小学三年3班
	
	* 以上的这种方案,会造成数据冗余,怎么解决数据冗余问题?
		班级和学生之间的关系是一个典型的:1 :多 的关系
		1个班级对应多个学生
		通常会采用两张表存储数据:一张表专门存储学生,另一张表专门存储班级
	
	* 第二种方案:

		t_class班级表

		id(pk)		name
		---------------------------------------------------------
		100		北京市大兴区亦庄北京小学三年2班
		101		北京市大兴区亦庄北京小学三年3班

		t_student学生表

		id(pk)		name		classno(fk)	
		-----------------------------------------------------------
		1		a		100
		2		b		100
		3		c		100
		4		d		101
		5		e		101
		6		f		101
		7		g		101

		为了保证t_student表当中的classno字段中的数据必须来自t_class表中的id字段,
		需要给t_student表中的classno字段添加外键约束,classno就是一个外键字段。

		外键约束的字段可以为NULL,但只要不是NULL,则一定是其它表当中某个字段下的值。

		有了外键约束之后,就有了父子表:
			t_class 父表
			t_student 子表

			原则:
				先创建父表,再创建子表
				先向父表中插入数据,再向子表中插入数据
				先删除子表中的数据,再删除父表中的数据
				先删除子表,再删除父表
		
		drop table if exists t_student;
		drop table if exists t_class;

		create table t_class(
			id int(3),
			name varchar(100),
			constraint t_class_id_pk primary key(id)
		);

		create table t_student(
			id int(3),
			name varchar(32),
			classno int(3),
			constraint t_student_id_pk primary key(id),
			constraint t_student_classno_fk foreign key(classno) references t_class(id)
		);

		insert into t_class(id,name) values(100,'北京市大兴区亦庄北京小学三年2班');
		insert into t_class(id,name) values(101,'北京市大兴区亦庄北京小学三年3班');

		insert into t_student(id,name,classno) values(1,'a',100);
		insert into t_student(id,name,classno) values(2,'b',100);
		insert into t_student(id,name,classno) values(3,'c',100);
		insert into t_student(id,name,classno) values(4,'d',101);
		insert into t_student(id,name,classno) values(5,'e',101);
		insert into t_student(id,name,classno) values(6,'f',101);
		insert into t_student(id,name,classno) values(7,'g',101);

		insert into t_student(id,name,classno) values(8,'k',102); //error
		insert into t_student(id,name,classno) values(8,'k');

		mysql> select * from t_student;
		+----+------+---------+
		| id | name | classno |
		+----+------+---------+
		|  1 | a    |     100 |
		|  2 | b    |     100 |
		|  3 | c    |     100 |
		|  4 | d    |     101 |
		|  5 | e    |     101 |
		|  6 | f    |     101 |
		|  7 | g    |     101 |
		|  8 | k    |    NULL |
		+----+------+---------+

	* 主键存在联合主键,外键有联合外键吗?
		有
		constraint t_student_classno_fk foreign key(classno,?) references t_class(id,?)

		(id,?) 需要保证唯一性

	
	* 外键字段引用别的表中某个字段的时候,被引用的字段必须是主键吗?
		被引用的字段只要有unique约束即可。不一定是主键。

2.8、怎么查看约束?

	* 约束一旦创建之后在mysql数据库当中以对象的形式存在,怎么查看这些对象呢?

	mysql> use information_schema;
	Database changed

	mysql> show tables like '%CONSTRA%';
	+------------------------------------------+
	| Tables_in_information_schema (%CONSTRA%) |
	+------------------------------------------+
	| REFERENTIAL_CONSTRAINTS                  |
	| TABLE_CONSTRAINTS                        |
	+------------------------------------------+

	重点:在实际开发当中为了提高检索效率,尽可能少的使用FK,缩小扫描范围。
	在实际开发中没有FK的话,怎么保证这个字段中的数据必须来自于某个表当中某个字段中的数据?
		下拉列表

2.9、主键如何自动维护

	* t_user
		id(pk)	name	password
		---------------------------
		1	a	123
		2	b	123
		3	c	123
		4	d	123
		5	e	123
		6	f	123
	
	* 注册功能:用户在页面上填写表单信息,提交表单,表单中一般是不需要提供主键的,
	主键一般都是自动维护。

	* mysql中主键值自动维护:auto_increment

		create table t_user8(
			id int(3) primary key auto_increment,
			name varchar(32)
		);
	
	* 使用auto_increment前提是该字段为主键字段。

3、对约束的增、删、改(了解)

* 这块内容术语了解内容,不要死记硬背,在实际开发中表一旦设计完成,尤其是项目已经进行了一部分,
此时表中的字段很少的增删改,此时表中的约束也是很少的增删改。

* 系统设计完成之后需要进行评审。
	* 需求分析(评审)
	* 系统设计(评审)
	* 编码(评审:代码走查)程序员一般情况下负责编码,同时还需要对自己编写的代码负责:单元测试(白盒测试)
	* 测试(评审)
	* 实施(评审)

* 删除主键约束
	alter table t_user drop primary key;

* 删除外键约束
	alter table t_user drop foreign key 外键名字;

* 添加主键约束
	alter table t_user add primary key(id);

* 添加外键约束
	alter table t_user add constraint 外键名字 foreign key(?) references t_student(?);

4、存储引擎(了解)

* 什么是存储引擎,有什么作用?
	创建一张表的时候,可以给这张表指定存储引擎,不同的存储引擎会导致底层采用不同的方式去组织表中的数据。
	表组织形式的不同方式

* 存储引擎是mysql特有的,Oracle没有。

* 注意:不同的mysql版本会支持不同的存储引擎

* 查看当前数据库支持哪些存储引擎?
	show engines;

* 通常是在创建表的时候在最后的位置上使用以下语句来指定存储引擎以及字符集:
	create table t_name(
		....
	)ENGINE=InnoDB DEFAULT CHARSET=utf8;

* 面试官可能会问哪些问题?

	- 你听说过MySQL存储引擎吗?

	- 可以说几个常见的存储引擎吗?
		MyISAM、InnoDB、MEMORY...

	- 你在实际开发中是如何选择存储引擎的?

		很少的修改操作,大部分都是读,并且数据量庞大,可以考虑MEMORY存储引擎
		使用MEMORY存储引擎可能会导致数据丢失。

		对事务没有太多要求,希望数据保存在硬盘上面的,可以选择MyISAM存储引擎

		对事务要求比较严格,建议使用InnoDB存储引擎。

* MyISAM存储引擎:
	三个文件方式:
		结构文件:xx.frm
		数据文件:xx.MYD
		索引文件:xx.MYI
	此存储引擎可以使用auto_increment
	可被转换为压缩、只读表来节省空间

* InnoDB存储引擎:
	提供事务支持(支持提交和回滚操作)
	在MySQL服务器崩溃后提供自动恢复
	行级锁定(悲观锁)
	支持外键及引用的完整性,包括级联删除和更新
	InnoDB和MyISAM对比来说:InnoDB更安全,但是效率没有MyISAM高。

	关于级联更新和级联删除

		t_class

		id(pk)	name
		-------------------
		1	高三1班
		2	高三2班

		t_student

		id(pk)	name	cid(fk)
		-------------------------
		1	a	1
		2	b	1
		3	c	2
		4	d	2

		级联更新:
			在创建t_student表的时候,给cid字段添加外键约束的时候,指定该字段支持级联更新,
			当更新t_class表当中id的时候,cid字段中的数据会被级联更新。

		级联删除:
			在创建t_student表的时候,给cid字段添加外键约束的时候,指定该字段支持级联删除,
			当删除t_class表当中数据的时候,cid关联的数据全部删除。

		alter table t_student drop foreign key t_student_classno_fk;
		alter table t_student add constraint t_student_classno_fk foreign key(classno) references t_class(id) on delete cascade;
		
		当没有设置cid支持级联更新和级联删除的时候,删除或者更新父表当中的id,mysql会提示错误信息。


* MEMORY存储引擎:
	MEMORY存储引擎管理的表具有下列特征:
		–在数据库目录内,每个表均以.frm格式的文件表示。
		–表数据及索引被存储在内存中。
		–不能包含TEXT或BLOB字段。

	MEMORY存储引擎以前被称为HEAP引擎。

5、事务初步(掌握)

* 事务对应的英语单词:Transaction

* 事务只针对DML语句(只有insert update delete才会有事务),和其它语句无关

* 事务的存在让数据更安全,更完整。

* DML语句有一个特点,这些语句都是操作数据库表当中“数据”的。

* 事务有一些相关的术语:
	开启事务	begin transaction
	结束事务	end transaction
	提交事务	commit transaction
	回滚事务	rollback transaction

	“提交事务”和“回滚事务”都属于“结束事务”

* 提交和回滚?
	提交对应的SQL语句:commit;(提交之后,内存当中的数据会持久化到硬盘上)
	回滚对应的SQL语句:rollback;(回滚之后,内存当中的数据消失,不和硬盘交互)

	无论你执行了commit还是rollback,事务都会结束,只不过commit表示事务成功的结束了
	rollback表示事务也结束了,但是数据库表中数据没有做任何改动,也可以理解为失败的结束了。

* 什么是事务?

	事务是最小的工作单元,不可再分。

	t_act账户表

	actno		balance
	--------------------------------
	act-001		10000
	act-002		3000

	转账5000元:从act-001转到act-002账户

	//当没有事务的时候,执行这条语句,马上更新硬盘数据,显然这种方式不安全,因为后面的SQL语句是否能够执行成功!
	update t_act set balance = 5000 where actno = 'act-001'; 

	update t_act set balance = 8000 where actno = 'act-002';

	实质上事务的本质是:
		多条DML语句要么同时成功,要么同时失败,不允许出现部分成功,部分失败,这样会导致数据不安全/不完整。

		在实际开发中到底有多少条DML语句需要绑定到一个事务当中,那要看具体的业务逻辑。
	
	转账就是一个业务逻辑,两条数据都更新成功才算该业务结束。才算该事务结束。

	一个事务也可以等同的看做一个完整的业务逻辑。

* 事务具有哪些特性:ACID特性
	A:原子性:表示事务是最小的工作单元,不可再分。
	C:一致性:同时成功,或者同时失败
	I:隔离性:事务和事务之间具有隔离
	D:持久性:事务的最终保证,事务结束的标志是,数据已经持久化到硬盘文件当中了。

* 关于事务的隔离性:
	
	- 事务和事务之间具有隔离

	- 隔离涉及到隔离级别,常见的隔离级别有4个:
		read uncommitted(读未提交:对方未提交的数据,我可以读取到。这种现象被称为脏读/dirty read)
		read committed(读已提交:提交之后对方才能读取到数据,避免dirty read,但是存在“不可重复读取”现象)
		repeatable read(可重复读,只要开启事务,在结束事务之前,每一次读取到的数据都是一样的,可以重复读取,避免“不可重复读取”现象,但是会导致“幻影读”现象)
		serializable(串行化:当事务开启之后,只能当前事务操作该表当中的数据,该事务没有结束,其它事务排队,可以避免“幻影读”)
	
	- mysql数据库默认的隔离级别是:可重复读
		mysql> select @@global.tx_isolation;
		+-----------------------+
		| @@global.tx_isolation |
		+-----------------------+
		| REPEATABLE-READ       |
		+-----------------------+
	
	- oracle数据库默认隔离级别:读已提交

	- mysql默认情况下是自动提交吗?
		默认支持自动提交,什么是自动提交:只要执行任意一条DML语句则提交一次,这是mysql默认的行为。
	
	- 怎么关闭mysql的自动提交呢?
		start transaction; 表示手动开启事务
		commit;/rollback; 表示事务结束

* 查看当前全局的事务隔离级别:
	select @@global.tx_isolation;

* 设置全局的隔离级别:
	set global transaction isolation level read uncommitted;


* 测试每一个隔离级别:
	read uncommitted
	read committed
	repeatable read
	serializable

6、索引index(理解)

* 怎么创建索引?
	create index 索引的名字 on 表名(字段名);

* 怎么删除索引?
	drop index 索引的名字 on 表名;

* 索引的作用是什么?
	索引:index
	索引相当于一本书的目录(目录也是有顺序的,需要排序的)
	作用:主要是为了提高检索效率

* 表的检索包括两种方式:
	- 全表扫描
	- 根据索引扫描(效率很高)

* 主键字段会自动添加索引,所以一般情况下,建议使用主键字段进行查询,效率较高。
	create table t_1(
		id int(3) primary key
	);

* 什么时候给表当中某个字段添加索引?
	- 数据量很大的时候适合添加索引
	- 经常被修改的字段不适合添加索引,因为索引也需要维护。(不经常DML操作的字段适合添加索引)
	- 经常出现在where条件当中的字段适合添加索引

	select ename,sal from emp where ename = 'SMITH'; 
	当ename字段没有添加索引的时候,ename字段中的数据全部扫描一遍
	当ename字段添加索引的时候,会先找到ename字段对应的索引进行检索

* 使用索引的时候注意事项:
	select * from emp where ename like '%SMITH%';
	以上使用了模糊查询,索引失效。

7、视图view(理解)

* 从另一个角度看待数据

* 视图:view

* 视图的作用:
	提高检索效率(不需要表连接提高效率)
	隐藏表的实现细节(DBA负责创建N多个视图对象,把视图对象分配给程序员,程序员对视图对象进行CRUD操作)

* CRUD:
	create	增
	retrive	查
	update	改
	delete	删
	

* 怎么创建视图?

	create view myview as select empno,ename,sal from emp;

	mysql> select * from myview;
	+-------+--------+---------+
	| empno | ename  | sal     |
	+-------+--------+---------+
	|  7369 | SMITH  |  800.00 |
	|  7499 | ALLEN  | 1600.00 |
	|  7521 | WARD   | 1250.00 |
	|  7566 | JONES  | 2975.00 |
	|  7654 | MARTIN | 1250.00 |
	|  7698 | BLAKE  | 2850.00 |
	|  7782 | CLARK  | 2450.00 |
	|  7788 | SCOTT  | 3000.00 |
	|  7839 | KING   | 5000.00 |
	|  7844 | TURNER | 1500.00 |
	|  7876 | ADAMS  | 1100.00 |
	|  7900 | JAMES  |  950.00 |
	|  7902 | FORD   | 3000.00 |
	|  7934 | MILLER | 1300.00 |
	+-------+--------+---------+

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

	create view myview2 as select empno a,ename b,sal c from emp;

	mysql> select b from myview2;
	+--------+
	| b      |
	+--------+
	| ADAMS  |
	| ALLEN  |
	| BLAKE  |
	| CLARK  |
	| FORD   |
	| JAMES  |
	| JONES  |
	| KING   |
	| MARTIN |
	| MILLER |
	| SCOTT  |
	| SMITH  |
	| TURNER |
	| WARD   |
	+--------+

* 怎么删除视图?
	drop view myview;
原文地址:https://www.cnblogs.com/f-bob/p/14885080.html