Mysql----整理

--------------------------------------------------数据常库常用操作总结-------------------------------------------------------
四种存储引擎
	*1:engine=innodb-----------------支持事物,行锁
	*2:engine=myisam-----------------不支持事物,表锁
	3:engine=memory
	4:engine=blackhole---------------黑洞引擎

	Mysql默认端口:-------------------3306
	
	InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
	MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
	Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
	NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
	Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;
	
*库--------------------------------------------------------库操作----------------------------------------------------------
	
	增---------------------------------------------create database db1 charset utf8;

	查---------------------------------------------show databases;
												   show create database db1;
		show databases;-----------------------------------------------------------查看所有的数据库
		create database;----------------------------------------------------------数据库名;
		dropdatabase database_name;-----------------------------------------------创建数据库
		dorp database-------------------------------------------------------------删除数库,
		show create database;-----------------------------------------------------查看新建的库
		
	改---------------------------------------------alter database db1 charset gbk;
	
	删---------------------------------------------drop database db1;

	
*表--------------------------------------------------------操作文件(表)----------------------------------------------------
	
	切换到文件夹下:use db1

	增--------------------------------------------create table t1(id int, name char(10))engine = innodb;
												  create table t2(id int, name char(10))engine = innodb default charset utf8;
	查--------------------------------------------show tables;
	                                              show create table t1;
			show create table table_name;------------------------------------------------查看当前数据库中table_name的建表语句,
			show create table t2;--------------------------------------------------------查看表的信息,含字符编码格式;
		查看表结构------------------------------------desc t1;
	改--------------------------------------------alter table t1 add age int;
												  alter table t1 modify name char(12);
												  修改表名------------ALTER TABLE 表名 RENAME 新表名;
			create table table_name(字段名 字段数据类型[约束], 字段名 字段数据类型[约束]) rename table 原表名 to 新表名------------------------------修改表名
			增加字段(t2指带表名)----------------------------------------------------------alter table table_name add 字段 字段类型 约束 位置[first | after 字段名];
			增加多个字段------------------------------------------------------------------alter table t2 add salary float(5, 2), add addres char; 																	 alter table t2 add grade char not nullunique;
			修改表所用的字符编码--------------------------a-------------------------------alter tablet1 character set gbk ;把t1表所用的字符编码改成gbk,
	删--------------------------------------------drop table t1;
			alter create database database_name charset utf;------------------------------查看创建数据库信息(或者说是建库语句, 含字符编码)
			alter database db1 charset utf - 8;-------------------------------------------修改数据库的字符编码,
			drop database-----------------------------------------------------------------删除某一个数据库
			use database_name;------------------------------------------------------------使用某个数据库,相当于进入这个数据库(文件夹)
			select database();------------------------------------------------------------显示当前所在的数据库
			

*字段------------------------------------------------------操作文件的一行行内容(记录)--------------------------------------
	
	增--------------------------------------------insert into db1.t1 values(1, 'egon1'), (2, 'egon2'), (3, 'egon3'); 
												  insert into db1.t1(name)alues('egon1'), ('egon2'), ('egon3');
	查--------------------------------------------select *from t1;
												  select name from t1;
												  select name, id from t1;

	改--------------------------------------------update t1 set name = 'SB' where id = 4;
												  update t1 set name = 'SB' where name = 'alex';
			alter table t2 modify salary int not null; ----------------------------更改salary字段的数据类型,并加not null的约束条件。
			alter table t2 change salary salariesint; -----------------------------更改salary字段的名字为salaries,注意 会改变约束条件,需要的话,需要添加;							  
	删--------------------------------------------delete from t1 where id = 4;

		对于清空表记录有两种方式,但是推荐后者:
			truncate t1; ------------------------当数据量比较大的情况下,使用这种方式,删除速度快

	自增id --------------------------------------create table t5(id int primary key auto_increment, name char(10));
		   --------------------------------------create table t4(id int not null unique, name char(10));
	增加字段-------------------------------------ALTER TABLE 表名 ADD 字段名  数据类型 [完整性约束条件…],ADD 字段名  数据类型 [完整性约束条件…];
												 ALTER TABLE 表名 ADD 字段名  数据类型 [完整性约束条件…]  FIRST;
												 ALTER TABLE 表名 ADD 字段名  数据类型 [完整性约束条件…]  AFTER 字段名;                            
	删除字段-------------------------------------ALTER TABLE 表名 DROP 字段名;

	修改字段-------------------------------------ALTER TABLE 表名 MODIFY  字段名 数据类型 [完整性约束条件…];
												 ALTER TABLE 表名 CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
												 ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
	  

*数据类型--------------------------------------------------数据类型--------------------------------------------------------
	1------------------------------------------------------数字(默认都是有符号,宽度指的是显示宽度,与存储无关)
		tinyint:-------------------------------长整形
		int:-----------------------------------整形
		bigint:--------------------------------个数,年龄,id,qq号,手机号
		float:---------------------------------浮点型,价格,身高,体重,余额
		double:--------------------------------
		decimal:-------------------------------

	2-------------------------------------------字符(宽度指的是字符个数):姓名,性别,职业,地址,职称,介绍
		char:---------------------------简单粗暴,不够则凑够固定长度存放起来,浪费空间,存取速度快
		varchar:------------------------精准,计算出待存放的数据的长度,节省空间,存取速度慢

	3------------------------------------------------------日期
		datetime-----------------------------注册时间
		date:--------------------------------出生年月日,开学时间
		time:--------------------------------聊天记录,上课时间
		year:--------------------------------出生年

	4-----------------------------------------------------枚举与集合
		enum---------------------------------枚举:规定一个范围,可有多个值,但是为该字段传值时,只能取规定范围中的一个
		set集合------------------------------规定一个范围,可有多个值,但是为该字段传值时,可以取规定范围中的一个或多个

		整型测试----------------------------------------create table t1(id tinyint);
		                                                create table t2(id int);
														create table t3(id bigint);

		浮点型测试--------------------------------------create table t4(salary float(5, 2));
		                                                insert into t4 values(3.73555); 
														insert into t4 values(-3.73555);
														insert into t4 values(-1111.73555);
														insert into t4 values(-111.73555);

		char与varchar测试-------------------------------create table t6(name char(4)); 
														insert into t6 values('alexsb'); 
														insert into t6 values('欧德博爱');
														insert into t6 values('艾利克斯a');	
														create table t7(x char(5), y varchar(5));


			insert into t7 values('abc', 'abc');  -------char_length :查看字符的长度 
			insert into t7 values('你好啊', '好你妹');---length:查看字节的长度
				注意两点:
					insert into t7 values('abc ', 'abc '); --length:查看字节的长度
					select * from t7 where y = 'abc    '; ----去掉末尾的空格然后去比较


		日期类型测试------------------------------------create table student(idint,name char(5),born_datedate,born_yearyear,reg_timedatetime,class_timetime);
														insertintostudentvalues(1, 'alex', now(), now(), now(), now());insertintostudentvalues(1, 'alex', '2017-09-06', '2017', '2017-09-06 10:39:00', '08:30:00');
		
		枚举与集合测试----------------------------------create table student1(id int primary key auto_increment,namechar(5),sex enum('male', 'female'),hobbiesset('music', 'read', 'study', 'coding'));
														insert into student1(name, sex, hobbies) values('egon', 'None', 'asdfasdfasdf'); 
														insert into student1(name, sex, hobbies) values('egon', 'male', 'music,read');


