参照mysql安装文档
语法:
select 查询列表 from 表名 where 筛选条件
分类:
条件运算符:>,<,=,!=,>=,<=
查询员工工资>1w2的员工信息 select * from employee where salary >12000; 查询部门编号!=90号的员工名和部门编号 select name, dep_id from employee where dep_id 1=90;逻辑运算符:&&,||,!,AND,OR,NOT
查询工资在一万到两万之见的员工名,工资以及奖金。 select name,salary ,jiangjin where salary between 10000 and 20000; 查询部门编号不在90-110之间,或者工资高于15000的员工信息。 select * from employee where department<90||department>110 ||salary >15000;like:一般和通配符搭配使用 通配符: %任意多个字符,包含0个字符 _任意单个字符 BETWEEN AND:包含临界值 IN:判断某个字段的值是否属于in列表中的某一项 IS NULL,IS NOT NULL:=或者!=不能用来判断null 安全等于<=>可以判断null
查询员工名中包含a的员工信息 select * from emp where name like %a%; 查询员工名中第三个字符为e第五个字符为a的员工名和工资 select name ,salary from emp where name like %__e_a%; 员工名中第二个字符为_的员工名 select name from emp where name like %_\_%; 查询员工编号在100到120之间的所有员工信息 select * from emp where id between 100 and 120; 查询员工的工种编号是IT_PRIG,AD_PRES,AD_VP中的一个员 工名和工种编号; select name , id from emp where id in(IT_PRIG,AD_PRES,AD_VP); 查询没有奖金的员工名和奖金率 select salary , jjl from emp where salary is Null; 查询有奖金的员工名和奖金率 select salary ,jjl from emp where salary is not null;语法:
select 查询列表
from 表
where 筛选条件
order by 排序列表 asc 或desc (升序或者降序,默认为升序)
查询员工信息,要求工资从高到低排序 select * from emp order by salary desc; 查询部门编号大于等于90的员工信息,按照入职时间先后排序 select * from emp where dep_id >=90 order by createtime asc; 按照员工年薪的高低显示员工的信息和年薪 select * ,年薪 from emp order by salary*(1+if null(jjl,0))*12 as 年薪 desc; 按姓名长度显示员工的姓名和工资 select name ,salary from emp order by length(name) asc; 查询员工信息,先按照工资排序,再按照员工编号排序 select * from emp order by salary asc,id asc;功能:类似Java中的方法 分类:单行函数 分组函数
功能:用作统计使用
1.sum :求和 SELECT SUM(salary) FROM employees; 2.avg:平均值 SELECT AVG(salary) FROM employees; 3.max:最大值 SELECT MAX(salary) FROM employees; 4.min:最小值 SELECT MIN(salary) FROM employees; 5.count:计算个数 SELECT COUNT(salary) FROM employees; 总结 ①.sum,avg一般用于处理数值类型 ②.max,min,count用来处理任何类型 ③.以上分组函数都忽略null值 ④.可以和distinct搭配 SELECT SUM(DISTINCT salary) 纯净,SUM(salary) FROM employees; 6.count的详细介绍 ①select COUNT(*) FROM employees; ②select COUNT(1) FROM employees; ③和分组函数一同查询的字段要求是group by后的字段。GROUP BY 和分组函数对应 分组查询中分组条件分为两类
数据源位置关键字分组前筛选原始表GROUP BY 子句的前面WHERE分组后筛选分组后的结果集GROUP BY 子句的后面HAVING分组函数做条件肯定是放在having子句中。 group BY 子句支持单个字段分组,多个字段分组 (多个字段之间用逗号隔开没有顺序要求),表达式或函数。 也可以添加排序,放在整个分组查询的最后。
案例:查询每个工种的最高工资 SELECT MAX(salary), job_id FROM employees GROUP BY job_id ORDER BY MAX(salary) ASC ; 案例:查询邮箱中包含a字符的,每个部门的平均工资 SELECT AVG(salary), department_id FROM employees WHERE email LIKE '%a%' GROUP BY department_id ; #select Avg(salary),dep_id from employee where email like %a% group by dep_id ; 案例:查询有奖金的每个领导手下员工的最高工资 SELECT MAX(salary), manager_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id ; #select max(salary) ,manage_id from employees where commission_pct is not null group by manager_id; 案例:哪个部门的员工个数大于二? SELECT COUNT(*), department_id FROM employees GROUP BY department_id HAVING COUNT(*) > 2 ; #select dep_id from emp group by dep_id having count(*)>2; 案例:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资 SELECT MAX(salary), job_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING MAX(salary) > 12000 ; #select job_id ,max(salary) from emp where commission_pct IS NOT NULL group by job_id having max(salary)>12000; 案例:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个? SELECT manager_id ,MIN(salary) FROM employees WHERE manager_id>102 GROUP BY manager_id HAVING MIN(salary)>5000; #select manager_id from emp where manager_id>102 group by manager_id having min(salary)>5000; #按照员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些? SELECT COUNT(*) AS c FROM employees GROUP BY LENGTH(last_name) HAVING c>5; # select count(*) from emp group by length(name) having count(*)>5; #查询每个部门每个工种的员工的平均工资 SELECT AVG(salary),job_id FROM employees GROUP BY department_id,job_id; #select avg(salary) from emp group by dep_id,job_id; #查询每个部门每个工种的员工的平均工资并且按照平均工资的高低显示 SELECT AVG(salary),job_id FROM employees GROUP BY department_id,job_id ORDER BY AVG(salary) ASC; #select avg(salary) from emp group by dep_id,job_id order by avg(salary) asc;又称为多表查询,当查询的字段来自多个表时,就会用到连接查询。 笛卡尔乘积现象:表1有m行,表2有n行,结果:m*n行 发生原因:没有有效的连接条件
分类
①按年代分类 sql92:仅仅支持内连接 sql99:不支持全外连接
②按功能分类
内连接外连接交叉连接等值连接左外连接非等值连接右外连接自连接全外连接①多表等值连接的结果为多表的交集部分 ②n表连接,至少需要n-1个连接条件 ③多表的顺序没有要求 ④一般需要为表起别名 ⑤可以搭配前面介绍的所有子句使用,比如排序,分组,筛选
#案例一:查询女优名对应的男优名 SELECT NAME, boyName FROM beauty, boys WHERE beauty.boyfriend_id = boys.`id` ; #select name, boyname from girl ,boy where girl.boyfriend_id=boy.id; #案例:查询员工名和对应的部门名 SELECT last_name, department_name FROM employees, departments WHERE employees.`department_id` = departments.`department_id` ; #select name ,dep_name from emp e,dep d where e.dep.id= d.id; #案例:查询员工名,工种号,工种名。 SELECT last_name, emp.`job_id`, job_title FROM employees emp, jobs job WHERE emp.`job_id` = job.`job_id` ; #select name , e.job_id,job_title from emp e,job j where e.job_id=j.id; #案例:查询有奖金的员工名和部门名 SELECT last_name, department_name FROM employees emp, departments dep WHERE commission_pct IS NOT NULL && emp.`department_id` = dep.`department_id` ; #select name ,dep_name from emp e ,dep d where e.dep_id =d.id &&e.salary_pct is not null; #案例:查询城市名第二个字符为o的部门 SELECT department_name FROM locations l, departments d WHERE l.`location_id` = d.`location_id` AND l.`city` LIKE '_o%' ; #select dep_name from location l , dep d where l.city like %_o% && l.id =d.location_id; #案例:查询每个城市的部门个数 SELECT COUNT(*), city FROM locations l, departments d WHERE l.`location_id` = d.`location_id` GROUP BY l.`city` ; #select count(*),city from loca l,dep d where l.loc_id=d.loc_id group by count(*) asc; #案例:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资 SELECT d.`department_name`, d.manager_id, MIN(salary) FROM employees e, departments d WHERE e.`department_id` = d.`department_id` AND e.`commission_pct` IS NOT NULL GROUP BY d.`department_id`, d.`department_name` ; #select dep_name ,d.manager_id ,min(salary) from emp e ,dep d where e.`department_id` = d.`department_id` AND e.`commission_pct` IS NOT NULL GROUP BY d.`department_id`,d.`department_name` ; #案例:查询每个工种的工种名和员工的个数,并且按照员工个数降序排序 SELECT j.job_title, COUNT(*) FROM jobs j, employees e WHERE j.`job_id` = e.`job_id` GROUP BY e.`job_id`, j.`job_title` ORDER BY COUNT(*) DESC ; #案例:查询员工名,部门名和所在城市 SELECT last_name, department_name, city FROM employees e, departments d, locations l WHERE e.`department_id` = d.`department_id` AND d.`location_id` = l.`location_id` ;INNER 可以省略
#查询员工名,部门名 SELECT last_name, department_name FROM employees e INNER JOIN departments d ON e.department_id = d.department_id ; #查询名字中包含e的员工名和工种名 SELECT last_name, job_title FROM employees e INNER JOIN jobs j ON e.job_id = j.job_id WHERE last_name LIKE '%e%' ; #查询部门个数>3的城市名和部门个数 SELECT city, COUNT(*) FROM departments d INNER JOIN locations l ON d.`location_id` = l.`location_id` GROUP BY city HAVING COUNT(*) > 3 ; #查询哪个部门的部门员工个数>3的部门名和员工个数,并按照个数降序排序 SELECT department_name, COUNT(*) FROM employees e INNER JOIN departments d ON e.`department_id` = d.`department_id` GROUP BY e.department_id HAVING COUNT(*) > 3 ORDER BY COUNT(*) DESC ; #查询员工名,部门名,工种名,并按照部门名降序排序 SELECT last_name, department_name, job_title FROM employees e INNER JOIN departments d ON e.`department_id` = d.`department_id` INNER JOIN jobs j ON e.`job_id` = j.`job_id` ORDER BY department_name DESC ; #查询员工工资级别 SELECT grade_level, salary FROM job_grades j INNER JOIN employees e ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal` ; #查询每个工资级别的个数,并且降序排序 SELECT grade_level,COUNT(*) FROM employees e INNER JOIN job_grades j ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal` GROUP BY grade_level ORDER BY COUNT(*) DESC; #查询员工的名字和上级的名字 SELECT e1.last_name, e2.last_name FROM employees e1 INNER JOIN employees e2 ON e1.`employee_id`=e2.`manager_id`;语法: SELECT 查询列表 FROM 表1 【连接类型】 JOIN 表2 ON 连接条件 WHERE 筛选条件 GROUP BY 分组 HAVING 筛选条件 ORDER BY 排序条件 连接类型: 内连接:inner 左外连接:left 右外连接:right 全外连接:full 交叉连接:cross 外连接 用于查询一个表中有,另一个表中没有的数据 左外连接,left左边是主表 右外连接,right右边是主表 Mysql不支持全外连接
#没有男朋友的女生 SELECT g.`name`,b.`boyName` FROM beauty g LEFT JOIN boys b ON g.`boyfriend_id`=b.`id` WHERE b.`boyName` IS NULL;笛卡尔乘积
出现在其它语句中的select语句,称为子查询或内查询 外部的查询语句,称为主查询或外查询 分类:
①按照子查询出现的位置:
select后面from后面where或having后面exists后面仅仅支持标量子查询支持表子查询标量子查询,列子查询表子查询②按照结果集的行列数不同:
标量子查询列子查询行子查询表子查询结果只有一行一列结果一列多行一行多列多行多列特点: 子查询一般放在小括号内 子查询一般放在条件的右边 标量子查询,一般搭配着单行操作符 列子查询:一般搭配多行操作符使用
1.标量子查询 #谁的工资比Abel高 SELECT last_name FROM employees WHERE salary > (SELECT salary FROM employees WHERE last_name = 'Abel') ; #返回job_id于141号员工相同,salary比143号员工多的员工 姓名,job_id和工资 SELECT last_name, job_id, salary FROM employees WHERE job_id = (SELECT job_id FROM employees WHERE employee_id = 141) AND salary > (SELECT salary FROM employees WHERE employee_id = 143) #返回公司工资工资最少的员工的姓名,job_id,salary SELECT last_name, job_id, salary FROM employees WHERE salary = (SELECT MIN(salary) FROM employees); #查询最低工资大于50号部门最低工资的部门id和其最低工资 SELECT department_id, MIN(salary) FROM employees GROUP BY department_id HAVING MIN(salary) > (SELECT MIN(salary) FROM employees WHERE department_id = 50) ; 2.列子查询 多行操作符: IN / NOT in:等于列表中的任意一个 ANY / SOME :和子查询返回的某一个值比较 ALL :和子查询返回的所有值比较 #返回location_id是1400或者1700的部门中的所有员工姓名 SELECT last_name FROM employees WHERE department_id IN (SELECT DISTINCT department_id FROM departments WHERE location_id IN (1400, 1700)) ; #返回其他工种中比job_id为IT_PROG部门任意工资低的员工 #工号,姓名,job_id以及salary SELECT employee_id, last_name, job_id, salary FROM employees WHERE salary < (SELECT MAX(salary) FROM employees WHERE job_id = 'IT_PROG') AND job_id !='IT_PROG'; #返回其他工种中比job_id为IT_PROG部门所有工资低的员工 #工号,姓名,job_id以及salary SELECT employee_id, last_name, job_id, salary FROM employees WHERE salary < (SELECT MIN(salary) FROM employees WHERE job_id = 'IT_PROG') AND job_id !='IT_PROG'; ********************************* 3.行子查询 #查询员工编号最小并且工资最高的员工信息 SELECT * FROM employees WHERE employee_id = (SELECT MIN(employee_id) FROM employees) AND salary = (SELECT MAX(salary) FROM employees)*语法:limit(currentPage-1)size,size
#查询前五条员工信息 SELECT * FROM employees LIMIT 0,5; #查询第11-25条员工信息 SELECT * FROM employees LIMIT 10,15; #查询有奖金的员工,并且工资最高的前十名显示出来 SELECT * FROM employees WHERE commission_pct IS NOT NULL ORDER BY salary DESC LIMIT 0 ,10;要查询的结果来自于多个表,且多个表没有直接的连接关系,单查询的信息一致时 特点: 1.要求多条查询语句的查询列数是一致的 2.要求多条查询语句的查询的每一列的类型和顺序最好一致 3.union关键字默认去重,如果使用union all 可以不去除重复项
案例:查询员工部门编号大于90或邮箱包含a的员工信息 SELECT * FROM employees WHERE department_id>90 UNION SELECT * FROM employees WHERE email LIKE '%a%';插入insert
一:插入语句 #插入beauty一行数据 INSERT INTO beauty(NAME,sex,borndate,phone,photo,boyfriend_id) VALUES('波多野吉依','女','1998-11-11','13342969497', NULL,10) #可以为null的列如何不插入值 直接写null,或列名少写一列 INSERT INTO beauty(NAME,sex,borndate,phone,photo,boyfriend_id) VALUES('小泽玛利亚','女','1999-11-11','13342456497', NULL,11) INSERT INTO beauty VALUES(15,'马蓉','女','1989-11-11','13342456123', NULL,12); INSERT INTO beauty SET id=16,NAME='刘亦菲', sex='女',borndate='1989-10-01', phone='15945231056',boyfriend_id=16; #insert 嵌套子查询,将一个表的数据插入另一张表 INSERT INTO beauty (NAME,sex,borndate,phone,boyfriend_id) SELECT '妲己','女','1111-11-11','13146587954',0;修改update
二,修改 UPDATE beauty SET phone='110' WHERE id=16; 多表修改:sql99 UPDATE 表1 别名 INNER|LEFT|RIGHT JOIN 表2 别名 ON 连接条件 SET 列=值 WHERE 筛选条件 #修改张无忌的女朋友手机号为114 UPDATE beauty g INNER JOIN boys b ON g.boyfriend_id=b.id SET g.phone='114' WHERE b.boyName='张无忌'; #修改没有男朋友的女生的男朋友编号都为4号 UPDATE beauty g LEFT JOIN boys b ON g.`boyfriend_id`=b.id SET g.`boyfriend_id`=4 WHERE b.id=NULL;删除delete
三,删除 DELETE 和 TRUNCATE 的区别: 1.delete可以加where条件,truncate不行 2.truncate删除效率高 3.加入要删除的表中有自增列, 用delete删除整个表后在插入数据,从断点处开始插入 用truncate删除后在插入数据,从1开始。 4.truncate删除没有返回值,delete有返回值 5.truncate删除不能回滚,delete删除可以回滚 DELETE FROM beauty WHERE id=17; 语法:truncate TABLE 表名; #删除张无忌的女朋友的信息 DELETE g FROM beauty g INNER JOIN boys b ON g.boyfriend_id=b.id WHERE b.id=1; #删除黄晓明以及他女朋友的信息 DELETE b,g FROM beauty g INNER JOIN boys b ON b.`id`=g.`boyfriend_id` WHERE b.`boyName`='黄晓明'; 多表删除 :TRUNCATE TRUNCATE TABLE boys数值型 1.整型
TINYINTSMALLINTMEDIUMINTINT/INTEGERBIGINT12348 如何设置无符号和有符号(默认有符号) DROP TABLE tab_int; CREATE TABLE tab_int(t1 INT,t2 INT UNSIGNED); INSERT INTO tab_int(t1,t2) VALUES(-1,1); DESC tab_int;1)如果插入的数值超出了整形的范围,会报out of range异常,并且插入 临界值。 2)如果不设置长度,会有默认的长度。 长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须搭配 zerofill使用。 2.小数 ①定点数 dec(M,D) ②浮点数 float(4) ,double(8) M,D的意思:M指定一共多少位,D指定小数几位,超出会四舍五入。 MD都可以省略, 如果是dec,则M默认为10,D默认为0 如果是浮点数,则会根据插入数值的精度改变精度 定点型精度相对较高。 3.字符型 ①较短的文本 CHAR(M)默认为1,VARCHAR(M) M:字符数 char:固定长度字符,比较耗费空间,但是效率高。 varchar:可变长度字符
ENUM 枚举类 CREATE TABLE tab_char( t1 ENUM('a','c','b') ); SET 集合 CREATE TABLE tab_set( s1 SET('a','b','c','d') ); INSERT INTO tab_set(s1) VALUES('a,b');BINARY:保存较短的二进制。 ②较长的文本 text(文本),BLOB(较大的二进制) 4.日期型 DATE:日期 DATETIME:日期加时间,8字节 timestamp:跟时区有关系,建议使用,4字节 time:时间 year:年
CREATE TABLE tab_date( t1 DATETIME, t2 TIMESTAMP ); INSERT INTO tab_date(t1,t2) VALUES(NOW(),NOW()); SELECT * FROM tab_date; SET time_zone='+9:00'; #设置时区为东9区含义:一种限制,用于限制表中的数据,保证数据的一致性。
NOT NULL
DEFAULT
PRIMARY KEY 唯一,且不为空
UNIQUE 唯一,可以为空
CHECK Mysql不支持
FOREIGN KEY 外键约束,用于限制两个表的关系, 用于保证该字段的值必须来自于主表的关联列的值。 约束的分类: 列级约束:除外键约束 表级约束:除了非空,默认。 CREATE TABLE 表名( 字段1 字段类型 列级约束, 字段2 字段类型 列级约束, 表级约束 );
#创建表时添加列级约束 DROP TABLE tab_test; CREATE TABLE tab_test( id INT PRIMARY KEY, stu_name VARCHAR(20) NOT NULL, gender CHAR DEFAULT '男', seat_id INT UNIQUE, major_id INT REFERENCES tab_major(id) ); CREATE TABLE tab_major( id INT PRIMARY KEY , major_name VARCHAR(20) NOT NULL ); DESC tab_test; SHOW INDEX FROM tab_test; #查看索引信息 #添加表级约束 CREATE TABLE tab_test( id INT PRIMARY KEY AUTO_INCREMENT, stu_name VARCHAR(20) NOT NULL, gender CHAR DEFAULT '男', seat_id INT UNIQUE, major_id INT , CONSTRAINT m_id FOREIGN KEY(major_id) REFERENCES tab_major(id) ); CONSTRAINT m_id 可以省略面试题:主键约束和唯一约束的区别: 都可以保证唯一性, 主键不能为空 ,unique 能为空,但是只能有一个null。 主键只能有1个,unique可以有多个。 都允许两个列组合成一个约束。 面试题:外键: 要求在从表设置外键关系 从表的外键列类型和主表的关联列类型一致,名称无要求 要求主表的关联列必须是主键或者唯一键 插入数据应该先插入主表再插入从表 删除数据应该先删除从表,在删除主表 二,修改表时添加约束
CREATE TABLE tab_test2( id INT , stu_name VARCHAR(20) , gender CHAR , seat_id INT , major_id INT ); ALTER TABLE tab_test2 MODIFY COLUMN stu_name VARCHAR(20) NOT NULL ; ALTER TABLE tab_test2 MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT; #添加外键 ALTER TABLE tab_test2 ADD FOREIGN KEY(major_id) REFERENCES tab_major(id);自增长列 AUTO_INCREMENT 特点: 1.表示必须和一个key搭配 2.一个表最多一个标识列 3.标识列类型只能是数值型 4.标识列可以通过set auto_increment_increment=3;设置步长
CREATE tab_auto( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL );事务:一个或一组sql语句组成的执行单元,
要么全部执行,要么都不执行。 存储引擎:在MySQL中的数据用各种不同的技术存储在文件中。 通过show ENGINES;来查看mysql支持的存储引擎。 innodb引擎支持事务。 事务的ACID属性: 1.原子性:事务是一个不可分割的工作单位,要么都发生,要么都不发生。 2.一致性:事务必须使数据库从一个一致性状态变为另一个一致性状态。 3.隔离性:一个事务的执行不能被另一个事务干扰。 4.持久性:事务一旦被提交,对数据库事务的改变就是永久性的。
DELETE 和 TRUNCATE 在事务中的区别:
演示delete SET autocommit=0; START TRANSACTION; DELETE FROM tab_teacher; ROLLBACK; 演示 TRUNCATE SET autocommit=0; START TRANSACTION; TRUNCATE TABLE tab_teacher; ROLLBACK; DELETE 是直接删除表中数据,truncate是江表删除,创建一张与原来一样的空表。含义:虚拟表,和普通表格一样使用 通过表动态生成的数据
语法: CREATE VIEW 视图名 AS 查询语句 ;
# 案例:查询姓名中包含a字符的员工名,部门名和工种信息 create view view1 as select e.last_name,d.department_name ,j.job_title from employees e inner join departments d on e.department_id = d.department_id inner join jobs j on e.job_id = j.job_id where e.last_name like '%a%'; select * from view1; # 案例:查询各个部门的平均工资级别 create view view2 as select j.grade_level ,aa.department_id from job_grades j inner join (select avg(salary) avg_s,department_id from employees group by department_id) aa on aa.avg_s between j.lowest_sal and j.highest_sal; select * from view2; # 案例:查询平均工资最低的部门信息 create view view3 as select avg(salary) avg_s ,department_id from employees group by department_id order by avg_s asc limit 1; select * from view3;①create OR REPLACE VIEW 视图名 AS 查询语句; ②alter VIEW 视图名 AS 查询语句;
DROP VIEW v1,v2;
DESC v1;
#创建视图emp_v1,要求查询电话号码以011开头的员工姓名和工资,邮箱 CREATE VIEW emp_v1 AS SELECT last_name ,salary,email FROM employees WHERE phone_number LIKE '%011'; #创建视图emp_v2,要求查询部门的最高工资高于12000的部门信息 CREATE VIEW v4 AS SELECT department_id FROM employees GROUP BY department_id HAVING MAX(salary)> 12000; CREATE VIEW emp_v2 AS SELECT * FROM departments WHERE department_id IN(SELECT * FROM v4);视图的可更新性和视图中查询的定义有关,以下类型的视图是不能更新的。 1.包含以下关键字的sql语句:分组函数,distinct,group by,having,union 2.常量视图 3.select中包含子查询的 4.join 5.from 一个不能更新的视图 6.where子句的子查询引用了from子句的表
系统变量 :变量由系统提供,不是用户自定义,属于服务器层面。 查看系统所有变量:show GLOBAL VARIABLES; 查看满足条件的部分系统变量: SHOW GLOBAL VARIABLES LIKE ‘%char%’; 查看指定的某个系统变量的值: SELECT @@global.autocommit; 为某个系统变量赋值:set @@global.系统变量名=值; 全局变量:GLOBAL 作用域:服务器每次启动将为所有的全局变量赋初始值,针对于所有的会话有效,但不能 跨重启。 会话变量:SESSION 作用域:针对当前的会话有效。 用户自定义变量 用户变量 声明: SET/SELECT @用户变量名 :=值; 赋值:通过 SELECT 字段 INTO 变量名;或 SET/SELECT @用户变量名 :=值; 使用:select @用户变量名; 应用在任何地方。 作用域:针对当前会话和连接有效。 局部变量 作用域:作用在定义它的begin END 块中。 声明: DECLARE 变量名 类型 (default 值); 赋值:通过 SELECT 字段 INTO 变量名;或 SET/SELECT @变量名 :=值; 使用:select @变量名; 只能放在begin END 中的第一句话
一组预先定义好的sql语句集合,理解成批处理语句。 1.提高代码的重用性 2.简化操作 3.减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率。
CREATE PROCEDURE 存储过程名(参数列表) BEGIN 一组合法的sql语句; END 参数列表:参数模式 参数名 参数类型
参数模式: in:该参数可以作为输入,也就是该参数需要调用方传入值 OUT :该参数可以作为输出,也就是该参数可以作为返回值 inout:该参数既可以作为输入又可以作为输出
如果存储过程只有一句话,begin END 可以省略
存储过程体中的每条sql语句的结尾需要必须加分号, 存储过程的结尾可以使用 DELIMITER 重新设置。
CALL 存储过程名(实参列表);
存储过程可以有0/n个返回值:适合批量增删改 函数有且仅有一个返回值:适合查询
注意: 参数列表:参数名,参数类型 一定会有return语句
SELECT 函数名(参数列表)
#返回公司员工个数 DELIMITER $ CREATE FUNCTION my_f1() RETURNS INT BEGIN DECLARE c INT DEFAULT 0 ; SELECT COUNT(*) INTO c FROM employees; RETURN c; END $ SELECT my_f1(); #根据员工名返回他的工资 DELIMITER $ CREATE FUNCTION my_f2(NAME VARCHAR(20)) RETURNS DOUBLE BEGIN DECLARE c DOUBLE; SELECT salary INTO c FROM employees WHERE last_name=NAME; RETURN c; END $ SET @a='Hunold'; SELECT my_f2(@a);如果表达式1成立,就返回表达式2的值,否则返回表达式3的值。 应用在任何地方
语法: CASE 要判断的字段或者表达式 WHEN 常量1 THEN 要显示的值1或者语句1 WHEN 常量2 THEN 要显示的值2或者语句2 … ELSE 要显示的值n或者语句n;
案例:查询员工的工资,要求 部门号==30,显示的工资为1.1倍, 部门号==40,显示的工资为1.2倍, 部门号==50,显示的工资为1.3倍, 其他部门,显示原有工资。 SELECT salary AS 原始工资, department_id , CASE department_id WHEN 30 THEN salary * 1.1 WHEN 40 THEN salary * 1.2 WHEN 50 THEN salary * 1.3 ELSE salary END AS 新工资 FROM employees ;语法: CASE WHEN 条件1 THEN 要显示的值1或语句1 WHEN 条件2 THEN 要显示的值2或语句2 … ELSE 要显示的值n或语句n END
案例:查询员工的工资情况 如果>2w,显示A 如果>1.5w,显示B 如果>1w,显示C 否则,显示D SELECT salary, CASE WHEN salary > 20000 THEN 'A' WHEN salary > 15000 THEN 'B' WHEN salary > 10000 THEN 'C' ELSE 'D' END AS 工资等级 FROM employees 可以放在任何地方 #创建存储过程,根据传入的成绩,显示等级,90A,80B,70C,60D ,F DELIMITER $ CREATE PROCEDURE my_1(IN score INT) BEGIN CASE WHEN score BETWEEN 90 AND 100 THEN SELECT 'A'; WHEN score BETWEEN 80 AND 90 THEN SELECT 'B'; WHEN score BETWEEN 70 AND 80 THEN SELECT 'C'; WHEN score BETWEEN 70 AND 60 THEN SELECT 'D'; ELSE SELECT 'E'; END CASE; END $ CALL my_1(95);语法: IF 条件1 THEN 语句1; ELSEIF 条件2 THEN 语句2; … ELSE 语句n; END IF; 只能用在begin end中
#创建存储过程,根据传入的成绩,返回等级,90A,80B,70C,60D ,F DELIMITER $ CREATE FUNCTION my_2( score INT) RETURNS CHAR BEGIN IF score >=90 THEN RETURN'A'; ELSEIF score >=80 THEN RETURN'B'; ELSEIF score >=70 THEN RETURN'C'; ELSEIF score >=60 THEN RETURN'D'; ELSE RETURN'E'; END IF; END $ SELECT my_2(85);在存储过程或函数里面使用
语法: 标签:WHILE 循环条件 DO 循环体; END WHILE 标签; 循环控制和标签搭配使用
语法: 标签: LOOP 循环体; END LOOP 标签;
语法: 标签: REPEAT 循环体; UNTIL 结束循环的条件 END REPEAT 标签;
循环控制 ITERATE 类似continue LEAVE 类似break
left join==left outer join
a left join b 就是取a和b的交集加a剩下的部分
inner join
a inner join b就是取交集
出现乱码问题如何解决:
vim /etc/my.conf
最后加上一句话: character_set_server=utf8 修改已经创建好的库和表的字符集 alter database xxx character set 'utf8'; alter table xxx convert to character set 'utf8';
远程访问权限问题: 1.创建新用户: create user username identified by 'password'; 此时默认支持所有访问,但是权限很低。 2.创建用户并授权: grant all privileges on *.*to用户@'%' identified by 'password'; 3.修改某个用户密码: update mysql.user set password=password('123456')where user='lisi';
group by使用原则:select 后面只能放 函数 和group by后的字段
1.去连接池获取连接
2.查询缓存,如果有直接返回,如果没有执行第3步。
3.sql接口分析
4.sql解析器解析复杂sql
5.sql优化器,不改变结果的前提下,生成优化计划
6.存储引擎按照计划分类型执行
7.查询结果存入缓存
8.返回结果
1、show engines;#查看MySQL所有的引擎,
2、show variables like "storage_engine%";查看当前正在使用的引擎
NDB 存储引擎 2003 年,MySQL AB 公司从 Sony Ericsson 公司收购了 NDB 存储引擎。 NDB 存储引擎是一个集群存储引擎,类似于 Oracle 的 RAC 集群,不过与 Oracle RAC 的 share everything 结构不同的是,其结构是 share nothing 的集群架构,因此能提供更高级别的 高可用性。NDB 存储引擎的特点是数据全部放在内存中(从 5.1 版本开始,可以将非索引数 据放在磁盘上),因此主键查找(primary key lookups)的速度极快,并且能够在线添加 NDB 数据存储节点(data node)以便线性地提高数据库性能。由此可见,NDB 存储引擎是高可用、 高性能、高可扩展性的数据库集群系统,其面向的也是 OLTP 的数据库应用类型。
Memory 存储引擎 正如其名,Memory 存储引擎中的数据都存放在内存中,数据库重 启或发生崩溃,表中的数据都将消失。它非常适合于存储 OLTP 数据库应用中临时数据的临时表,也可以作为 OLAP 数据库应用中数据仓库的维度表。Memory 存储引擎默认使用哈希 索引,而不是通常熟悉的 B+ 树索引。
Infobright 存储引擎 第三方的存储引擎。其特点是存储是按照列而非行的,因此非常 适合 OLAP 的数据库应用。其官方网站是 http://www.infobright.org/,上面有不少成功的数据 仓库案例可供分析。
NTSE 存储引擎 网易公司开发的面向其内部使用的存储引擎。目前的版本不支持事务, 但提供压缩、行级缓存等特性,不久的将来会实现面向内存的事务支持。
BLACKHOLE 黑洞存储引擎,可以应用于主备复制中的分发主库。
索引是数据结构
索引的目的是提高查询效率,可以类比字典。
优点:查询,排序快。
缺点:写操作慢,占用磁盘空间。
非叶子节点:数据,向下的指针,指向数据的指针(二叉树)
非叶子节点:数据,向下的指针(平衡二叉树)
mysql选择B+Tree
一张表聚簇索引只有一个:主键索引
其他,通过命令创建的索引都是非聚簇索引
create index idx_name on t_emp(name);
create unique index idx_empno on t_emp(empno);
表的主键指定后,建表时自动创建。
create index idx_age_deptId_name on t_emp(age,deptId,name);
show index from t_emp;
drop index indexName on 表名
1)主键自动建立唯一索引
2)频繁作为查询条件的字段应该创建索引
3)查询中与其他表关联的字段,外键关系建立索引
4)单键/组合索引的选择问题,组合索引性价比更高
5)查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
6)查询中统计或者分组字段
1)表记录太少
2)经常增删改的表或字段
3)Where条件里用不到的字段不创建索引
4)过滤性不好的不适合建索引
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈
1)表的读取顺序
2)哪些索引可以使用
3)数据读取操作的操作类型
4)哪些索引被实际使用
5)表之间的引用
6)每张表有多少行被物理查询
id相同,执行顺序由上到下
id不同,执行顺序从大到小
id既有相同又有不同,先从大到小,在从上到下
关注点:id每个号码,表示一趟独立的查询。一个sql的查询趟数越少越好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPXzBxAE-1601998234924)(img/mysql11111111.png)]
ALL,全表扫描,建索引优化
INDEX,使用了索引但是没用通过索引进行过滤
RANGE,使用了索引,但是过滤条件是范围查询
定义:where后面筛选字段命中索引长度
key_len规则:数值越大,查询越快
定义:整个sql物理扫描的行数(预估)
Rows规则:数值越小,查询越快
Using filesort orderby没有用上索引
Using temporary groupby没有用上索引
Using join buffer join字段没有用上索引
随机产生字符串
DELIMITER $$ CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) BEGIN DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; DECLARE return_str VARCHAR(255) DEFAULT ''; DECLARE i INT DEFAULT 0; WHILE i < n DO SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1)); SET i = i + 1; END WHILE; RETURN return_str; END $$ #假如要删除 #drop function rand_string;随机产生部门编号
#用于随机产生多少到多少的编号 DELIMITER $$ CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11) BEGIN DECLARE i INT DEFAULT 0; SET i = FLOOR(from_num +RAND()*(to_num -from_num+1)) ; RETURN i; END$$ #假如要删除 #drop function rand_num;#执行存储过程,往dept表添加1w条数据
#执行存储过程,往dept表添加1万条数据 DELIMITER ; CALL insert_dept(10000);#执行存储过程,往emp表添加50w条数据
#执行存储过程,往emp表添加50万条数据 DELIMITER ; CALL insert_emp(100000,500000);SQL语句
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND deptId=4 AND emp.name='abcd'; #创建索引前:0.069s #创建索引后:创建索引前
CREATE INDEX idx_age_deptId_name ON emp(age,deptId,NAME);结论:过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。
is not null 无法使用索引,但是is null可以使用
UPDATE emp SET age =NULL WHERE id=123456; CREATE INDEX idx_age ON emp(age); EXPLAIN SELECT * FROM emp WHERE age IS NULL EXPLAIN SELECT * FROM emp WHERE age IS NOT NULL对于单键索引,尽量选择针对当前query过滤性更好的索引
在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好
在选择组合索引的时候,尽量选择可以能够包含当前query中的where字句中更多字段的索引
在选择组合索引的时候,如果某个字段可能出现范围查询时,尽量吧这个字段放在索引次序的最后面
书写sql语句时,尽量避免造成索引失效的情况
#添加索引后
DELETE FROM class WHERE id<5; EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;#可以看到第二行的 type 变为了 ref,rows 也变成了优化比较明显。 #这是由左连接特性决定的。LEFT JOIN 条件用于确定如何从右表搜索行,左边一定都有, #所以右边是我们的关键点,一定需要建立索引。
#可以看到左表的索引对优化没啥卵用
1)保证被驱动表的join字段已经被索引
2)left join时,选择小表作为驱动表,大表作为被驱动表
3)inner join ,mysql会自己帮你吧结果集小的表选为驱动表
4)子查询尽量不要放在被驱动表,有可能使用不到索引
5)能够直接多表关联的尽量直接多表关联,不用子查询
#取所有不为掌门人的员工,按年龄分组 ,每个年龄段多少人
CREATE INDEX idx_ceo ON dept(ceo); EXPLAIN SELECT SQL_NO_CACHE age,COUNT(*) FROM emp a WHERE id NOT IN(SELECT ceo FROM dept b2 WHERE ceo IS NOT NULL) GROUP BY age HAVING COUNT(*)<10000; EXPLAIN SELECT SQL_NO_CACHE * FROM emp a LEFT JOIN dept b ON a.`id`=b.`CEO` WHERE b.`id` IS NULL;尽量不要使用not in 或者 not exists,用left outer join on xxx is null 替代
(1)无过滤,不索引
CREATE INDEX idx_age_deptid ON emp(age,deptid); EXPLAIN SELECT SQL_NO_CACHE * FROM emp ORDER BY age,deptid; EXPLAIN SELECT SQL_NO_CACHE * FROM emp ORDER BY age,deptid LIMIT 10;(2)顺序错,必排序
CREATE INDEX idx_deptid_age ON emp(deptid,age); EXPLAIN SELECT id,NAME,age,deptid,empno FROM emp WHERE deptid=45 ORDER BY age;有orderby的查询语句,必须将where后的字段和orderby后的字段都搞成一个索引或者只写where后面的字段,才会生效。
但是吧where和orderby一起写了效率高。
(3)方向反,必排序
建立3个字段的索引
建立两个字段的索引,但是需要在范围和排序中选一个
单路排序比双路排序要快
group by 使用索引的原则几乎跟order by一致 ,唯一区别是groupby 即使没有过滤条件用到索引,也可以直接使用索引
查询语句,不要写select * ,要写具体字段
MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。
具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10秒以上的语句。
由他来查看哪些SQL超出了我们的最大忍耐时间值,比如一条sql执行超过5秒钟,我们就算慢SQL,希望能收集超过5秒的sql,结合之前explain进行全面分析。
默认情况下,MySQL数据库没有开启慢查询日志,需要我们手动来设置这个参数。
当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件
默认情况下slow_query_log的值为OFF,表示慢查询日志是禁用的, 可以通过设置slow_query_log的值来开启
使用set global slow_query_log=1;开启了慢查询日志只对当前数据库生效, 如果MySQL重启后则会失效。
全局变量设置,对当前连接不影响,因此
SET SESSION long_query_time =1; SHOW VARIABLES LIKE '%long_query_time%';
如果要永久生效,就必须修改配置文件my.cnf(其它系统变量也是如此)
修改my.cnf文件,[mysqld]下增加或修改参数 slow_query_log和slow_query_log_file后,然后重启MySQL服务器。也即将如下两行配置进my.cnf文件
slow_query_log =1 slow_query_log_file=/var/lib/mysql/atguigu-slow.log
关于慢查询的参数slow_query_log_file,它指定慢查询日志文件的存放路径,系统默认会给一个缺省的文件host_name-slow.log(如果没有指定参数slow_query_log_file的话)
这个是由参数long_query_time控制,默认情况下long_query_time的值为10秒, 命令:SHOW VARIABLES LIKE 'long_query_time%';
假如运行时间正好等于long_query_time的情况,并不会被记录下来。也就是说, 在mysql源码里是判断大于long_query_time,而非大于等于。
vim /var/lib/mysql/izbp1ix6yixfm2zbnl72crz-slow.log
SHOW GLOBAL STATUS LIKE '%Slow_queries%';
my.cnf 【mysqld】下配置:
slow_query_log=1 slow_query_log_file=/var/lib/mysql/atguigu-slow.log long_query_time=3 log_output=FILE在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具mysqldumpslow。
能干什么?
查询所有用户正在干什么
如果出现不顺眼的,kill [id]