*约束------------------------------------------------------约束------------------------------------------------------------
	约束:
		not null(不为空) 与default(默认值);
		primary key(主键) auto_increment(自增id);
		例:
			create table student2(id int primary key auto_increment, name char(5),sex enum('male', 'female')not null default 'female');
			insert intos tudent3(name) values('alex');
	唯一:
		unique(唯一)
			单列唯一-----------------------------------create table teacher(id int not null unique, namechar(10));
													   insert into teacher values(1, 'egon'); 
			多列唯一-----------------------------------create table services(id int primary key auto_increment,name char(10), host char(15),
														port int,constrainthost_portunique(host, port));
													   insert into services values('ftp', '192.168.20.17', 8080);
	偏移量:
		auto_increment_offset:---------偏移量
					----------------------------------create table dep(id int primary key auto_increment,name char(10));
					                                  insert into dep(name) values('IT'), ('HR'), ('SALE'), ('Boss');

					----------------------------------create table dep1(id int primary key auto_increment, name char(10))auto_increment = 10;
													  insert into dep1(name) values('IT'), ('HR'), ('SALE'), ('Boss');
	步长:
		auto_increment_increment:------步长
					----------------------------------create table dep2(id int primary key auto_increment,name char(10));
			set session uto_increment_increment = 2; ---------------会话级,只对当前会话有效
			set global auto_increment_increment=2;   ---------------全局,对所有的会话都有效
				insert into dep1(name) values('IT'), ('HR'), ('SALE'), ('Boss');
			auto_increment_offset:偏移量+auto_increment_increment:步长
			注意:如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值会被忽略
				set session auto_increment_offset = 2;
				set session auto_increment_increment = 3;
		create table dep3(id int primary key auto_increment, name char(10));
		insert into dep3(name) values('IT'), ('HR'), ('SALE'), ('Boss');


*连表------------------------------------------------------连表------------------------------------------------------------
	先建被关联的表,并且被关联的字段必须唯一,再创建关联的表
	一对多:-------------------------------------------foreign key
			create table dep(idint primary key auto_increment,name varchar(50),comment varchar(100));
			create table emp_info(id int primary key auto_increment,name varchar(20),dep_id int,constraint fk_depid_id foreign key(dep_id)references dep(id)on delete cascade on update cascade);
		例:一对多
			create table press(id int primary key auto_increment,name varchar(20));
			create table book(id int primary key auto_increment, ectnamevarchar(20),press_id int not null,froeignkey(press_id)referencer press(id)on delete cascade on update cascade);
		**:on delete cascade on update cascade---------------------------添加和删除的权限	
		insert into press(name)values \ ('北京工业地雷出版社'), \('人民音乐不好听出版社'), \('知识产权没有用出版社');
		insertintobook(name, press_id)values \('九阳神功', 1), \('九阴真经', 2), \('九阴白骨爪', 2), \('独孤九剑', 3), \('降龙十巴掌', 2), \('葵花宝典', 3);

	多对多:-------------------------------------------foreign key+一张新的表
		例:多对多
			create table author(id int primary key auto_increment,name varchar(20);
			create table author2book(id int not null unique auto_increment,author_id int not null,book_id int not null,
				constraint fk_author foreign key(author_id) references author(id)on delete cascadeon update cascade,
				constraint fk_book foreign key(book_id) references book(id)on delete cascadeon update cascade,primary key(author_id,book_id));
				
	一对一:-------------------------------------------foreign key+unique
		例:一对一
			create table customer(id int primary key auto_increment,name varchar(20) not null,qq varchar(10) not null,phone char(16) not null);
			create table student(id int primary key auto_increment,class_name varchar(20) not null,customer_id int unique, #该字段一定要是唯一的
				foreign key(customer_id) references customer(id) delete cascadeon update cascade);
				customer_id int unique, ---该字段一定要是唯一的
				customer(id)---------------外键的字段一定要保证uniqueon 
				

*单表查询--------------------------------------------------单表查询--------------------------------------------------------
	重点中的重点:关键字的执行优先级:
									from----------------------------------1.找到表:from
									where---------------------------------2.拿着where指定的约束条件,去文件/表中取出一条条记录
									group by------------------------------3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
									having--------------------------------4.将分组的结果进行having过滤
									select--------------------------------5.执行select
									distinct------------------------------6.去重
									order by------------------------------7.将结果按条件排序:order by
									limit---------------------------------8.限制结果的显示条数
									
	简单查询:-------------------------------------------select * from employee;
														select name, salary from employee;

	where条件:------------------------------------------select name, salary from employee wheresalary > 10000;
														select name, salary from employee where salary > 10000 and salary < 20000;--------------多条件查询
														select name, salary from employee where salary not between 10000 and 20000;-------------关键字BETWEEN AND
														select name, salary from employee where salary = 10000 or salary = 20000 or salary = 30000;
														select name, salary from employee where salary in (10000, 20000, 30000);-----------------关键字IN集合查询
														select * from employee where salary = 10000 or age = 18 or sex = 'male';
														select * from employee where post_comment is Null;
														select * from employee where post_comment = Null;
														select * from employee where post_comment is not Null;
													关键字LIKE模糊查询
														select * from employee where name like '%n%';------------通配符’%’
														select * from employee where namelike 'e__n';------------通配符’_’

	group by分组:---------------------------------------select depart_id, group_concat(name)from employee group by depart_id;
															+-----------+--------------------------------------------------------------+
															| depart_id | group_concat(name) |
															+-----------+--------------------------------------------------------------+
															| 1 | egon, alex, wupeiqi, yuanhao, liwenzhou, jingliyang, jinxin, 成龙 |
															| 2 | 歪歪, 丫丫, 丁丁, 星星, 格格 |
															| 3 | 张野, 程咬金, 程咬银, 程咬铜, 程咬铁 |
															+-----------+--------------------------------------------------------------+

														select depart_id, count(id) from employee group by depart_id;-------------------count:总数
															+-----------+-----------+
															| depart_id | count(id) |
															+-----------+-----------+
															| 1 | 8 |
															| 2 | 5 |
															| 3 | 5 |
															+-----------+-----------+
														select depart_id, group_concat(id) from employee group by depart_id;
															+-----------+------------------+
															| depart_id | group_concat(id) |
															+-----------+------------------+
															| 1 | 1, 2, 3, 4, 5, 6, 7, 8 |
															| 2 | 9, 10, 11, 12, 13 |
															| 3 | 14, 15, 16, 17, 18 |
															+-----------+------------------+
														select depart_id, count(id) from employee group by depart_id;
															+-----------+-----------+
															| depart_id | count(id) |
															+-----------+-----------+
															| 1 | 8 |
															| 2 | 5 |
															| 3 | 5 |
															+-----------+-----------+
														select depart_id, max(salary) from employee group by depart_id;-----------------最大数
															+-----------+-------------+
															| depart_id | max(salary) |
															+-----------+-------------+
															| 1 | 1000000.31 |
															| 2 | 4000.33 |
															| 3 | 20000.00 |
															+-----------+-------------+
														selectdepart_id, min(salary) from employee group by depart_id;------------------最小数
															+-----------+-------------+
															| depart_id | min(salary) |
															+-----------+-------------+
															| 1 | 2100.00 |
															| 2 | 1000.37 |
															| 3 | 10000.13 |
															+-----------+-------------+
														select depart_id, sum(salary)from employee group by depart_id;------------------求和
															+-----------+-------------+
															| depart_id | sum(salary) |
															+-----------+-------------+
															| 1 | 1070200.64 |
															| 2 | 13001.47 |
															| 3 | 84000.13 |
															+-----------+-------------+
														select depart_id, avg(salary) from employee group by depart_id;-----------------求平均数
															+-----------+--------------                        -+
															| depart_id | avg(salary) |
															+-----------+---------------+
															| 1 | 133775.080000 |
															| 2 | 2600.294000 |
															| 3 | 16800.026000 |
															+-----------+---------------+
	
	聚合:
		max
		min
		sum
		avg
		count
		group_concat
			SELECT COUNT(*) FROM employee;
			SELECT COUNT(*) FROM employee WHERE depart_id=1;
			SELECT MAX(salary) FROM employee;
			SELECT MIN(salary) FROM employee;
			SELECT AVG(salary) FROM employee;
			SELECT SUM(salary) FROM employee;
			SELECT SUM(salary) FROM employee WHERE depart_id=3;

	having过滤:----------------------------------------select max(salary) from t1 whereid > 2 group by depart_id having count(id) > 2;
														select from t1 where id > 2 group by depart_id having 4 > 2;
														select post, count(id), group_concat(name) from emp group by post having count(id) < 2;
														select post, avg(salary) as 平均工资 from emp group by post having avg(salary) > 10000;
														select post岗位名, avg(salary) 平均工资 from emp group by post having avg(salary) > 10000;

	order by排序:--------------------------------------select * from emp order by salary;
														select * from emp order by salary asc;------------------------------------asc:升序
														select * from emp order by salary desc;-----------------------------------desc:降序
														select * from emp order by age asc, salary desc;--------------------------先按照年龄从小到大排,如果年龄分不出胜负(即值相同)再按照salary从大到小排。
														select * from emp order by age asc, hire_date desc;
														select post 岗位名, avg(salary) 平均工资 from emp group by post having avg(salary) > 10000 order by avg(salary) asc;

	limit限制结果的显示条数:----------------------------select * from emp limit 10;
														select * from emp limit 0, 3;----------------------------------------------从哪开始,往后取几条
														select * from emp limit 3, 3;
														select * from emp limit 6, 3;
														select name, id from emp where id > 15 having id > 16;

	distinct去重:--------------------------------------SELECT DISTINCT post FROM employee;

	使用正则表达式查询----------------------------------SELECT * FROM employee WHERE name REGEXP '^ale';
														SELECT * FROM employee WHERE name REGEXP 'on$';
														SELECT * FROM employee WHERE name RE GEXP 'm{2}';
										小结:对字符串匹配的方式
											WHERE name = 'egon';
											WHERE name LIKE 'yua%';
											WHERE name REGEXP 'on$';


*多表查询--------------------------------------------------多表查询--------------------------------------------------------
	简单查询----------------------------------------------------select * from department, employee;  
	
	笛卡尔积----------------------------------------------------select * from department, employee where department.id = employee.dep_id;

	内连接(inner join):按照on条件只两张表的相同的部分,连接成一张虚拟的表----select * from employee inner join department on department.id = employee.dep_id;
																			  select * from department inner join employee on department.id = employee.dep_id;
																			  select * from employee,department where department.id=employee.dep_id;

	左链接(left join): 按照on的条件取到两张表共同部分的基础上,保留左表的记录--select * from employee left join department on department.id = employee.dep_id;

	右链接(right join):按照on的条件取到两张表共同部分的基础上,保留右表的记录select * from employee right join department on department.id = employee.dep_id;
	
	全外连接(union):显示左右两个表全部记录----------------------------------select * from employee left join department on department.id = employee.dep_id
																		union select * from employee right join department on department.id = employee.dep_id;

	子查询:-----------------------------------------------select * from employee where dep_id in (select id from department where	name in ('技术', '销售'));
																+----+-----------+--------+------+--------+
																| id | name | sex | age | dep_id |
																+----+-----------+--------+------+--------+
																| 1 | egon | male | 18 | 200 |
																| 4 | yuanhao | female | 28 | 202 |
																| 5 | liwenzhou | male | 18 | 200 |
																+----+-----------+--------+------+--------+
	
	带EXISTS关键字的子查询:---------------------------------select * from employee where exists(select id from department where name = 'hahahahah');
															select * from employee where exists(select id from department where name = '技术');
															+----+------------+--------+------+--------+
																| id | name | sex | age | dep_id |
																+----+------------+--------+------+--------+
																| 1 | egon | male | 18 | 200 |. 
																| 2 | alex | female | 48 | 201 |
																| 3 | wupeiqi | male | 38 | 201 |
																| 4 | yuanhao | female | 28 | 202 |
																| 5 | liwenzhou | male | 18 | 200 |
																| 6 | jingliyang | female | 18 | 204 |
																+----+------------+--------+------+--------+
	
																
	查询平均年龄在25岁以上的部门名:
									select name from department where id in (select dep_id from employee group by dep_id having avg(age) > 25);
	查看技术部员工姓名:
					select name from employee where dep_id = (select id from department where name = '技术');

	查看小于2人的部门名
				select name from department where id in ( select dep_id from employee group by dep_id having count(id) < 2) union
				select name from department where id not in (select distinct dep_id from employee);

	提取空部门,有人的部门
				select * from department where id not in (select distinct dep_id from employee);
				select name from department where id in(
				select dep_id from employee group by dep_id having count(id) < 2 union select id from department whereid not in (
				select distinct dep_id from employee));


权限管理:-------------------------------------------------权限管理:------------------------------------------------------
		授权表:
			user ------------------------------------------------该表放行的权限,针对:所有数据,所有库下所有表,以及表下的所有字段
			db --------------------------------------------------该表放行的权限,针对:某一数据库,该数据库下的所有表,以及表下的所有字段
			tables_priv -----------------------------------------该表放行的权限。针对:某一张表,以及该表下的所有字段
			columns_priv ----------------------------------------该表放行的权限,针对:某一个字段

		按图解释:
			user:-----------------------------------------------放行db1,db2及其包含的所有
			db:-------------------------------------------------放行db1,及其db1包含的所有
			tables_priv:-----------------------------------------放行db1.table1,及其该表包含的所有
			columns_prive:---------------------------------------放行db1.table1.column1,只放行该字段
			
		创建用户:
			create user 'egon'@'1.1.1.1' identified by '123';
			create user 'egon'@'192.168.1.%' identified by '123';
			create user 'egon'@'%' identified by '123';
			
		授权:对文件夹,对文件,对文件某一字段的权限
			查看帮助:--------------------------------------------help grant
			常用权限有:------------------------------------------select,update,alter,delete
																  all可以代表除了grant之外的所有权限
			针对所有库的授权:*.*
				grant select on *.* to 'egon1'@'localhost' identified by '123'; -------只在user表中可以查到egon1用户的select权限被设置为Y

			针对某一数据库:db1.*
				grant select on db1.* to 'egon2'@'%' identified by '123'; -------------只在db表中可以查到egon2用户的select权限被设置为Y

			针对某一个表:db1.t1
				grant select on db1.t1 to 'egon3'@'%' identified by '123';  -----------只在tables_priv表中可以查到egon3用户的select权限

			针对某一个字段:
				grant select (id,name),update (age) on db1.t3 to 'egon4'@'localhost' identified by '123'; -----可以在tables_priv和columns_priv中看到相应的权限
			
		查看权限:
				mysql> select * from tables_priv where user='egon4'\G
				*************************** 1. row ***************************
					   Host: localhost
						 Db: db1
					   User: egon4
				 Table_name: t3
					Grantor: root@localhost
				  Timestamp: 0000-00-00 00:00:00
				 Table_priv:
				Column_priv: Select,Update
				row in set (0.00 sec)

				mysql> select * from columns_priv where user='egon4'\G
				*************************** 1. row ***************************
					   Host: localhost
						 Db: db1
					   User: egon4
				 Table_name: t3
				Column_name: id
				  Timestamp: 0000-00-00 00:00:00
				Column_priv: Select
				*************************** 2. row ***************************
					   Host: localhost
						 Db: db1
					   User: egon4
				 Table_name: t3
				Column_name: name
				  Timestamp: 0000-00-00 00:00:00
				Column_priv: Select
				*************************** 3. row ***************************
					   Host: localhost
						 Db: db1
					   User: egon4
				 Table_name: t3
				Column_name: age
				  Timestamp: 0000-00-00 00:00:00
				Column_priv: Update
				rows in set (0.00 sec)

		删除权限
			revoke select on db1.* from 'egon'@'%';

			
*索引:----------------------------------------------------索引------------------------------------------------------------
	1:为何要有索引?
		答:加速查询。
	2: 什么是索引?
		答:索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。相当与字典的音序表。
	3: 索引的优缺点?
		答:优点,加速查询。
		    缺点,加太多的索引,应用程序的性能可能会受到影响,占用磁盘。
			解决方法:去掉没必要的索引,只给需要快速查询的字段加索引
	4: 索引的原理?
		答:索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。
	
	5:索引的本质?
		答:本质都是:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,
		    同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,
			我们可以总是用同一种查找方式来锁定数据。
	6:索引的数据结构?
		答:b+树,---------------------------B+树是通过二叉查找树,再由平衡二叉树,B树演化而来。
		
	7:
		索引字段要尽量的小,索引的最左匹配特性
		
	8:索引分类:
			1、聚集索引
			2、辅助索引
				聚集索引与辅助索引相同的是:不管是聚集索引还是辅助索引,其内部都是B+树的形式,即高度是平衡的,叶子结点存放着所有的数据。
				聚集索引与辅助索引不同的是:叶子结点存放的是否是一整行的信息
	9:mysql的其他索引?
		答:mysql中的primary key,unique,联合唯一也都是索引,这些索引除了加速查找以外,还有约束的功能。
	
	Mysql索引管理:
		mysql常用的索引?
			普通索引:index------------------------------------------------加速查找
			
			唯一索引:
					主键索引:primary key----------------------------------加速查找+约束(不为空、不能重复)
					唯一索引:unique---------------------------------------加速查找+约束(不为空)
			联合索引:	
					联合住建索引:--------------------------------primary key(id,name)
					联合唯一索引:--------------------------------unique(id,name)
					联合普通索引:--------------------------------index(id,name)
		
		索引两大类型?
			hash类型的索引:------------------------------------------查询单条快,范围查询慢
			btree类型的索引:-----------------------------------------b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)		
			
		语法:
			方法一:创建表时---------------------create table t1(id int,name char,age int,sex enum('male','female'),unique key uni_id(id),index ix_name(name));
				  							 create table s1(id int,name char(6),age int,email varchar(30),index(id));
					CREATE TABLE 表名 (
								字段名1  数据类型 [完整性约束条件…],
								字段名2  数据类型 [完整性约束条件…],
								[UNIQUE | FULLTEXT | SPATIAL ]   INDEX | KEY
								[索引名]  (字段名[(长度)]  [ASC |DESC]) 
								);

			方法二:CREATE在已存在的表上创建索引--------------------------------------create index ix_age on t1(age);
																					  create index name on s1(name);-----------------------添加普通索引
																					  create unique index age on s1(age);------------------添加唯一索引
																					  alter table s1 add primary key(id);------------------添加主键索引
																					  create index name on s1(id,name);--------------------添加联合普通索引
					
					CREATE  [UNIQUE | FULLTEXT | SPATIAL ]  INDEX  索引名 
								 ON 表名 (字段名[(长度)]  [ASC |DESC]) ;

			方法三:ALTER TABLE在已存在的表上创建索引---------------------------------alter table t1 add index ix_sex(sex); 
																					  alter table s1 drop primary key;----------------------添加主键索引															  
					ALTER TABLE 表名 ADD  [UNIQUE | FULLTEXT | SPATIAL ] INDEX
										 索引名 (字段名[(长度)]  [ASC |DESC]) ;
               
			查看索引:----------------------------------------------------------------show create table t1
					mysql> show create table t1;
								| t1    | CREATE TABLE `t1` (
								  `id` int(11) DEFAULT NULL,
								  `name` char(1) DEFAULT NULL,
								  `age` int(11) DEFAULT NULL,
								  `sex` enum('male','female') DEFAULT NULL,
								  UNIQUE KEY `uni_id` (`id`),
								  KEY `ix_name` (`name`),
								  KEY `ix_age` (`age`),
								  KEY `ix_sex` (`sex`)
								) ENGINE=InnoDB DEFAULT CHARSET=latin1
			
			删除索引:DROP INDEX 索引名 ON 表名字;------------------------------------drop index id on s1;
																					  drop index name on s1;

	正确使用索引:
		如何命中索引?
			1:明确字段
			2:缩小范围
			3:尽量选择区分度高的列作为索引
			4:索引列不能参与计算,保持列“干净”
			5:最左前缀匹配原则。

		使用:
			1:加索引提速:范围
					mysql> select count(*) from s1 where id=1000;
						+----------+
						| count(*) |
						+----------+
						|        1 |
						+----------+
						1 row in set (0.12 sec)
					mysql> select count(*) from s1 where id>1000;
						+----------+
						| count(*) |
						+----------+
						|   298999 |
						+----------+
						1 row in set (0.12 sec)

					mysql> select count(*) from s1 where id=1000;
						+----------+
						| count(*) |
						+----------+
						|        1 |
						+----------+
						1 row in set (0.00 sec)

					mysql> select count(*) from s1 where id>1000;
						+----------+
						| count(*) |
						+----------+
						|   298999 |
						+----------+
						1 row in set (0.12 sec)

					mysql> select count(*) from s1 where id>1000 and id < 2000;
						+----------+
						| count(*) |
						+----------+
						|      999 |
						+----------+
						1 row in set (0.00 sec)
					mysql> select count(*) from s1 where id>1000 and id < 300000;
					+----------+
					| count(*) |
					+----------+
					|   298999 |
					+----------+
					1 row in set (0.13 sec)

			2:区分度低的字段不能加索引
						mysql> select count(*) from s1 where name='xxx';
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.00 sec)
						mysql> select count(*) from s1 where name='egon';
							+----------+
							| count(*) |
							+----------+
							|   299999 |
							+----------+
							1 row in set (0.19 sec)
						mysql> select count(*) from s1 where name='egon' and age=123123123123123;
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.45 sec)
					mysql> create index c on s1(age);
					Query OK, 0 rows affected (3.03 sec)
					Records: 0  Duplicates: 0  Warnings: 0
						mysql> select count(*) from s1 where name='egon' and age=123123123123123;
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.00 sec)
						mysql> select count(*) from s1 where name='egon' and age=10;
							+----------+
							| count(*) |
							+----------+
							|   299999 |
							+----------+
							1 row in set (0.35 sec)
						mysql> select count(*) from s1 where name='egon' and age=10 and id>3000 and id < 4000;
							+----------+
							| count(*) |
							+----------+
							|      999 |
							+----------+
							1 row in set (0.00 sec)
						mysql> select count(*) from s1 where name='egon' and age=10 and id>3000 and email='xxxx';
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.47 sec)
					mysql> create index d on s1(email);
					Query OK, 0 rows affected (4.83 sec)
					Records: 0  Duplicates: 0  Warnings: 0
						mysql> select count(*) from s1 where name='egon' and age=10 and id>3000 and email='xxxx';
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.00 sec)
					mysql> drop index a on s1;
					Query OK, 0 rows affected (0.10 sec)
					Records: 0  Duplicates: 0  Warnings: 0

					mysql> drop index b on s1;
					Query OK, 0 rows affected (0.09 sec)
					Records: 0  Duplicates: 0  Warnings: 0

					mysql> drop index c on s1;
					Query OK, 0 rows affected (0.09 sec)
					Records: 0  Duplicates: 0  Warnings: 0
						mysql> desc s1;
						+-------+-------------+------+-----+---------+-------+
							| Field | Type        | Null | Key | Default | Extra |
							+-------+-------------+------+-----+---------+-------+
							| id    | int(11)     | NO   |     | NULL    |       |
							| name  | char(20)    | YES  |     | NULL    |       |
							| age   | int(11)     | YES  |     | NULL    |       |
							| email | varchar(30) | YES  | MUL | NULL    |       |
							+-------+-------------+------+-----+---------+-------+
							4 rows in set (0.00 sec)

						mysql> select count(*) from s1 where name='egon' and age=10 and id>3000 and email='xxxx';
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.00 sec)

			3:增加联合索引,关于范围查询的字段要放到后面
				 select count(*) from s1 where name='egon' and age=10 and id>3000 and email='xxxx';
					index(name,email,age,id)
				 select count(*) from s1 where name='egon' and age> 10 and id=3000 and email='xxxx';
					index(name,email,id,age)
				 select count(*) from s1 where name like 'egon' and age= 10 and id=3000 and email='xxxx';
					index(email,id,age,name)
					mysql> desc s1;
						+-------+-------------+------+-----+---------+-------+
						| Field | Type        | Null | Key | Default | Extra |
						+-------+-------------+------+-----+---------+-------+
						| id    | int(11)     | NO   |     | NULL    |       |
						| name  | char(20)    | YES  |     | NULL    |       |
						| age   | int(11)     | YES  |     | NULL    |       |
						| email | varchar(30) | YES  |     | NULL    |       |
						+-------+-------------+------+-----+---------+-------+
					4 rows in set (0.00 sec)
						mysql> create index xxx on s1(age,email,name,id);
						Query OK, 0 rows affected (6.89 sec)
						Records: 0  Duplicates: 0  Warnings: 0

						mysql> select count(*) from s1 where name='egon' and age=10 and id>3000 and email='xxxx';
						+----------+
						| count(*) |
						+----------+
						|        0 |
						+----------+
						1 row in set (0.00 sec)

			4. 最左前缀匹配
				index(id,age,email,name)
				#条件中一定要出现id
				id
				id age
				id email
				id name
				email #不行
				mysql> select count(*) from s1 where id=3000;
					+----------+
					| count(*) |
					+----------+
					|        1 |
					+----------+
					1 row in set (0.11 sec)

				mysql> create index xxx on s1(id,name,age,email);
				Query OK, 0 rows affected (6.44 sec)
				Records: 0  Duplicates: 0  Warnings: 0

				mysql>  select count(*) from s1 where id=3000;
					+----------+
					| count(*) |
					+----------+
					|        1 |
					+----------+
					1 row in set (0.00 sec)
				mysql>  select count(*) from s1 where name='egon';
					+----------+
					| count(*) |
					+----------+
					|   299999 |
					+----------+
					1 row in set (0.16 sec)
				mysql>  select count(*) from s1 where email='[email protected]';
					+----------+
					| count(*) |
					+----------+
					|        1 |
					+----------+
					1 row in set (0.15 sec)
				mysql>  select count(*) from s1 where id=1000 and email='[email protected]';
					+----------+
					| count(*) |
					+----------+
					|        0 |
					+----------+
					1 row in set (0.00 sec)
				mysql>  select count(*) from s1 where email='[email protected]' and id=3000;
					+----------+
					| count(*) |
					+----------+
					|        0 |
					+----------+
					1 row in set (0.00 sec)

			5.索引列不能参与计算,保持列“干净”
						mysql> select count(*) from s1 where id=3000;
							+----------+
							| count(*) |
							+----------+
							|        1 |
							+----------+
							1 row in set (0.11 sec)
						mysql> create index xxx on s1(id,name,age,email);
						Query OK, 0 rows affected (6.44 sec)
						Records: 0  Duplicates: 0  Warnings: 0
						
						mysql>  select count(*) from s1 where id=3000;
							+----------+
							| count(*) |
							+----------+
							|        1 |
							+----------+
							1 row in set (0.00 sec)
						mysql>  select count(*) from s1 where name='egon';
							+----------+
							| count(*) |
							+----------+
							|   299999 |
							+----------+
							1 row in set (0.16 sec)

						mysql>  select count(*) from s1 where email='[email protected]';
							+----------+
							| count(*) |
							+----------+
							|        1 |
							+----------+
							1 row in set (0.15 sec)

						mysql>  select count(*) from s1 where id=1000 and email='[email protected]';
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.00 sec)

						mysql>  select count(*) from s1 where email='[email protected]' and id=3000;
							+----------+
							| count(*) |
							+----------+
							|        0 |
							+----------+
							1 row in set (0.00 sec)


查询优化神器-explain:-------------------------------------查询优化神器-explain--------------------------------------------
	关于explain命令相信大家并不陌生,具体用法和字段含义可以参考官网explain-output,
	这里需要强调rows是核心指标,绝大部分rows小的语句执行一定很快(有例外,下面会讲到)。
	所以优化语句基本上都是在优化rows。
	
	执行计划:让mysql预估执行操作(一般正确)
		all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
		id,email
		
		慢:
			select * from userinfo3 where name='alex'
			
			explain select * from userinfo3 where name='alex'
			type: ALL(全表扫描)
				select * from userinfo3 limit 1;
		快:
			select * from userinfo3 where email='alex'
			type: const(走索引)
	慢查询优化的基本步骤:
		0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
		1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
		2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
		3.order by limit 形式的sql语句让排序的表优先查
		4.了解业务方使用场景
		5.加索引时参照建索引的几大原则
		6.观察结果,不符合预期继续从0分析
	慢日志管理:
			慢日志
				- 执行时间 > 10
				- 未命中索引
				- 日志文件路径
				
			配置:
				- 内存
					show variables like '%query%';
					show variables like '%queries%';
					set global 变量名 = 值
				- 配置文件
					mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini'
					
					my.conf内容:
						slow_query_log = ON
						slow_query_log_file = D:/....
						
					注意:修改配置文件之后,需要重启服务
		
			MySQL日志管理:
				========================================================
				错误日志: 记录 MySQL 服务器启动、关闭及运行错误等信息
				二进制日志: 又称binlog日志,以二进制文件的方式记录数据库中除 SELECT 以外的操作
				查询日志: 记录查询的信息
				慢查询日志: 记录执行时间超过指定时间的操作
				中继日志: 备库将主库的二进制日志复制到自己的中继日志中,从而在本地进行重放
				通用日志: 审计哪个账号、在哪个时段、做了哪些事件
				事务日志或称redo日志: 记录Innodb事务相关的如事务执行时间、检查点等
				========================================================
				一、bin-log
				1. 启用
				# vim /etc/my.cnf
				[mysqld]
				log-bin[=dir\[filename]]
				# service mysqld restart
				2. 暂停
				//仅当前会话
				SET SQL_LOG_BIN=0;
				SET SQL_LOG_BIN=1;
				3. 查看
				查看全部:
				# mysqlbinlog mysql.000002
				按时间:
				# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56"
				# mysqlbinlog mysql.000002 --stop-datetime="2012-12-05 11:02:54"
				# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" --stop-datetime="2012-12-05 11:02:54" 

				按字节数:
				# mysqlbinlog mysql.000002 --start-position=260
				# mysqlbinlog mysql.000002 --stop-position=260
				# mysqlbinlog mysql.000002 --start-position=260 --stop-position=930
				4. 截断bin-log(产生新的bin-log文件)
				a. 重启mysql服务器
				b. # mysql -uroot -p123 -e 'flush logs'
				5. 删除bin-log文件
				# mysql -uroot -p123 -e 'reset master' 


				二、查询日志
				启用通用查询日志
				# vim /etc/my.cnf
				[mysqld]
				log[=dir\[filename]]
				# service mysqld restart

				三、慢查询日志
				启用慢查询日志
				# vim /etc/my.cnf
				[mysqld]
				log-slow-queries[=dir\[filename]]
				long_query_time=n
				# service mysqld restart
				MySQL 5.6:
				slow-query-log=1
				slow-query-log-file=slow.log
				long_query_time=3
				查看慢查询日志
				测试:BENCHMARK(count,expr)
				SELECT BENCHMARK(50000000,2*3);

				日志管理

								
*视图(view):----------------------------------------------视图------------------------------------------------------------
	视图:sql查询的虚拟表,非真实存在的,用户使用时只需要名称即可获取结果集,可以将结果当做表来使用,存到硬盘中。简化查询。----------------------------view
		语法:CREATE VIEW 视图名称 AS  SQL语句-------------------------------create view teacher_view as select tid from teacher where tname='李平老师';
			于是查询李平老师教授的课程名的sql可以改写为
			mysql> select cname from course where teacher_id = (select tid from teacher_view);
			+--------+
			| cname  |
			+--------+
			| 物理   |
			| 美术   |
			+--------+
			2 rows in set (0.00 sec)
		使用视图:
			修改视图,原始表也跟着改
				mysql> select * from course;
					+-----+--------+------------+
					| cid | cname  | teacher_id |
					+-----+--------+------------+
					|   1 | 生物   |          1 |
					|   2 | 物理   |          2 |
					|   3 | 体育   |          3 |
					|   4 | 美术   |          2 |
					+-----+--------+------------+
					rows in set (0.00 sec)

				mysql> create view course_view as select * from course; -------创建表course的视图
				Query OK, 0 rows affected (0.52 sec)
					mysql> select * from course_view;
					+-----+--------+------------+
					| cid | cname  | teacher_id |
					+-----+--------+------------+
					|   1 | 生物   |          1 |
					|   2 | 物理   |          2 |
					|   3 | 体育   |          3 |
					|   4 | 美术   |          2 |
					+-----+--------+------------+
					rows in set (0.00 sec)
				 
				mysql> update course_view set cname='xxx'; ---------------------更新视图中的数据
				Query OK, 4 rows affected (0.04 sec)
				Rows matched: 4  Changed: 4  Warnings: 0

				mysql> insert into course_view values(5,'yyy',2); --------------往视图中插入数据
				Query OK, 1 row affected (0.03 sec)

				mysql> select * from course; -----------------------------------发现原始表的记录也跟着修改了
				+-----+-------+------------+
				| cid | cname | teacher_id |
				+-----+-------+------------+
				|   1 | xxx   |          1 |
				|   2 | xxx   |          2 |
				|   3 | xxx   |          3 |
				|   4 | xxx   |          2 |
				|   5 | yyy   |          2 |
				+-----+-------+------------+
				rows in set (0.00 sec)
		修改视图:
			语法:ALTER VIEW 视图名称 AS SQL语句-----------------------------alter view teacher_view as select * from course where cid>3;
				mysql> alter view teacher_view as select * from course where cid>3;
				Query OK, 0 rows affected (0.04 sec)

				mysql> select * from teacher_view;
				+-----+-------+------------+
				| cid | cname | teacher_id |
				+-----+-------+------------+
				|   4 | xxx   |          2 |
				|   5 | yyy   |          2 |
				+-----+-------+------------+
				2 rows in set (0.00 sec)
		删除视图:
				语法:DROP VIEW 视图名称---------------------------DROP VIEW teacher_view

		
*触发器(trigger):-----------------------------------------触发器----------------------------------------------------------
	触发器:限定一个条件,一旦此条件为真,则触发一个动作,执行一条sql语句--------------------------trigger
	创建表:
			create table grade(id int primary key auto_increment,grade_name varchar(30),grade_score float,sex enum('男','女'));
			create table grr(id int primary key auto_increment,gname varchar(30),gscore float);
	创建触发器
			delimiter //  
			create trigger grade_g_s1
			after insert on grade for each row
			begin
			if NEW.grade_score < '80' then
				insert into grr(gname,gscore)values(NEW.grade_name,NEW.grade_score);
			end if;
			end //
			delimiter ;
	插入数据
			insert into grade(grade_name,grade_score,sex)values('贝贝',60.5,'男'),('晶晶',97.5,'女'),('欢欢',90,'女'),
			('莹莹',40,'男'),('妮妮',100,'女');

			
*事物(transaction):---------------------------------------事物------------------------------------------------------------
	事物:将某些操作多个sql作为原子操作,一旦某一个出现错误,就回滚到原始状态,从而保证数据的完整性,安全性。

			create table user(id int primary key auto_increment,name char(20),balane int);
			insert into user(name,balance)values('悟空',200),('八戒',200),('沙和尚',200);
			start transaction;
			update user1 set balance=100 where name ='悟空';
			update user1 set balance=210 where name='八戒';
			updaate user1 set balance=290 where name='沙和尚';
			rollback;
			commit;
			create table user1(id int primary key auto_increment,name char(32),balance int);
			insert into user1(name,balance) values('庞文废',200),('萧pt',200),('八哥',200);

			start transaction;
			update user1 set balance=100 where name='庞文废';
			update user1 set balance=210 where name='萧pt';
			updsate user1 set balance=290 where name='八哥';
			rollback; -------------------------------------------------------如果任意一条sql出现异常都应该回滚到初始状态
			commit; --------------------------------------------------------如果所有的sql都正常,应该执行commit

			
*存储过程(procedure):-------------------------------------存储过程--------------------------------------------------------
	存储过程是一系列可执行的sql语句,存储过程存储在mysql中,通过调用它的名字在内部执行一些sql.-----------------------procedure
	使用存储过程的优点:
		1 程序与数据实现解耦
		2 减少网络传输的数据量
		使用存储过程的优点:
	使用存储过程的缺点:
		扩展功能不方便
	创建无参存储过程--------------------------------------------------
		1:创建无参存储过程:
			delimiter //
			create procedure p1()
			begin
				select * from test;
				insert into test(username,dep_id) values('wsb',2);
			end //
			delimiter ;

		2:调用存储过程
			call p1(); ---------------------------------------------在mysql中调用
			cursor.callproc('p1') ----------------------------------在python中通过pymysql模块调用
	创建有参存储过程之in的使用---------------------------------------	
		1:创建有参存储过程之in的使用
			delimiter //
			create procedure p2(
				in m int,
				in n int,
			)
			begin
				select * from test where id between m and n;
			end //
			delimiter ;

		2:调用存储过程
			call p2(3,7); -------------------------------------------在mysql中调用
			cursor.callproc('p2',args=(3,7)) ------------------------在python中通过pymysql模块调用
	创建有参存储过程之out的使用--------------------------------------
		1:创建有参存储过程之out的使用
			delimiter //
			create procedure p3(
				in m int,
				in n int,
				out res int
			)
			begin
				select * from test where id between m and n;
				set res=1;
			end //
			delimiter ;

		2:调用存储过程
			在mysql中
				set @x=11111111111
				call p3(3,7,@x); #在mysql中调用, 查看结果:select @x;
			在python中
				res=cursor.callproc('p3',args=(3,7,123)) #@_p3_0=3,@_p3_1=7,@_p3_2=123
				print(cursor.fetchall()) #只是拿到存储过程中select的查询结果
				cursor.execute('select @_p3_0,@_p3_1,@_p3_2')
				print(cursor.fetchall()) #可以拿到的是返回值
	创建有参存储过程之inout的使用------------------------------------			
		创建有参存储过程之inout的使用
			delimiter //
			create procedure p4(
				inout m int
			)
			begin
				select * from test where id > m;
				set m=1;
			end //
			delimiter ;
		在mysql中
			set @x=2;
			call p4(@x);
			select @x;
			delimiter //
			create procedure p5(
				inout m int
			)
			begin
				select * from test11111111 where id > m;
				set m=1;
			end //
			delimiter ;

			set @x=2;
			call p5(@x);
			select @x;
	捕捉异常+事务----------------------------------------------------
			delimiter //
			create PROCEDURE p6(
				OUT p_return_code tinyint
			)
			BEGIN
				DECLARE exit handler for sqlexception
				BEGIN
					-- ERROR
					set p_return_code = 1;
					rollback;
				END;

				DECLARE exit handler for sqlwarning
				BEGIN
					-- WARNING
					set p_return_code = 2;
					rollback;
				END;

				START TRANSACTION;
					insert into test(username,dep_id) values('egon',1);
					DELETE from tb1111111; #执行失败
				COMMIT;

				-- SUCCESS
				set p_return_code = 0; #0代表执行成功

			END //
			delimiter ;


			用python模拟
				try:
					START TRANSACTION;
						DELETE from tb1; #执行失败
						insert into blog(name,sub_time) values('yyy',now());
					COMMIT;
					set p_return_code = 0; #0代表执行成功
				except sqlexception:
					set p_return_code = 1;
					rollback;
				except sqlwaring:
					set p_return_code = 2;
					rollback;

				mysql> show procedure status like 'p1%'; #查看某一类存储过程


*函数(function)--------------------------------------------函数------------------------------------------------------------
	Mysql中提供了许多的内置函数:
		如:聚合函数:AVG,min,max,sum等
			字符串函数:concat字符串拼接,conv进制装换,lower变小写,upper变小写等
			时间和日期函数:year,week,等
			加密函数,控制流函数,
			还可以自定制函数
	
	CREATE TABLE blog (
		id INT PRIMARY KEY auto_increment,
		NAME CHAR (32),
		sub_time datetime
	);

	INSERT INTO blog (NAME, sub_time)
	VALUES
		('第1篇','2015-03-01 11:31:21'),
		('第2篇','2015-03-11 16:31:21'),
		('第3篇','2016-07-01 10:21:31'),
		('第4篇','2016-07-22 09:23:21'),
		('第5篇','2016-07-23 10:11:11'),
		('第6篇','2016-07-25 11:21:31'),
		('第7篇','2017-03-01 15:33:21'),
		('第8篇','2017-03-01 17:32:21'),
		('第9篇','2017-03-01 18:31:21');

	select date_format(sub_time,'%Y-%m'),count(1) from blog group by date_format(sub_time,'%Y-%m');
	自定义函数
		mysql> select f1(1,2)
			-> ;
		+---------+
		| f1(1,2) |
		+---------+
		|       3 |
		+---------+
		1 row in set (0.00 sec)

		mysql> select f1(1,2) into @res;
		Query OK, 1 row affected (0.00 sec)

		mysql> select @res;
		+------+
		| @res |
		+------+
		|    3 |
		+------+
		1 row in set (0.00 sec)


流程控制(if....):------------------------------------------流程控制--------------------------------------------------------
	函数中不要写sql语句,它仅仅只是一个功能,是一个在sql中被应用的功能
	若要想在begin...end...中写sql,请用存储过程
		delimiter //
		create function f5(
			i int
		)
		returns int
		begin
			declare res int default 0;
			if i = 10 then
				set res=100;
			elseif i = 20 then
				set res=200;
			elseif i = 30 then
				set res=300;
			else
				set res=400;
			end if;
			return res;
		end //
		delimiter ;


		#while循环
		delimiter //
		CREATE PROCEDURE proc_while ()
		BEGIN

			DECLARE num INT ;
			SET num = 0 ;
			WHILE num < 10 DO
				SELECT
					num ;
				SET num = num + 1 ;
			END WHILE ;

		END //
		delimiter ;


分页(limt):-----------------------------------------------分页------------------------------------------------------------
		查询数据量大时使用,就是根据sql语句,加上限制条件,显示从第几条数据,到第几条数据。
		创建分页:sql查询+limt限制条件。limt,----------------------------------select * from sjdr_product_detail limit 0,5; 		


mysql数据库备份:------------------------------------------数据库备份------------------------------------------------------
	1. 物理备份:-----------------------------------------------------------直接复制数据库文件,适用于大型数据库环境。但不能恢复到异构系统中如Windows。
	2. 逻辑备份:-----------------------------------------------------------备份的是建表、建库、插入等操作所执行SQL语句,适用于中小型数据库,效率相对较低。
	3. 导出表:-------------------------------------------------------------将表导入到文本文件中。 	
	一、使用mysqldump实现逻辑备份:
		语法:-------------------------------------------------------------mysqldump -h 服务器 -u用户名 -p密码 数据库名 > 备份文件.sql

			示例:
				单库备份:--------------------------------------------------mysqldump -uroot -p123 db1 > db1.sql
																		   mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql

				多库备份:--------------------------------------------------mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql

				备份所有库:------------------------------------------------mysqldump -uroot -p123 --all-databases > all.sql

	二、恢复逻辑备份:
					方法一:----------------------------------------------- mysql -uroot -p123 < /backup/all.sql

					方法二:----------------------------------------------- use db1;
																			SET SQL_LOG_BIN=0;
																			source /root/db1.sql

						注:如果备份/恢复单个库时,可以修改sql文件
						DROP database if exists school;
						create database school;
						use school;

	三、备份/恢复案例:
				数据库备份/恢复实验一:数据库损坏
					备份:
					1. # mysqldump -uroot -p123 --all-databases > /backup/`date +%F`_all.sql
					2. # mysql -uroot -p123 -e 'flush logs' //截断并产生新的binlog
					3. 插入数据 //模拟服务器正常运行
					4. mysql> set sql_log_bin=0; //模拟服务器损坏
					mysql> drop database db;

					恢复:
					1. # mysqlbinlog 最后一个binlog > /backup/last_bin.log
					2. mysql> set sql_log_bin=0; 
					mysql> source /backup/2014-02-13_all.sql //恢复最近一次完全备份 
					mysql> source /backup/last_bin.log //恢复最后个binlog文件


				数据库备份/恢复实验二:如果有误删除
					备份:
					1. mysqldump -uroot -p123 --all-databases > /backup/`date +%F`_all.sql
					2. mysql -uroot -p123 -e 'flush logs' //截断并产生新的binlog
					3. 插入数据 //模拟服务器正常运行
					4. drop table db1.t1 //模拟误删除
					5. 插入数据 //模拟服务器正常运行

					恢复:
					1. # mysqlbinlog 最后一个binlog --stop-position=260 > /tmp/1.sql 
					# mysqlbinlog 最后一个binlog --start-position=900 > /tmp/2.sql 
					2. mysql> set sql_log_bin=0; 
					mysql> source /backup/2014-02-13_all.sql //恢复最近一次完全备份
					mysql> source /tmp/1.log //恢复最后个binlog文件
					mysql> source /tmp/2.log //恢复最后个binlog文件

				注意事项:
				1. 完全恢复到一个干净的环境(例如新的数据库或删除原有的数据库)
				2. 恢复期间所有SQL语句不应该记录到binlog中

	四、实现自动化备份:
					备份计划:
						1. 什么时间 2:00
						2. 对哪些数据库备份
						3. 备份文件放的位置
					备份脚本:
						[root@egon ~]# vim /mysql_back.sql
						#!/bin/bash
						back_dir=/backup
						back_file=`date +%F`_all.sql
						user=root
						pass=123
						if [ ! -d /backup ];then
						mkdir -p /backup
						fi

					备份并截断日志
						mysqldump -u${user} -p${pass} --events --all-databases > ${back_dir}/${back_file}
						mysql -u${user} -p${pass} -e 'flush logs'

					只保留最近一周的备份
						cd $back_dir
						find . -mtime +7 -exec rm -rf {} \;

					手动测试:
						[root@egon ~]# chmod a+x /mysql_back.sql 
						[root@egon ~]# chattr +i /mysql_back.sql
						[root@egon ~]# /mysql_back.sql

					配置cron:
						[root@egon ~]# crontab -l
						* * * /mysql_back.sql
	
	五、表的导出和导入:
					SELECT... INTO OUTFILE 导出文本文件
					示例:
					mysql> SELECT * FROM school.student1
					INTO OUTFILE 'student1.txt'
					FIELDS TERMINATED BY ',' //定义字段分隔符
					OPTIONALLY ENCLOSED BY '”' //定义字符串使用什么符号括起来
					LINES TERMINATED BY '\n' ; //定义换行符
					mysql 命令导出文本文件
					示例:
						# mysql -u root -p123 -e 'select * from student1.school' > /tmp/student1.txt
						# mysql -u root -p123 --xml -e 'select * from student1.school' > /tmp/student1.xml
						# mysql -u root -p123 --html -e 'select * from student1.school' > /tmp/student1.html

					LOAD DATA INFILE 导入文本文件
					mysql> DELETE FROM student1;
					mysql> LOAD DATA INFILE '/tmp/student1.txt'
					INTO TABLE school.student1
					FIELDS TERMINATED BY ','
					OPTIONALLY ENCLOSED BY '”'
					LINES TERMINATED BY '\n';
	
	六、数据库迁移:
		务必保证在相同版本之间迁移-----------------------------------------mysqldump -h 源IP -uroot -p123 --databases db1 | mysql -h 目标IP -uroot -p456

		
*pymysql模块:----------------------------------------------pymysql模块-----------------------------------------------------
		安装-----------------------------------pip3 install pymysql
		代码实现:
			import pymysql
			user=input('用户名: ').strip()
			pwd=input('密码: ').strip()

			#链接
			conn=pymysql.connect(host='localhost',user='root',password='123',database='egon',charset='utf8')
			#游标
			cursor=conn.cursor() #执行完毕返回的结果集默认以元组显示
			#cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)


			#执行sql语句
			sql='select * from userinfo where name="%s" and password="%s"' %(user,pwd) #注意%s需要加引号

			print(sql)
			res=cursor.execute(sql) #执行sql语句,返回sql查询成功的记录数目
			print(res)

			cursor.close()
			conn.close()

			if res:
				print('登录成功')
			else:
				print('登录失败')

		execute()之sql注入:
			注意:符号--会注释掉它之后的sql,正确的语法:--后至少有一个任意字符
		根本原理:就根据程序的字符串拼接name='%s',我们输入一个xxx' -- haha,用我们输入的xxx加'在程序中拼接成一个判断条件name='xxx' -- haha'
		最后那一个空格,在一条sql语句中如果遇到select * from t1 where id > 3 -- and name='egon';则--之后的条件被注释掉了
			#1、sql注入之:用户存在,绕过密码
			egon' -- 任意字符

			#2、sql注入之:用户不存在,绕过用户与密码
			xxx' or 1=1 -- 任意字符
		解决方法:
			# 原来是我们对sql进行字符串拼接
			# sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd)
			# print(sql)
			# res=cursor.execute(sql)

			#改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
			sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
			res=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
		增、删、改:conn.commit():
			import pymysql
			#链接
			conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
			#游标
			cursor=conn.cursor()

			#执行sql语句
			#part1
			# sql='insert into userinfo(name,password) values("root","123456");'
			# res=cursor.execute(sql) #执行sql语句,返回sql影响成功的行数
			# print(res)

			#part2
			# sql='insert into userinfo(name,password) values(%s,%s);'
			# res=cursor.execute(sql,("root","123456")) #执行sql语句,返回sql影响成功的行数
			# print(res)

			#part3
			sql='insert into userinfo(name,password) values(%s,%s);'
			res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #执行sql语句,返回sql影响成功的行数
			print(res)

			conn.commit() #提交后才发现表中插入记录成功
			cursor.close()
			conn.close()
		查:fetchone,fetchmany,fetchall:
			import pymysql
			#链接
			conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
			#游标
			cursor=conn.cursor()

			#执行sql语句
			sql='select * from userinfo;'
			rows=cursor.execute(sql) #执行sql语句,返回sql影响成功的行数rows,将结果放入一个集合,等待被查询

			# cursor.scroll(3,mode='absolute') # 相对绝对位置移动
			# cursor.scroll(3,mode='relative') # 相对当前位置移动
			res1=cursor.fetchone()
			res2=cursor.fetchone()
			res3=cursor.fetchone()
			res4=cursor.fetchmany(2)
			res5=cursor.fetchall()
			print(res1)
			print(res2)
			print(res3)
			print(res4)
			print(res5)
			print('%s rows in set (0.00 sec)' %rows)



			conn.commit() #提交后才发现表中插入记录成功
			cursor.close()
			conn.close()

			'''
			(1, 'root', '123456')
			(2, 'root', '123456')
			(3, 'root', '123456')
			((4, 'root', '123456'), (5, 'root', '123456'))
			((6, 'root', '123456'), (7, 'lhf', '12356'), (8, 'eee', '156'))
			rows in set (0.00 sec)
			'''
		获取插入的最后一条数据的自增ID:
			import pymysql
			conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
			cursor=conn.cursor()

			sql='insert into userinfo(name,password) values("xxx","123");'
			rows=cursor.execute(sql)
			print(cursor.lastrowid) #在插入语句后查看

			conn.commit()

			cursor.close()
			conn.close()
			
					
练习题:
	1、查询所有的课程的名称以及对应的任课老师姓名
		select cname,tname from course left join teacher on course.teacher_id=teacher.tid;

	2、查询学生表中男女生各有多少人
		select gender,count(sid) from student group by gender;

	3、查询物理成绩等于100的学生的姓名
		子查询的方式:
			select sname from student where sid in(select student_id from score where course_id = (select cid from course where cname='物理') and num=100);
		连表的方式
			select sname from student inner join(select student_id from score where course_id = (select cid from course where cname='物理') and num=100) as a
				on a.student_id=student.sid;
	
	4、查询平均成绩大于八十分的同学的姓名和平均成绩
		select student.sname,t1.平均成绩 from student inner join(
		select student_id,avg(num) 平均成绩 from score group by student_id having avg(num) > 80) as t1 on student.sid=t1.student_id;

	5、查询所有学生的学号,姓名,选课数,总成绩
		select student.sid,sname 学生名,选课数,总成绩 from student left join(
		select student_id,count(course_id) 选课数,sum(num) 总成绩 from score group by student_id) as t1 on student.sid=t1.student_id;

	6、 查询姓李老师的个数
		select count(tid) from teacher where tname like '李%';

	7、 查询没有报李平老师课的学生姓名
		select sname from student where sid not in (
		select distinct student_id from score where course_id in (
		select cid from course where teacher_id=(select tid from teacher where tname='李平老师')));

	8、 查询物理课程比生物课程高的学生的学号
		select t1.student_id from
		(select student_id,num from score inner join course on score.course_id=course.cid
		where course.cname='物理') as t1
		inner join(select student_id,num from score inner join course on score.course_id=course.cid
		where course.cname='生物') as t2
		on t1.student_id=t2.student_id
		where t1.num > t2.num;

	9、 查询没有同时选修物理课程和体育课程的学生姓名
		select sname from student where sid in (select student_id from score inner join course
		on course.cname in ('物理','体育') and course.cid=score.course_id
		group by student_id having count(course_id) !=2);

	10、查询挂科超过两门(包括两门)的学生姓名和班级名字
		select t2.sname,class.caption from(select sname,class_id from student inner join (
		select student_id from scorewhere num < 60 group by student_id having count(course_id) >=2) as t1
		on student.sid=t1.student_id) as t2 inner join class on class.cid = t2.class_id;

	11 、查询选修了所有课程的学生姓名
		select sname from student inner join(
		select student_id from score group by student_id having count(course_id) = (select count(cid) from course)) t1on t1.student_id = student.sid;
		select snam from student inner join(select student_id from score group by student_id having count(couder_id)=(selet count(cid) from couser
		) t1 on t1.student_id=student.id;

	12、查询李平老师教的课程的所有成绩记录
		select student_id,course_id,num from score inner join(
		select cid from course inner join teacher on teacher.tname='李平老师' and teacher.tid=course.teacher_id) as t1on t1.cid=score.course_id;
		
	13、查询全部学生都选修了的课程号和课程名
		select course.cid,course.cname from course inner join(select course_id from score group by course_id
		having count(student_id) = (select count(sid) from student)) t1 on t1.course_id=course.cid;
	14、查询每门课程被选修的次数
		select course.cname,选修人数 from course inner join(
		select course_id,count(student_id) as 选修人数 from score group by course_id) as t1 on t1.course_id=course.cid;
	15、查询之选修了一门课程的学生姓名和学号
		select sid,sname from student inner join(select student_id from score group by student_id having count(course_id)=1) t1 on t1.student_id = student.sid;
	16、查询所有学生考出的成绩并按从高到低排序(成绩去重)
		select distinct num from score order by num desc;
	
	17、查询平均成绩大于85的学生姓名和平均成绩
		select student.sname,avg_num from student inner join(
		select student_id,avg(num) as avg_num from score group by student_id having avg(num) > 85) t1on student.sid=t1.student_id;
	18、查询生物成绩不及格的学生姓名和对应生物分数
		select student.sname,t1.num from student inner join(select student_id,num from score where course_id=(
		select cid from course where cname='生物') and num < 60) t1on t1.student_id=student.sid;
	19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名
		select sname from student where sid =(select student_id from score where course_id in
		(select cid from course inner join teacher on teacher.tname='李平老师' and course.teacher_id=teacher.tid)group by student_id
		order by avg(num) desc limit 1);

  

猜你喜欢

转载自www.cnblogs.com/w-s-l123/p/9460342.html