MySQL第七章之后的

目录

8 聚合函数

8.1聚合函数讲解

8.2聚合函数练习

 9子查询

9.1子查询讲解

10

11增删改查

11.1增删改查讲解

 12数据类型讲解

13约束

13.1约束讲解

13.2约束练习

14视图

14.1视图讲解

14.2视图练习

15存储过程与存储函数

15.1存储过程与存储函数讲解

15.2存储过程与存储函数练习

韩顺平索引

韩顺平索引讲解

韩顺平索引练习

韩顺平存储引擎

韩顺平隔离级别

韩顺平事务

韩顺平用户管理讲解

韩顺平用户讲解

韩顺平用户管理练习

韩顺平作业2,3

韩顺平作业4

韩顺平作业5

韩顺平作业6

韩顺平作业7

韩顺平作业8


8 聚合函数

8.1聚合函数讲解

#第八章 聚合函数

#1 常用的聚合函数 
#1.1 avg /sum
SELECT AVG(salary)  #6461.682243
FROM employees;

SELECT SUM(salary)
FROM employees;

SELECT SUM(salary) / COUNT(employee_id)  #6461.682243
FROM employees;

#1.2 max / min
SELECT MAX(salary),MIN(salary)
FROM employees;

SELECT MAX(last_name),MIN(last_name)  #根据名字第一个字母
FROM employees;

#1.3 count
SELECT COUNT(salary),COUNT(employee_id),COUNT(commission_pct)
FROM employees;

#如果计算表中有多少条记录 
#方式1;count(*)
#方式2;count(1)
#方式3;count(具体字段) 不一定对  不计算null

SELECT AVG(salary),SUM(salary) / COUNT(salary)
FROM employees;

#查询公司中平均奖金率
SELECT SUM(commission_pct) / COUNT(IFNULL(commission_pct,0)),
AVG(IFNULL(commission_pct,0))
FROM employees;

#如果需要统计表中的统计数,哪个效率更高count(*)  count(1)  count(具体字段)
#如果使用的是myisam存储引擎,则三者效率相同,都是O(1)
#如果使用的是innodb存储引擎,则三者效率,count(*) = count(1) > count(字段)


#其他 方差 标准差 中位数

#2 GROUP BY 的使用
SELECT department_id,avg(salary) 
FROM employees
GROUP BY department_id;

SELECT job_id,AVG(salary)
FROM employees
GROUP BY job_id;

#查询各个department——id,jobid的平均工资
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id;
#或
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY job_id,department_id;

SELECT department_id,job_id,AVG(salary) 'newSalary'
FROM employees
GROUP BY department_id WITH rollup
ORDER BY newSalary asc;

#3 HAVING 的使用 用来过滤数据的
#查询各个部门中最高工资比10000高的部门信息
#错误的
SELECT department_id,MAX(salary)
FROM employees
WHERE MAX(salary) > 10000;
GROUP BY department_id;
#正确的
# 要求1: 如果过滤条件中使用了聚和函数,则必须使用having来替换where 否则报错
# 要求2:having必须声明在group by后面
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
having MAX(salary) > 10000;

#要求3:开发中,使用HAVING的前提是使用了GROUP BY 

#查询部门id为10,20,30,40这四个部门中最高工资比10000高的部门信息
#方式1  效率高于方式2
SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40)
GROUP BY department_id
HAVING MAX(salary) > 10000;
#或
#方式2
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING department_id IN (10,20,30,40) and MAX(salary) > 10000

#结论:当过滤条件有聚合函数时,则此过滤函数条件必须声明在having中
# 		 当过滤条件没有聚合函数时,则此过滤函数条件必须声明在having中或声明在where中都可以,但是建议生命在where

/*
WHERE 与 HAVING 的对比
1. 从适用范围上来讲,having的适用范围更广
2. 如果过滤条件中没有聚合函数,这种情况下,where的执行效率要高于having
*/

#4 sql的执行原理
# 4.1 select 语句的完整结构
/*
方式1:(SQL92语法)
  SELECT ...,....,...
        FROM ...,...,....
        WHERE 多表的连接条件
        AND 不包含组函数的过滤条件
        GROUP BY ...,...
        HAVING 包含组函数的过滤条件
        ORDER BY ... ASC/DESC
        LIMIT ...,...
				
				方式2 sql99:
        SELECT ...,....,...
        FROM ... JOIN ...
        ON 多表的连接条件
        JOIN ...
        ON ...
        WHERE 不包含组函数的过滤条件
        AND/OR 不包含组函数的过滤条件
        GROUP BY ...,...
        HAVING 包含组函数的过滤条件
        ORDER BY ... ASC/DESC
        LIMIT ...,...
				
				其中:
        (1)from:从哪些表中筛选
        (2)on:关联多表查询时,去除笛卡尔积
        (3)where:从表中筛选的条件
        (4)group by:分组依据
        (5)having:在统计结果中再次筛选
        (6)order by:排序
        (7)limit:分页
*/

#4.2 sql语句的执行过程
#FROM ...,...->on -> (left/right join) -> where -> group by -> having -> SELECT -> 
#  distint -> order by ->  limit

-- 比如你写了一个 SQL 语句,那么它的关键字顺序和执行顺序是下面这样的:
--         SELECT DISTINCT player_id, player_name, count(*) as num # 顺序 5
--         FROM player JOIN team ON player.team_id = team.team_id # 顺序 1
--         WHERE height > 1.80 # 顺序 2
--         GROUP BY player.team_id # 顺序 3
--         HAVING num > 2 # 顺序 4
--         ORDER BY num DESC # 顺序 6
--         LIMIT 2 # 顺序 7

8.2聚合函数练习

#1.where子句可否使用组函数进行过滤?
-- no!

#2.查询公司员工工资的最大值,最小值,平均值,总和
SELECT MAX(salary),MIN(salary),AVG(salary),SUM(salary)
FROM employees;

#3.查询各job_id的员工工资的最大值,最小值,平均值,总和
SELECT job_id,MAX(salary),MIN(salary),AVG(salary),SUM(salary)
FROM employees
GROUP BY job_id;

#4.选择具有各个job_id的员工人数
SELECT job_id,COUNT(*)
FROM employees
GROUP BY job_id;

# 5.查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT (MAX(salary) -MIN(salary)) 'difference'
FROM employees;


#6.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
-- SELECT e2.manager_id,e2.MIN(salary),e1.department_id
-- FROM employees e1 , employees e2
-- WHERE e1.department_id = e2.manager_id
-- GROUP BY manager_id;
SELECT manager_id,MIN(salary)
FROM employees
WHERE manager_id is not null
GROUP BY manager_id
having min(salary) > 6000;
#答案
SELECT manager_id, MIN(salary)
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN(salary) > 6000;


# 7.查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序
SELECT department_name,l.location_id,COUNT(department_name),AVG(salary)
FROM departments d,locations l,employees e
WHERE d.location_id = l.location_id
AND e.department_id = d.department_id
order by AVG(salary)

SELECT department_name,location_id,COUNT(employee_id),AVG(salary) 'avgsalary'
FROM departments d LEFT JOIN employees e
on e.department_id = d.department_id
GROUP BY department_name,location_id
HAVING avgsalary is not null
ORDER BY avgsalary desc;

#答案
SELECT department_name, location_id, COUNT(employee_id), AVG(salary) avg_sal
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
GROUP BY department_name, location_id
ORDER BY avg_sal DESC;

# 8.查询每个工种、每个部门的部门名、工种名和最低工资
SELECT job_id,department_name,MIN(salary) 'minSalary'
FROM departments d LEFT JOIN employees e
ON d.department_id = e.department_id
GROUP BY job_id,department_name;

 9子查询

9.1子查询讲解

#第九章 子查询  for 里面 套 for
#谁的工资比abel高
#方式一
SELECT
	salary 
FROM
	employees 
WHERE
	last_name = 'Abel';
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	salary > 11000;#方式二 自连接
SELECT
	e2.last_name,
	e2.salary 
FROM
	employees e1,
	employees e2 
WHERE
	e2.salary > e1.salary 
	AND e1.last_name = 'Abel';#方式三 子查询
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	salary > ( SELECT salary FROM employees WHERE last_name = 'Abel' );#2. 称谓规范:外查询(主查询)、内查询(子查询)
/*
子查询(内查询)在主查询之前一次执行完成
子查询的结果被主查询使用
注意事项 
				子查询要包含在括号
				将子查询放在比较条件的右侧
				单行操作符对应单行子查询 多行操作符对应多行子查询
*/
SELECT
	last_name,
	salary 
FROM
	employees 
WHERE
	( SELECT salary FROM employees WHERE last_name = 'Abel' ) < salary; /*
3.子查询的分类
角度一 从内查询返回的结果的条目数
单行子查询vs多行子查询

角度二 内查询是否被执行多次
				相关子查询  vs  不相关子查询
比如 :相关子查询的需求:查询工资大于本部门平均工资的员工信息
			不相关子查询的需求:查询工资大于本公司平均工资的员工信息
*/ #4 单行子查询
#4.1 单行比较操作符  = > >= < <=
#需求1:查询工资大于149号员工工资的员工信息
SELECT last_name, salary, employee_id FROM employees WHERE salary > ( SELECT salary FROM employees WHERE employee_id = 149 );# 子查询的编写技巧  1 从里往外写  2 从外往里写
#需求2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
SELECT
	job_id,
	salary,
	last_name 
FROM
	employees 
WHERE
	job_id = ( SELECT job_id FROM employees WHERE employee_id = 141 ) 
	AND salary > ( SELECT salary FROM employees WHERE employee_id = 143 );#需求3:返回公司工资最少的员工的last_name,job_id和salary
SELECT
	last_name,
	job_id,
	salary 
FROM
	employees 
WHERE
	salary = ( SELECT MIN( salary ) FROM employees );#需求4:查询与141号或174号员工的manager_id和department_id相同的其他员工的
#      employee_id,manager_id,department_id
#方式一
SELECT
	employee_id,
	manager_id,
	department_id 
FROM
	employees 
WHERE
	manager_id = ( SELECT manager_id 
									FROM employees 
									WHERE employee_id = 141 
									) 
	AND department_id = ( SELECT department_id 
												FROM employees 
												WHERE employee_id = 141 
											 );
AND employee_id <> 141;

#方式二了解
SELECT employee_id,manager_id,department_id
FROM employees
WHERE (manager_id,department_id) = (
																		SELECT manager_id,department_id
																		FROM employees
																		WHERE employee_id = 141
																		)
AND employee_id <> 141;

#需求5 查询最低工资大于110号部门最低工资的部门id和其最低工资
SELECT department_id,MIN(salary)
FROM employees
WHERE department_id is NOT NULL
GROUP BY department_id
HAVING MIN(salary) > (
								SELECT MIN(salary)
								FROM employees
								WHERE department_id = 110
								);
# 显式员工的employee_id,last_name和location。其中,若员工
# department_id与location_id为1800的department_id相同,则location
# 为’Canada’,其余则为’USA’。

SELECT employee_id,last_name,case department_id 
																	when (SELECT department_id
																				FROM departments
																				WHERE location_id = 1800) THEN 'Canda'
																	ELSE 'USA' end 'location'
FROM employees;

# 4.2 子查询中的空值问题
# 内查询空值不会报错,但没有结果

#4.3 非法使用子查询


#5多行子查询
#操作符 in any all some
SELECT employee_id,last_name
FROM employees
WHERE salary in
							(SELECT MIN(salary)
							FROM employees
							GROUP BY department_id
							);
#需求1:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、姓名、job_id 以及salary
SELECT department_id,last_name,job_id,salary
FROM employees
WHERE job_id <> 'IT_PROG'
AND salary < ANY (
									SELECT salary
									FROM employees
									WHERE job_id = 'IT_PROG'
									);
#需求2:返回其它job_id中比job_id为‘IT_PROG’部门全部工资低的员工的员工号、姓名、job_id 以及salary
SELECT department_id,last_name,job_id,salary
FROM employees
WHERE job_id <> 'IT_PROG'
AND salary < ALL (
									SELECT salary
									FROM employees
									WHERE job_id = 'IT_PROG'
									);
									
# 需求3:查询平均工资最低的部门id
#方式一
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL (
													SELECT AVG(salary)
													FROM employees
													GROUP BY department_id
													);
#方式二
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
											SELECT MIN(avg_sal)
											FROM (
														SELECT AVG(salary) 'avg_sal'
														FROM employees
														GROUP BY department_id
														)
											);


#5.3 空值问题
# 原因:内查询中存在NULL


# 6 相关子查询
#关联子查询:       如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为 关联子查询 。

#6.1
#需求1:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
#方式一 使用相关子查询
SELECT last_name,salary,department_id
FROM employees e
WHERE salary > (
								 SELECT AVG(salary)
							   FROM employees e2
								 WHERE e2.department_id = e.department_id
								 );
#方式二 c从from中

SELECT e.last_name,e.salary,e.department_id
FROM employees e,(
									SELECT department_id,AVG(salary) avg_sal
									FROM employees
									GROUP BY department_id
									) tmp_avg_sal							
WHERE e.salary > tmp_avg_sal.avg_sal
AND e.department_id = tmp_avg_sal.department_id;

#需求2:查询员工的id,salary,按照department_name 排序

SELECT employee_id,salary
FROM employees e
ORDER BY (
				  SELECT department_name
					FROM departments d
					WHERE e.department_id = d.department_id
					) asc;


#需求3:若employees表中employee_id与job_history表中employee_id相同的数目不小于2,
#输出这些相同id的员工的employee_id,last_name和其job_id		
SELECT *
FROM job_history;

SELECT employee_id,last_name,job_id
FROM employees e
WHERE 2 <= (
						SELECT COUNT(*)  #数目
						FROM job_history j
						WHERE j.employee_id = e.employee_id
						);

#6.2 EXISTS 与 NOT EXISTS关键字
#需求:查询公司管理者的employee_id,last_name,job_id,department_id信息
#方式一
SELECT DISTINCT mgr.employee_id,mgr.last_name,mgr.job_id,mgr.department_id
FROM employees emp JOIN employees mgr
on emp.manager_id = mgr.employee_id;

#方式二
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE employee_id in (
											SELECT DISTINCT manager_id
											FROM employees
											);

#方式三
SELECT employee_id,last_name,job_id,department_id
FROM employees e1
WHERE EXISTS(
							SELECT *
							FROM employees e2
							WHERE e1.employee_id = e2.manager_id
							);

#需求:查询departments表中,不存在于employees表中的部门的department_id和department_name
SELECT department_id,department_name
FROM departments d
WHERE NOT EXISTS(
								SELECT * 
								FROM employees e
								WHERE d.department_id = e.department_id
								);

10

11增删改查

11.1增删改查讲解

# 1. 添加数据

CREATE table if NOT EXISTS empl(
id int,
last_name VARCHAR(15),
hire_date DATE,
salary DOUBLE(10,2)
);

desc empl;
#fun 1 一条一条加数据

SELECT * FROM empl;

ALTER TABLE empl
MODIFY hire_date DATE;

# 1.1 
INSERT INTO empl 
VALUES (1,'tom','2000-08-26',12000);  #按照声明字段的先后顺序添加

#1.2
INSERT INTO empl(id,last_name,salary)
VALUES (2,'marry',20000);

#1.3
INSERT INTO empl(id,last_name,salary)
VALUEs
(4,'俊杰',5000),
(5,'俊爱',6000);



#fun 2 将查询结果插入表中
SELECT * FROM empl;

INSERT into empl(id,last_name,salary,hire_date)
SELECT employee_id,last_name,salary,hire_date
FROM employees
WHERE department_id in (50,60);



#更新数据
#UPDATE table_reference SET col_name1=expr1 WHERE where_condition
UPDATE empl
SET hire_date = CURDATE()
WHERE id = 1;


SELECT * FROM empl;

UPDATE empl
SET hire_date = CURRENT_DATE(),salary = 999
WHERE id = 2;

#题目:将表中姓名中把包含字符a的提薪20%
UPDATE empl
SET salary = salary *1.2
WHERE last_name LIKE '%a%';

# 3删除数据
DELETE FROM empl
WHERE id = 1;

#mysql8的新特性
CREATE TABLE test1(
a int,
b int,
c int generated always as (a + b) virtual
);

SELECT * FROM test1;

INSERT INTO test1(a,b)
VALUEs(14,2);

UPDATE test1
SET a = 100
WHERE a = 1;

#5.综合案例

11.2增删改查练习

#1. 创建数据库dbtest11
create DATABASE dbtest11 CHARACTER SET 'utf8';

#2. 运行以下脚本创建表my_employees
USE dbtest11;
CREATE TABLE my_employees(
id INT(10),
first_name VARCHAR(10),
last_name VARCHAR(10),
userid VARCHAR(10),
salary DOUBLE(10,2)
);
CREATE TABLE users(
id INT,
userid VARCHAR(10),
department_id INT
);
show TABLES;

#3. 显示表my_employees的结构
desc my_employees;

#4. 向my_employees表中插入下列数据
ID FIRST_NAME LAST_NAME USERID SALARY
1 patel Ralph Rpatel 895
2 Dancs Betty Bdancs 860
3 Biri Ben Bbiri 1100
4 Newman Chad Cnewman 750
5 Ropeburn Audrey Aropebur 1550
INSERT INTO my_employees
VALUES 
(1 ,'patel' ,'Ralph' ,'Rpatel', 895),
(2 ,'Dancs' ,'Betty' ,'Bdancs' ,860),
(3 ,'Biri' ,'Ben' ,'Bbiri' ,1100),
(4 ,'Newman' ,'Chad', 'Cnewman', 750),
(5 ,'Ropeburn', 'Audrey' ,'Aropebur', 1550);


SELECT * FROM my_employees;
#5. 向users表中插入数据
1 Rpatel 10
2 Bdancs 10
3 Bbiri 20
4 Cnewman 30
5 Aropebur 40
INSERT INTO users
VALUES
(1 ,'Rpatel', 10),
(2 ,'Bdancs', 10),
(3, 'Bbiri', 20),
(4 ,'Cnewman' ,30),
(5 ,'Aropebur' ,40);
SELECT * FROM users;
#6. 将3号员工的last_name修改为“drelxer”
UPDATE my_employees
SET last_name='drelxer'
WHERE id = 3;

#7. 将所有工资少于900的员工的工资修改为1000
UPDATE my_employees
set salary = 1000
WHERE salary < 900;

#8. 将userid为Bbiri的user表和my_employees表的记录全部删除
DELETE u,m
FROM users u
JOIN my_employees m
on u.userid = m.userid
AND u.userid = 'Bbiri';


SELECT * FROM my_employees;
SELECT * FROM users;
#9. 删除my_employees、users表所有数据
DELETE 
FROM users;

DELETE 
FROM my_employees;

#10. 检查所作的修正
TRUNCATE TABLE my_employees;

#练习2
# 1. 使用现有数据库dbtest11
use dbtest11;

# 2. 创建表格pet
CREATE TABLE pet (
`name` VARCHAR(20),
`owner` VARCHAR(20),
species VARCHAR(20),
sex char(1),
birth YEAR,
death YEAR
);

# 3. 添加记录
INSERT INTO pet
VALUES
('bowser','diane','Dog','m','2003','2009'),
('Fluffy','harold','Cat','f','2013','2010');


INSERT INTO pet
(`name`,`owner`,species,sex,birth)
VALUES('Claws','gwen','Cat','m','2014');

INSERT INTO pet
(`name`,species,sex,birth)
VALUEs ('Chirpy','bird','f','2008'),
VALUEs ('Buffy','Dog','f','2009');


INSERT INTO pet
(`name`,`owner`,species,sex,birth)
VALUES('Fang','benny','Dog','m','2000');

SELECT * FROM pet;
# 4. 添加字段:主人的生日owner_birth DATE类型。
ALTER TABLE pet
ADD owner_birth DATE;

# 5. 将名称为Claws的猫的主人改为kevin
#错误答案 my
-- ALTER TABLE pet
-- MODIFY `owner`= 'kevin'
-- WHERE `name` = 'Claws';

#答案
UPDATE  pet
SET `owner`= 'kevin'
WHERE `name` = 'Claws';

# 6. 将没有死的狗的主人改为duck
UPDATE pet
SET `owner` = 'duck'
WHERE death is NULL
AND species = 'Dog';

SELECT * FROM pet;


# 7. 查询没有主人的宠物的名字;
SELECT `name`
FROM pet
WHERE `owner` is NULL;

# 8. 查询已经死了的cat的姓名,主人,以及去世时间;
SELECT `name`,`owner`,death
FROM pet
WHERE death IS NOT NULL;

# 9. 删除已经死亡的狗
DELETE 
FROM pet
WHERE death is not null;



# 10. 查询所有宠物信息
SELECT * FROM pet;

#练习三
# 1. 使用已有的数据库dbtest11
use dbtest11;

# 2. 创建表employee,并添加记录
CREATE table employee
(id int,
`name` VARCHAR(25),
sex CHAR(1),
tel VARCHAR(20),
addr VARCHAR(20),
salary DOUBLE(20,2)
);

INSERT INTO employee(id,`name`,sex,tel,addr,salary)VALUES
(10001,'张一一','男','13456789000','山东青岛',1001.58),
(10002,'刘小红','女','13454319000','河北保定',1201.21),
(10003,'李四','男','0751-1234567','广东佛山',1004.11),
(10004,'刘小强','男','0755-5555555','广东深圳',1501.23),
(10005,'王艳','男','020-1232133','广东广州',1405.16);

# 3. 查询出薪资在1200~1300之间的员工信息。
SELECT *
FROM employee
WHERE salary BETWEEN 1200 and 1300;

# 4. 查询出姓“刘”的员工的工号,姓名,家庭住址。
SELECT id,`name`,addr
FROM employee
WHERE `name` LIKE '刘%';

# 5. 将“李四”的家庭住址改为“广东韶关”
UPDATE employee
SET addr='广东韶关'
WHERE `name` = '李四';

# 6. 查询出名字中带“小”的员工
SELECT *
FROM employee
WHERE `name` like '%小%';

 12数据类型讲解

13约束

13.1约束讲解

#1.基础知识
#1.1 为什么需要约束 -- 为了保证数据的完整性

-- 角度一
-- 约束的字段的个数
-- 单列约束 vs 多列约束

#角度二 约束的作用范围

#列级约束:对应字段之后
#表级约束:所有字段之后


#角度三 约束的作用

#① not null(非空约束)
#② unique(唯一约束)
#③ primary key(主键约束)
#④ foreign key(外键约束)
#⑤ check (检查约束)
#⑥ default (默认值约束)


#1.4 如何添加约束

create table +

ALTER TABLE +  -


# 2 如何查看表中的约束

SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name = 'employees';

# 3.not null(非空约束)
# 3.1 在create table添加约束
CREATE TABLE test2(
id int NOT NULL,
last_name VARCHAR(25) NOT null,
email VARCHAR(25));

DESC test2;

INSERT INTO test2
VALUES(1,'tom','dsadsad');

INSERT INTO test2
VALUES(1,NULL,'dsadsad');

#3.2 在alter table时添加约束
SELECT * FROM test2;

desc test2;

ALTER TABLE test2
MODIFY email VARCHAR(25) NOT null;

#3.3 alter table 时删除约束
alter TABLE test2
modify email VARCHAR(25) null;

#4.1 在create table添加约束
CREATE TABLE test4(
id int ,#unique,  列级约束
last_name VARCHAR(25) NOT NULL,
email VARCHAR(25),
#表级约束
#CONSTRAINT uk_test3_email UNIQUE(email)
UNIQUE(email)
);

DESC test4
SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name = 'test4';

#在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同

insert into test4
VALUES (1,'tom','2451477159.com'),

insert into test4
VALUES (1,'tom','2451477159.com'); 
#Duplicate entry '2451477159.com' for key 'test4.email'

#可以多次添加null值


#4.2 在alter table时添加约束
alter table test4
add unique(id);


alter table test4
modify last_name VARCHAR(25) unique;

desc test4;

#4.3 复合的唯一性约束
CREATE table users2(
id int,
`name` VARCHAR(25),
`password` VARCHAR(25),

#表级约束
UNIQUE(`name`,`password`)
);

desc users;



#4.4 alter table 时删除约束
-- 1.添加唯一性约束的列上也会自动创建唯一索引。
-- 2.删除唯一约束只能通过删除唯一索引的方式删除。
-- 3.删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
-- 4.如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;
--            如果是组合列,那么默认和() 中排在第一个的列名相同。
--            也可以是自定义唯一性约束名。

SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name = 'test4';

desc test4;

#删除唯一索引
alter table test4
drop index last_name; #或者命名的


#5 PRIMARY key
#主键约束特征 非空且唯一
#5.1 在create table时添加约束
create table test5(
id int PRIMARY key,  #列级约束
last_name VARCHAR(25),
salary DOUBLE(10,2),
email VARCHAR(25)
);

create table test6(
id int,  
last_name VARCHAR(25),
salary DOUBLE(10,2),
email VARCHAR(25),
#表级约束
CONSTRAINT pry_test5_id PRIMARY key(id)
);

desc test5;
desc test6;

SELECT * FROM information_schema.table_constraints
WHERE table_name = 'test5';

#联合主键
create TABLE user1
(
id int,
NAME VARCHAR(25),
PASSWORD VARCHAR(25),

PRIMARY KEY(NAME,PASSWORD)
);

INSERT INTO user1
VALUES(1,'tom','abc');

INSERT INTO user1
VALUES(1,'tom1','abc');

select * from user1;


#5.2 在alter table时添加约束
create TABLE user2
(
id int,
NAME VARCHAR(25),
PASSWORD VARCHAR(25)
);


ALTER TABLE user2
ADD PRIMARY KEY(id);

#5.3 如何删除主键约束 实际开发一般不会做
ALTER TABLE user2
DROP PRIMARY key;

#6 自增长auto_increment
create TABLE user3
(
id int PRIMARY KEY auto_increment,
NAME VARCHAR(25),
PASSWORD VARCHAR(25)
);
#开发中 一旦主键作用的字段上声明有auto——increment 在T添加数据时,
#就不要给主键对应的字段去赋值了
INSERT into user3
VALUES (1,'tom','21321')

INSERT into user3(NAME,PASSWORD)
VALUES ('tom1','2132123');

INSERT into user3(id,NAME)
VALUES (0,'MARY');

INSERT into user3(id,NAME)
VALUES (8,'MARY');

INSERT into user3(id,NAME)
VALUES (10,'MARY');

SELECT * FROM user3;

# 6.2 alter中添加
create TABLE user5
(
id int PRIMARY KEY,
NAME VARCHAR(25),
PASSWORD VARCHAR(25)
);

ALTER table user5
MODIFY id int auto_increment;

#6.3 删除
ALTER TABLE user5
MODIFY id int;

#6.4 MySQL8.0新特性
# 从结果可以看出,自增变量已经持久化了。
# MySQL 8.0将自增主键的计数器持久化到 重做日志 中。
# 每次计数器发生改变,都会将其写入重做日志中。
# 如果数据库重启,InnoDB 会根据重做日志中的信息来初始化计数器的内存值。


# 7 foreing key
# 经典白听 不常用 阿里不让用

# 8 check约束
CREATE TABLE test7(
id INT,
last_name VARCHAR(25),
salary DOUBLE(10,2) CHECK(salary > 2000)
);

INSERT into test7
VALUES(1,'tom',20000);

#Check constraint 'test7_chk_1' is violated.
#添加失败
INSERT into test7
VALUES(2,'tom',1000);

# 9 default约束
#9.1 create 添加
-- CREATE TABLE test8(
-- id int PRIMARY KEY auto_increment,
-- `name` VARCHAR(25) NOT NULL,
-- salary DOUBLE(10,2) DEFAULT 2000,
-- );
CREATE TABLE test8(
id INT PRIMARY KEY auto_increment,
last_name VARCHAR(25) NOT NULL,
salary DOUBLE(10,2) DEFAULT 2000
);
# 9.2 alter 添加
ALTER TABLE test8
MODIFY salary DOUBLE(10,2) DEFAULT 2000;

#9.3 在alter table删除约束
alter TABLE test8
modify salary DOUBLE(10,2);

SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name= 'test8';

#10 面试
#面试 1 、为什么建表时,加 not null default '' 或 default 0
#        答:不想让表中出现null 值。
#面试 2 、为什么不想要 null 的值
#        答: (1)不好比较。 null 是一种特殊值,
#               比较时只能用专门的is null 和is not null 来比较。碰到运算符,通常返回null 。
#            (2)效率不高。影响提高索引效果。
#                因此,我们往往在建表时 not null default '' 或 default 0

#面试 3 、带 AUTO_INCREMENT 约束的字段值是从 1 开始的吗?
#        在MySQL 中,默认AUTO_INCREMENT的初始 值是1,每新增一条记录,字段值自动加1 。设置自增属性(AUTO_INCREMENT)的时候,还可以指定第 一条插入记录的自增字段的值,这样新插入的记录的自增字段值从初始值开始递增,如在表中插入第一 条记录,同时指定id 值为 5 ,则以后插入的记录的 id 值就会从 6 开始往上增加。添加主键约束时,往往需要 设置字段自动增加属性。

#面试 4 、并不是每个表都可以任意选择存储引擎? 外键约束(FOREIGN KEY)不能跨引擎使用。(主表和从表用的引擎要相同)
#MySQL支持多种存储引擎,每一个表都可以指定一个不同的存储引擎,需要注意的是:
#外键约束是用来保证数据的参照完整性的,如果表之间需要关联外键,却指定了不同的存储引擎,
#那么这些表之间是不能创建外键约束的。所以说,存储引擎的选择也不完全是随意的。

13.2约束练习

CREATE DATABASE test04_emp;

use test04_emp;

CREATE TABLE emp2(
id INT,
emp_name VARCHAR(15)
);

CREATE TABLE dept2(
id INT,
dept_name VARCHAR(15)
);

#1.向表emp2的id列中添加PRIMARY KEY约束
ALTER TABLE emp2
MODIFY id INT PRIMARY KEY;

desc emp2;

#2. 向表dept2的id列中添加PRIMARY KEY约束
ALTER TABLE dept2
MODIFY id INT PRIMARY KEY;

desc dept2;


#3. 向表emp2中添加列dept_id,并在其中定义FOREIGN KEY约束,与之相关联的列是dept2表中的id列。
ALTER TABLE emp2
ADD COLUMN dept_id INT;

ALTER TABLE emp2 ADD CONSTRAINT fk_emp2_deptid FOREIGN KEY(dept_id) REFERENCES
dept2(id);


#练习2
# 1、创建数据库test01_library
CREATE DATABASE test01_library;

# 2、创建表 books,表结构如下:
CREATE TABLE books(
id INT,
`name` VARCHAR(50),
`authors` VARCHAR(100),
price FLOAT,
pubdate YEAR,
note VARCHAR(100),
num INT
);

# 3、使用ALTER语句给books按如下要求增加相应的约束
ALTER TABLE books
MODIFY id INT(11) PRIMARY KEY auto_increment;

ALTER TABLE books
MODIFY id INT(11) NOT NULL;

ALTER TABLE books
MODIFY id INT(11) UNIQUE;

ALTER TABLE books
MODIFY `name` VARCHAR(100) NOT null;

ALTER TABLE books
MODIFY `authors` VARCHAR(100) NOT null;

ALTER TABLE books
MODIFY price FLOAT NOT null;

ALTER TABLE books
MODIFY pubdate YEAR NOT null;

ALTER TABLE books
MODIFY num INT(11) NOT null;

desc books;


#练习3
#1. 创建数据库test04_company

#2. 按照下表给出的表结构在test04_company数据库中创建两个数据表offices和employees


14视图

14.1视图讲解

#第十四章 视图view
#存储起来的select语句


/*
	1.视图的理解/*
  
	1.1视图,可以看作是一个虚拟表,本身是不存在存储数据的
		 视图的本质,就可以看作是存储起来的SELECT语句
		 
  1.2视图中SELECT语句涉及到的表,称为基表

  1.3针对视图做DML(增删改)操作,会影响到对应基表中的数据。反之亦然。

  1.4视图的应用场景:针对小型项目,不推荐使用视图。
									  针对大型项目,可以考虑使用视图。
	1.5视图的优点:简化查询;控制数据的访问。
*/
CREATE DATABASE dbtest14;

USE dbtest14;

CREATE TABLE emps
AS 
SELECT * 
FROM atguigudb.employees;

CREATE TABLE depts
AS 
SELECT *
FROM atguigudb.departments;

SELECT * FROM emps;

SELECT * FROM depts;


#2.1 针对单表
CREATE VIEW vu_empl
AS 
SELECT employee_id,last_name,salary
FROM emps;

SELECT * FROM vu_empl;

#情况一 视图中的字段在基表中有对应的字段
#确定视图中字段名的方式一
CREATE VIEW vu_emp2
AS 
SELECT employee_id emp_id,last_name `name`,salary
FROM emps
WHERE salary > 8000;

SELECT * FROM vu_emp2;

#确定视图中的字段名的方式二
CREATE VIEW vu_emp3(emp_id,`name`,salary)
AS 
SELECT employee_id,last_name,salary
FROM emps
WHERE salary > 8000;

SELECT * FROM vu_emp3;

#情况一 视图中的字段在基表中没有对应的字段
#比如AVG(salary)

#2.2 针对多表
CREATE VIEW vu_ed
AS
SELECT e.employee_id emp,e.last_name `name`,d.department_id dept,d.department_name dname
FROM atguigudb.employees e 
JOIN atguigudb.departments d
ON e.department_id = d.department_id;

SELECT * FROM vu_ed;

CREATE VIEW vu_ed1
AS
SELECT CONCAT(e.last_name,'(',d.department_name,')') emp_info
FROM atguigudb.employees e 
JOIN atguigudb.departments d
ON e.department_id = d.department_id;

SELECT * FROM vu_ed1;

#2.3基于视图创建视图
CREATE VIEW vu_test
AS 
SELECT * 
FROM vu_ed1;

SELECT * FROM vu_test;

#3 查看视图
#3.1 查看数据库的表对象 视图对象
show tables;

#3.2 查看视图的结构
DESCRIBE vu_test;

#3.3 查看视图的属性信息
show table STATUS LIKE 'vu_test';

#3.4 查看视图的详细定义信息
show CREATE VIEW vu_test;


# 4 更新视图中的数据
# 4.1 一般情况下
#更新视图的数据 会导致基表的数据修改

#同理 更新基表中的数据,也会导致视图中的数据的修改

#删除视图中的数据 也会导致表中的数据的删除

# 4.2 不能更新视图中的数据
# 不存在的列名 avg(salary)
CREATE VIEW vu_emp_sal
AS 
SELECT employee_id,last_name,salary,avg(salary) avg_sal
FROM atguigudb.employees
GROUP BY department_id;


DROP VIEW vu_emp_sal

UPDATE vu_emp_sal
SET avg_sal = 5000
WHERE department_id = 30;
#更新失败
#The target table vu_emp_sal of the UPDATE is not updatable

DELETE FROM vu_emp_sal 
WHERE department_id = 30; 
#The target table vu_emp_sal of the DELETE is not updatable


#5 修改视图
desc vu_emp1;

#方式一
CREATE OR REPLACE VIEW vu_emp1
AS 
SELECT employee_id,last_name,salary
FROM emps
WHERE salary > 8000;

ALTER VIEW vu_emp1
AS 
SELECT employee_id,last_name,salary,hire_date
FROM emps
WHERE salary > 8000;

# 6 删除视图
drop view vu_emp2;

drop view vu_ed1;
#因为a,b视图而存在的视图c,a,b视图删除时,c视图需要修改或者删除

# 7.视图优点
# 7.1. 操作简单
#将经常使用的查询操作定义为视图,可以使开发人员不需要关心视图对应的数据表的结构、表与表之间的关联关系,也不需要关心数据表之间的业务逻辑和查询条件,而只需要简单地操作视图即可,极大简化了开发人员对数据库的操作。

# 7.2. 减少数据冗余
#视图跟实际数据表不一样,它存储的是查询语句。所以,在使用的时候,我们要通过定义视图的查询语句来获取结果集。而视图本身不存储数据,不占用数据存储的资源,减少了数据冗余。

# 7.3. 数据安全
#MySQL将用户对数据的 访问限制 在某些数据的结果集上,而这些数据的结果集可以使用视图来实现。用户不必直接查询或操作数据表。这也可以理解为视图具有 隔离性 。视图相当于在用户和实际的数据表之间加了一层虚拟表。
#        同时,MySQL 可以根据权限将用户对数据的访问限制在某些视图上, 用户不需要查询数据表,可以直接 通过视图获取数据表中的信息 。这在一定程度上保障了数据表中数据的安全性。

# 7.4. 适应灵活多变的需求
#当业务系统的需求发生变化后,如果需要改动数据表的结构,则工作量相对较
#大,可以使用视图来减少改动的工作量。这种方式在实际工作中使用得比较多。

# 7.5. 能够分解复杂的查询逻辑
#数据库中如果存在复杂的查询逻辑,则可以将问题进行分解,创建多个视图获取数据,再将创建的多个视图结合起来,完成复杂的查询逻辑。

# 8 视图的不足(维护成本高 小项目不用 大项目看情况)
#如果我们在实际数据表的基础上创建了视图,那么, 如果实际数据表的结构变更了,我们就需要及时对 相关的视图进行相应的维护 。特别是嵌套的视图(就是在视图的基础上创建视图),维护会变得比较复杂, 可读性不好 ,容易变成系统的潜在隐患。因为创建视图的 SQL 查询可能会对字段重命名,也可能包含复杂的逻辑,这些都会增加维护的成本。
#实际项目中,如果视图过多,会导致数据库维护成本的问题。
#        所以,在创建视图的时候,你要结合实际项目需求,综合考虑视图的优点和不足,这样才能正确使用视图,使系统整体达到最优。

14.2视图练习

USE dbtest14
#1.使用表employees创建视图employee_vu,其中包括姓名(LAST_NAME),员工号(EMPLOYEE_ID),部门号(DEPARTMENT_ID)
CREATE VIEW employee_vu
AS
SELECT last_name,employee_id,department_id
FROM atguigudb.employees;

#2. 显示视图的结构
desc employee_vu;

#3. 查询视图中的全部内容
SELECT *
FROM employee_vu;

#4. 将视图中的数据限定在部门号是80的范围内
ALTER VIEW employee_vu
AS 
SELECT last_name,employee_id,department_id
FROM atguigudb.employees
WHERE department_id = 80;

15存储过程与存储函数

15.1存储过程与存储函数讲解

CREATE DATABASE dbtest15;

use dbtest15;

CREATE TABLE employees
AS
SELECT * FROM atguigudb.employees;

CREATE TABLE departments
AS
SELECT * FROM atguigudb.departments;

SELECT * FROM employees;

SELECT * FROM departments;


#1 创建存储过程

#类型一 无参无返回值
#举例1 创建存储过程select_all_dta(),查看employees表的所有数据
delimiter $

CREATE PROCEDURE select_all_data()
BEGIN
			select * FROM employees;
END $

delimiter ;


#2 存储过程的调用
CALL select_all_data();


#举例2:创建存储过程avg_employee_salary(),返回emps中所有员工的平均工资

delimiter $

CREATE PROCEDURE avg_employee_salary()
BEGIN 
	SELECT AVG(salary) FROM employees;
END $

delimiter;

CALL avg_employee_salary;

#举例3:创建存储过程show_max_salary(),用来查看“emps”表的最高薪资值。
delimiter $
CREATE PROCEDURE show_max_salary()
BEGIN
	SELECT max(salary) max_sal
	FROM employees;
END $
delimiter ;

CALL show_max_salary();


#类型二 带out

#举例4:创建存储过程show_min_salary(),查看“emps”表的最低薪资值。并将最低薪资通过OUT参数“ms” 输出:
desc employees;
delimiter $

CREATE PROCEDURE show_min_salary(OUT ms DOUBLE(10,2))
BEGIN 
	SELECT MIN(salary) INTO ms
	FROM employees;
END $
delimiter ;

CALL show_min_salary(@ms);

#查看变量值
SELECT @ms;

#举例5:创建存储过程show_someone_salary(),查看“emps”表的某个员工的薪资,并用IN参数empname输入员工姓名。
delimiter $
CREATE PROCEDURE show_someone_salary1(IN empname VARCHAR(20))
BEGIN 
	SELECT salary,last_name
	FROM employees
	WHERE last_name = empname;
END $
delimiter;

SELECT * FROM employees;

#调用方式一
CALL show_someone_salary1('King');
#调用方式二
SET @empname := 'King';
CALL show_someone_salary1(@empname);

#举例6:创建存储过程show_someone_salary2(),查看“emps”表的某个员工的薪资,
# 并用IN参数empname输入员工姓名,用OUT参数empsalary输出员工薪资。

delimiter $
CREATE PROCEDURE show_someone_salary2(IN empname VARCHAR(20),OUT empsalary DOUBLE(10,2))
BEGIN 
	SELECT salary INTO empsalary
	FROM employees
	WHERE last_name = empname;
END $
delimiter;

SET @empname := 'Abel';
CALL show_someone_salary2(@empname,@empsalary);
SELECT @empsalary;

#举例7:创建存储过程show_mgr_name(),查询某个员工领导的姓名,
# 并用INOUT参数“empname”输入员工姓名,输出领导的姓名。

delimiter $

CREATE PROCEDURE show_mgr_name3(INOUT empname VARCHAR(25))
BEGIN 
	SELECT last_name
	FROM employees
	WHERE employee_id = (
											SELECT manager_id
											FROM employees
											WHERE last_name = empname
											);
END $

delimiter ;

set @empname := 'Abel';
CALL show_mgr_name3(@empname);

#2 存储函数

#举例1: 创建存储函数,名称为email_by_name(),参数定义为空,
# 该函数查询Abel的email,并返回,数据类型为字符串型。

DELIMITER $
CREATE FUNCTION email_by_name()
RETURNS VARCHAR(25)
	DETERMINISTIC 
	READS SQL DATA

BEGIN
	RETURN (SELECT email FROM employees WHERE last_name = 'Abel');
END $

DELIMITER ;

SELECT email_by_name();

#举例2: 创建存储函数,名称为email_by_id(),参数传入emp_id,该函数查询emp_id的email,
#并返回,数据类型为字符串型。


# 在创建函数前声明
#保证会成功
SET GLOBAL log_bin_trust_function_creators = 1;

delimiter $
CREATE FUNCTION email_by_id(emp_id INT)
RETURNS VARCHAR(25)

BEGIN
	RETURN(SELECT email FROM employees WHERE employee_id = emp_id);
END $
delimiter ;

SELECT email_by_id(100);

#举例3: 创建存储函数count_by_id(),参数传入dept_id,该函数查询dept_id部门的员工人数,
#并返回,数据类型为整型。

SET GLOBAL log_bin_trust_function_creators = 1;

delimiter $
CREATE FUNCTION count_by_id(dept_id INT)
RETURNS INT

BEGIN
	RETURN(SELECT count(*) FROM employees WHERE department_id = dept_id);
END $  

delimiter ;

SELECT count_by_id(100);

#3 存储过程 函数的查看
#3.1. 使用SHOW CREATE语句查看存储过程和函数的创建信息
SHOW CREATE PROCEDURE avg_employee_salary;

SHOW CREATE FUNCTION count_by_id;

#3.2. 使用SHOW STATUS语句查看存储过程和函数的状态信息
SHOW PROCEDURE STATUS LIKE 'avg_employee_salary';

SHOW FUNCTION STATUS LIKE 'count_by_id';

#3.3 从information_schema.Routines表中查看存储过程和函数的信息
SELECT * FROM information_schema.ROUTINES
WHERE routine_name = 'avg_employee_salary';

SELECT * FROM information_schema.ROUTINES
WHERE routine_name = 'count_by_id' AND routine_type = 'FUNCTION';


#4 修改
ALTER FUNCTION count_by_id 
SQL SECURITY INVOKER
COMMENT '部门人口数量';

#5 删除
DROP FUNCTION if EXISTS email_by_id;

#6 优缺点

#6.1 优点
--   1、存储过程可以一次编译多次使用。 
-- 	 2、可以减少开发工作量
-- 	 3、存储过程的安全性强。  我们在设定存储过程的时候可以 设置对用户的使用权限 ,
-- 	 4、可以减少网络传输量。
-- 	 5、良好的封装性。

#6.2 缺点
-- 1、可移植性差。
-- 2、调试困难。
-- 3、存储过程的版本管理很困难。  
-- 4、它不适合高并发的场景。

15.2存储过程与存储函数练习

CREATE DATABASE test15_pro_func;

USE test15_pro_func;

#存储过程练习

#1. 创建存储过程insert_user(),实现传入用户名和密码,插入到admin表中
CREATE TABLE admin(
id INT PRIMARY KEY auto_increment,
`name` VARCHAR(25) NOT NULL,
`password` VARCHAR(25) NOT null
);

delimiter $
CREATE PROCEDURE insert_user(IN username VARCHAR(25),IN userpassword VARCHAR(25))
BEGIN
	INSERT INTO admin(`name`,`password`)
	VALUE (username,userpassword);
END$

delimiter ;

CALL insert_user('tom','123qweasdzxc');

SELECT * FROM admin;

#2. 创建存储过程get_phone(),实现传入女神编号,返回女神姓名和女神电话
#准备工作
CREATE TABLE beauty(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(15) NOT NULL,
phone VARCHAR(15) UNIQUE,
birth DATE
);
INSERT INTO beauty(NAME,phone,birth)
VALUES
('朱茵','13201233453','1982-02-12'),
('孙燕姿','13501233653','1980-12-09'),
('田馥甄','13651238755','1983-08-21'),
('邓紫棋','17843283452','1991-11-12'),
('刘若英','18635575464','1989-05-18'),
('杨超越','13761238755','1994-05-11');
SELECT * FROM beauty;


delimiter $
CREATE PROCEDURE get_phone(IN bea_id INT,OUT bea_NAME VARCHAR(15),OUT bea_phone VARCHAR(15))
BEGIN
	SELECT NAME,phone INTO bea_NAME,bea_phone
	FROM beauty 
	WHERE id = bea_id;
END$
delimiter ;

CALL get_phone(2,@bea_NAME,@bea_phone);
SELECT @bea_NAME;
SELECT @bea_phone

#3. 创建存储过程date_diff(),实现传入两个女神生日,返回日期间隔大小
delimiter $
CREATE PROCEDURE date_diff1(IN bea_birth_a DATETIME,IN bea_birth_b DATETIME,OUT inter INT)
BEGIN 
	SELECT DATEDIFF(bea_birth_a,bea_birth_b) INTO inter;
END$
delimiter ;

CALL date_diff1('1982-02-12','1991-11-12',@inter);
SELECT @inter;

#4. 创建存储过程format_date(),实现传入一个日期,格式化成xx年xx月xx日并返回
DELIMITER //
CREATE PROCEDURE format_date(IN mydate DATETIME,OUT strdate VARCHAR(50))
BEGIN
SELECT DATE_FORMAT(mydate,'%y年%m月%d日') INTO strDate;
END //
DELIMITER ;

CALL format_date('1982-02-12',@strdate);
SELECT @strdate;

#5. 创建存储过程beauty_limit(),根据传入的起始索引和条目数,查询女神表的记录
#创建带inout模式参数的存储过程
DELIMITER //
CREATE PROCEDURE beauty_limit(IN startIndex INT,IN size INT)
BEGIN
SELECT * FROM beauty LIMIT startIndex,size;
END //
DELIMITER ;

CALL beauty_limit(1,3);

#6. 传入a和b两个值,最终a和b都翻倍并返回
delimiter $
CREATE PROCEDURE add_values(INOUT a INT,INOUT b INT)
BEGIN 
	SELECT a * 2 as `a`,b * 2 as `b`
	FROM DUAL;
END $
delimiter ;

SET @a = 3,@b = 4;
CALL add_values(@a,@b);
SELECT @a,@b;

#7. 删除题目5的存储过程
DROP PROCEDURE beauty_limit;

#8. 查看题目6中存储过程的信息
SELECT * FROM information_schema.ROUTINES
WHERE routine_name = 'add_values';

SHOW PROCEDURE STATUS like 'add_values';


#存储函数练习
#0. 准备工作
USE test15_pro_func;

CREATE TABLE employees
AS
SELECT * FROM atguigudb.`employees`;

CREATE TABLE departments
AS
SELECT * FROM atguigudb.`departments`;

#无参有返回
#1. 创建函数get_count(),返回公司的员工个数

SET GLOBAL log_bin_trust_function_creators = 1;

delimiter $
CREATE FUNCTION get_count()
RETURNS INT
BEGIN
	return(SELECT count(*) FROM employees);
END $
delimiter ;

SELECT get_count();

#有参有返回


#2. 创建函数ename_salary(),根据员工姓名,返回它的工资
SET GLOBAL log_bin_trust_function_creators = 1;
delimiter $
CREATE FUNCTION ename_salary(emp_name VARCHAR(25))
RETURNS DOUBLE(10,2)
BEGIN
	RETURN(SELECT salary 
				 FROM employees
				 WHERE last_name = emp_name);
END $
delimiter ;

SELECT ename_salary('Abel');

#3. 创建函数dept_sal() ,根据部门名,返回该部门的平均工资
delimiter $
CREATE FUNCTION dept_sal2(dept_name VARCHAR(25)) RETURNS DOUBLE(10,2)
BEGIN 
	RETURN(SELECT AVG(salary)
			   FROM employees e JOIN departments d
				 ON e.department_id = d.department_id
				 WHERE d.department_name = dept_name
				 );
END $
delimiter ;

SELECT dept_sal2('Marketing');

#4. 创建函数add_float(),实现传入两个float,返回二者之和
DELIMITER //
CREATE FUNCTION add_float(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
BEGIN
RETURN (SELECT num1 + num2 );
END //
DELIMITER ;

SET @num1 := 1.2,@num2 = 3.2;
SELECT add_float(@num1,@num2);

韩顺平索引

韩顺平索引讲解

#索引:
use atguigudb;

SELECT * 
FROM employees
where last_name = 'Abel';  #0.031

#创建索引
#创建索引后 文件会变大  索引本身会占用空间
CREATE INDEX emp_index ON employees(employee_id);
CREATE INDEX empname_index ON employees(last_name);

SELECT * 
FROM employees
where last_name = 'Abel'; # 0.032

#主键索引

#唯一索引

#普通索引

#全文索引(一般开发不使用mysql自带的全文索引,而是使用全文搜索solr和elasticsearch(es))

#创建索引
CREATE TABLE t25(
				id int,
				`name` VARCHAR(25)
);

#查询表是否有索引
SHOW indexes FROM t25;

#添加索引
#添加唯一索引
CREATE UNIQUE INDEX id_index ON t25(id);

#添加普通索引方式1
CREATE INDEX id_index ON t25(id);
#如何选择
#1 如果某列的值 是不会重复的,则优先考虑使用unique索引 否则使用普通索引

#天添加普通索引方式2
ALTER TABLE t25 ADD INDEX id_index(id);

#添加主键索引
CREATE TABLE t26(
				id INT,
				`name` VARCHAR(25));

ALTER TABLE t26 ADD PRIMARY KEY(id);

SHOW INDEX FROM t25;
SHOW INDEX FROM t26;

#删除索引
DROP INDEX id_index on t25;

#删除主键索引
alter TABLE t26 DROP PRIMARY KEY

#修改索引 (先删除 在添加新的索引)

#查询索引
#方式一
SHOW INDEX FROM t25;

#方式二
SHOW indexes FROM t25;

#方式三
SHOW KEYS FROM t25;

#方式四
desc t25;


#那些列上适合使用索引
#1 较频繁的作为查询条件字段应该创建索引

#2 唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件

#3 更新非常频繁的字段不适合创建索引

#4 不会出现在where子句中字段不该创建索引

韩顺平索引练习

#练习3
CREATE TABLE `orders`(
				id INT,
				goods VARCHAR(25),
				orderPer varchar(25),
				number INT
				);

ALTER TABLE orders ADD PRIMARY KEY(id);

CREATE TABLE `orders2`(
				id INT PRIMARY KEY,
				goods VARCHAR(25),
				orderPer varchar(25),
				number INT
				);

SHOW INDEX FROM orders
SHOW INDEX FROM orders2

#练习2
CREATE TABLE menu(
				id INT,
				menuName VARCHAR(25),
				chief VARCHAR(25),
				idcard INT(20),
				price DOUBLE(10,2)
				);

ALTER TABLE menu ADD PRIMARY KEY(id);
ALTER TABLE menu ADD UNIQUE(idcard);

SHOW index FROM menu;

CREATE TABLE menu1(
				id INT PRIMARY KEY,
				menuName VARCHAR(25),
				chief VARCHAR(25),
				idcard INT(20) UNIQUE,
				price DOUBLE(10,2)
				);
SHOW index FROM menu1;

#练习3
CREATE TABLE sportman(
				id INT PRIMARY KEY,
				`name` VARCHAR(25),
				speciality VARCHAR(25)
				);

CREATE INDEX index_name ON sportman(`name`);

ALTER TABLE sportman ADD INDEX speciality_index (speciality); 

SHOW INDEX FROM sportman;

韩顺平存储引擎

#查看所有的存储引擎
show ENGINEs;

#1 innodb 一直使用的 支持事务 支持外键

#2 myisal
# 如果不需要事务 处理的只是基本的增删改查 就用这个myisam 速度快
CREATE TABLE t29(
id int,
`name` VARCHAR(25)) ENGINE myisam;

START transaction

SAVEPOINT a;
INSERT INTO t29 VALUES (1,'jack');

SELECT * from t29;
rollback to a;

#3 memory
# 3.1 数据存储在内存中 
# 3.2 执行速度很快(没有io读写)
# 3.3 默认支持索引(hash表)
CREATE TABLE t30(
id int,
`name` VARCHAR(25)) ENGINE memory;

INSERT INTO t30 VALUES (1,'jack');
INSERT INTO t30 VALUES (2,'tom');
INSERT INTO t30 VALUES (3,'mary');
SELECT * from t30;
#memory 因为存储在内存中 所以mysql服务重启后 表内数据不存在 只保留列名

韩顺平隔离级别

#1 事务隔离级别介绍
# 多个连接开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个连接在获取数据时的准确性

#脏读:一个事务读取另外一个事务尚未提交的修改时
#     有可能回滚 放弃提交

#不可重复读:同一查询在同一事务中多次进行 由于其他提交事务所做的修改或删除 
#每次返回不同的结果集 alter delete update
#			delete alter c1还在事务还在进行,c2已提交的事务 让c1读走了

#幻读:同一查询在同一事务中多次进行 由于其他提交事务所做的插入操作 每次返回不同的结果集  insert
#     同上 不过是insert

CREATE TABLE account(
				id INT,
				`name` VARCHAR(25),
				money DOUBLE(10,2)
);

#查看当前会话隔离级别
SELECT @@transaction_isolation;
#查看系统当前隔离级别
SELECT @@global.TRANSACTION_isolation;

#设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

#设置系统当前隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL [级别]

#默认为可重复读 一般不去修改
#可以在my.ini里面设置默认的隔离级别,修改之后重新启动mysql服务

#2 事务acid特性
# 2.1 原子性
# 2.2 一致性
# 2.3 隔离性
# 2.4 持久性

start TRANSACTION


use atguigudb;

update dog set name = jack WHERE id = 1;

韩顺平事务

#事务的一个重要的概念和具体操作

#1 创建一个表
CREATE TABLE t28
				(
				id INT,
				`name` VARCHAR(25)
				);

#2 开始事务
START TRANSACTION

#3 设置保存点
SAVEPOINT a

#执行dml操作
INSERT INTO t28
VALUES (100,'tom');

SAVEPOINT b

INSERT INTO t28
VALUES (101,'tom1');

#回退到b
ROLLBACK TO b;

SELECT * FROM t28;

ROLLBACK to a;
#如果这样
rollback  #表示直接回到事务最开始的状态

COMMIT;
#commit结束事务点 删除之前所有的保存点 savepoint

#4 事务细节讨论
#4.1 如果不开始事务 默认情况下 dml操作是自动提交的 不能回滚
INSERT INTO t28
VALUES (103,'tom');

SELECT * FROM t28;

#4.2 如果开始一个事务 你没有创建保存点 你可以执行rollback
#默认就是回退到你事务开始的状态
START TRANSACTION;

INSERT INTO t28
VALUES (200,'tom');

INSERT INTO t28
VALUES (103,'tom');

ROLLBACK;
commit
#4.3 可以在事务没有提交时,创建多个保存点

#4.4 你可以在事务乜有提交前 选择回退到哪个保存点

#4.5 innodb存储引擎支持事务,myisam不支持

#4.6 开始一个事务 start transction  /  set autocommit=off
SET autocommit=off;

韩顺平用户管理讲解

韩顺平用户讲解

#因为项目开发中 可以根据不同的开发人员 给他不同的权限

#1. 创建新用户  'xxd_myself'@'localhost' 用户的完整信息 'xxd_myself 用户名  localhost 登录的ip 
CREATE USER 'xxd_myself'@'localhost' IDENTIFIED BY '123456';

SELECT * FROM mysql.user;

SELECT `host`,`user`,authentication_string
FROM mysql.user;

#删除用户
DROP USER 'xxd_myself'@'localhost'

# 3 登录用户

#不同的数据库用户 操作的库和表不相同

# 修改密码
SET PASSWORD = PASSWORD('abcdefg');

set PASSWORD FOR 'xxd_myself'@'localhost' = PASSWORD('abcdef');

#

韩顺平用户管理练习

#用户管理练习题


#1 创建一个用户
CREATE user 'xxd'@'localhost' IDENTIFIED by '123';

#2 创建库和表  使用root创建
CREATE DATABASE testdb;

CREATE table news(
				id int,
				`name` VARCHAR(25));
				
INSERT INTO news VALUES(1,'beijign');

#3 给用户分配权限
GRANT SELECT,INSERT
				ON testdb.news
				to 'xxd'@'localhost';
因为版本不同 代码也不同

韩顺平作业2,3

#2
DESC employees;
DESC departments;



#3.1 
SELECT department_name
FROM departments;

#3.2
SELECT last_name,salary*(1 + IFNULL(commission_pct,0)) * 12 'year salary'
FROM employees;

韩顺平作业4

#4.1
SELECT last_name,salary
FROM employees
WHERE salary > 2850;

#4.2
SELECT employee_id,salary
FROM employees
WHERE salary BETWEEN 1500 AND 2850;

#4.3
SELECT last_name,department_id
FROM employees
WHERE employee_id = 100;
#4.4
SELECT last_name,salary,department_id
FROM employees
WHERE department_id IN (10,30)
AND salary > 1500;

#4.5
SELECT last_name,job_id
FROM employees
WHERE manager_id IS NULL;

韩顺平作业5

#5.1
SELECT last_name,job_id,hire_date
FROM employees
WHERE hire_date BETWEEN '1988-02-01' AND '2000-05-01'
ORDER BY hire_date;
#>= '1988-02-01' AND hire_date <= '2000-05-01'

#5.2
SELECT last_name,salary,commission_pct
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary desc;

韩顺平作业6

#6.1
SELECT *
FROM employees
WHERE department_id = 30;

#6.2
SELECT last_name,employee_id,department_id
FROM employees
WHERE job_id = 'IT_PROG';

#6.3
SELECT *
FROM employees e
WHERE e.salary > (
									SELECT AVG(salary)
									FROM employees
									);

#6.4
SELECT *
FROM employees e
WHERE e.salary > (
									SELECT AVG(salary) * 1.6
									FROM employees
									);

#6.5
SELECT e1.department_id,e1.last_name,e1.employee_id,e2.manager_id
FROM employees e1 left JOIN employees e2
ON (e1.department_id = 10
AND e1.employee_id = e2.manager_id
)OR e1.department_id = 20;

#6.6

#6.7
SELECT DISTINCT job_id
FROM employees
WHERE commission_pct IS NOT NULL;

#6.8
SELECT last_name,employee_id,commission_pct
FROM employees
WHERE (salary * IFNULL(commission_pct,0)) < 1000;

#6.9 wei
#老韩提示
SELECT LAST_DAY(now()) #返回当前月份最后一天

SELECT *
FROM employees
WHERE LAST_DAY(hire_date) -2 = hire_date;

#6.10 wei 入职时间大于十二年
SELECT last_name,employee_id,hire_date
FROM employees
WHERE DATE_ADD(hire_date,INTERVAL 12 YEAR) < NOW();

#6.11 wei
SELECT CONCAT(LOWER(SUBSTRING(last_name,1,1)),substring(last_name,2))
FROM employees;

#6.12
SELECT last_name,employee_id
FROM employees
WHERE last_name LIKE '_____';


#6.13
SELECT last_name
FROM employees
WHERE last_name NOT LIKE '%r%';

#6.14
SELECT SUBSTRING(last_name,1,3)
FROM employees;

#6.15 wei
SELECT REPLACE(last_name,'A','a')
FROM employees;


#6.16
SELECT last_name,hire_date
FROM employees
WHERE date_add(hire_date,interval 10 year) < NOW();

#6.17
SELECT *
FROM employees
ORDER BY last_name;

#6.18
SELECT last_name,hire_date
FROM employees
ORDER BY hire_date;

#6.19
SELECT last_name,job_id,salary
FROM employees
ORDER BY job_id,salary desc;

#6.20 wei
SELECT last_name,concat(YEAR(hire_date),' ',MONTH(hire_date))
FROM employees
ORDER BY MONTH(hire_date),year(hire_date) ;

#6.21 wei
SELECT last_name,floor(salary / 30)
FROM employees;


#6.22
SELECT hire_date,last_name
FROM employees
WHERE MONTH(hire_date) = 2;

#6.23
SELECT last_name,DATEDIFF(now(),hire_date)'天数'
FROM employees;

#6.24
SELECT last_name
FROM employees
WHERE last_name LIKE '%A%';

#6.25
SELECT last_name,concat(round(DATEDIFF(NOW(),hire_date) / 365) ,'年',FLOOR((DATEDIFF(NOW(),hire_date) % 365) / 31) ,'月')
FROM employees;

韩顺平作业7

#7.1 wei
SELECT department_id,COUNT(*)
FROM employees
GROUP BY department_id
HAVING COUNT(employee_id) > 1;

#7.2
SELECT * 
FROM employees
WHERE salary > (
								SELECT salary
								FROM employees
								WHERE last_name = 'Abel'
								);

#7.3 
SELECT e1.last_name '员工',e1.hire_date '员工入职时间',e2.last_name '上级',e2.hire_date '上级入职时间'
FROM employees e1,employees e2
WHERE e1.hire_date > e2.hire_date
AND e1.manager_id = e2.employee_id
AND e1.last_name LIKE '%a%';

#7.4 列出部门名称和这些部门的员工信息 同时列出那些没有员工的部门
/*
显示所有部门 因此使用外连接(左外连接)
*/
SELECT department_name,e.*
FROM departments d
left JOIN employees e
ON d.department_id = e.employee_id;


#7.5 列出所有(特有信息)

#7.6
SELECT job_id
FROM employees
GROUP BY job_id
HAVING MIN(salary) < 3500;

#7.7
SELECT last_name
FROM employees
WHERE job_id = 'IT_PROG';

#7.8
SELECT *
FROM employees
WHERE salary > (
								SELECT AVG(salary)
								FROM employees
								);

#7.9 
SELECT last_name,job_id
FROM employees
WHERE job_id = (
								SELECT job_id
								FROM employees
								WHERE last_name = 'Abel'
								);
								
#7.10 列出薪水高于部门30工作的所有
SELECT salary,last_name
FROM employees
WHERE salary > (
								SELECT MAX(salary)
								FROM employees
								WHERE department_id = 30
								);

#7.11 列出在每个部门工作的员工数量 平均工资 平均服务期限(wei)
SELECT COUNT(*) AS '员工数量',AVG(salary) AS '平均工资' ,
round(AVG((DATEDIFF(NOW(),hire_date)) /365 ),2) AS '平均年限(年)',department_id
FROM employees
GROUP BY department_id;

#7.12列出所有员工的姓名 部门名称和工资
SELECT e.last_name,d.department_name,e.salary
FROM employees e
LEFT JOIN departments d
ON e.department_id = d.department_id;

#7.13列出所有部门的详细信息和部门人数(wei)

#1. 先得出各部门的人数,把下面的结果看成临时表 和 departments 表联合查询
SELECT COUNT(*) as c,department_id
FROM employees
GROUP BY department_id
#2.
SELECT d.*,tmp.c
FROM departments d,(
							     SELECT COUNT(*) as c,department_id
								   FROM employees
                   GROUP BY department_id
							     ) tmp
WHERE d.department_id = tmp.department_id;

#7.14列出各种工作的最低工资
SELECT MIN(salary),job_id
FROM employees
GROUP BY job_id;

#7.15列出管理者的最低薪水
SELECT MIN(leader.salary),leader.last_name
FROM employees leader,employees emp 
WHERE leader.department_id = emp.manager_id;

#7.16列出所有员工的年工资 按年薪从低到高排序
SELECT (salary * (1 + IFNULL(commission_pct,0)) * 12) as year_sal
FROM employees
ORDER BY year_sal;

韩顺平作业8

#8.1
#创建表 系
CREATE TABLE DEPARTMENT(
						departmrntid VARCHAR(32) PRIMARY KEY,
						deptname varchar(32) UNIQUE NOT NULL
						);
#创建表 班 class
CREATE TABLE `class`(
						classid INT PRIMARY KEY,
						`subject` VARCHAR(32) NOT NULL DEFAULT '',
						depename VARCHAR(32),
						enrolltime INT NOT NULL DEFAULT 2000,
						num INT NOT NULL DEFAULT 0,
						FOREIGN KEY (depename) REFERENCES DEPARTMENT(deptname)
						);
#创建表 学生

CREATE TABLE students(
						studentid INT PRIMARY key,
						`name` VARCHAR(32) NOT NULL DEFAULT '',
						age INT NOT NULL DEFAULT 0,
						classid INT,
						FOREIGN KEY (classid) REFERENCES `class`(classid)
						);

#添加测试数据
INSERT INTO department VALUES ('001','数学');
INSERT INTO department VALUES ('002','计算机');
INSERT INTO department VALUES ('003','化学');
INSERT INTO department VALUES ('004','中文');
INSERT INTO department VALUES ('005','经济');

INSERT INTO class VALUES (101,'软件','计算机',1995,20);
INSERT INTO class VALUES (102,'微电子','计算机',1996,30);
INSERT INTO class VALUES (111,'无机化学','化学',1991,29);
INSERT INTO class VALUES (112,'高分子化学','化学',1992,24);
INSERT INTO class VALUES (121,'统计数学','数学',1990,21);
INSERT INTO class VALUES (131,'现代语言','中文',1995,27);
INSERT INTO class VALUES (141,'国际贸易','经济',1999,12);
INSERT INTO class VALUES (142,'国际贸易','经济',1993,20);

INSERT INTO students VALUES (8101,'张三',18,101);
INSERT INTO students VALUES (8102,'李四',19,121);
INSERT INTO students VALUES (8103,'王五',18,141);
INSERT INTO students VALUES (8104,'赵六',16,111);
INSERT INTO students VALUES (8105,'李可',17,102);
INSERT INTO students VALUES (8106,'赵龙',18,101);

SELECT * FROM department
SELECT * FROM class;
SELECT * FROM students;

#找出所有行李的学生
SELECT * 
FROM students 
WHERE `name` LIKE '李%';

#列出所有开设超过一个专业的系的名字
class depename
DEPARTMENT deptname

SELECT depename
FROM class
GROUP BY depename
HAVING count(*) <> 1;

#列出人数大于等于30的系的编号和名字
SELECT departmrntid,depename
FROM DEPARTMENT d,(
										SELECT sum(num) as nums,depename
										FROM class
										GROUP BY depename
										HAVING nums >= 30
										) tmp
WHERE d.deptname = tmp.depename;


#给张三办理退学

start TRANSACTION;
#(应该先让班级减一,再去删除张三的信息,因为如果先删除张三信息,在对班级人数减一的时候就会找不到张三的班级,
#而无法对张三的班级人数减一)

#班级人数减一
UPDATE class set num = num - 1
WHERE classid = (
									SELECT classid
									FROM students
									WHERE `name` = '张三'
									);

#删除张三信息
DELETE 
FROM students
WHERE `name` = '张三';

COMMIT;

SELECT * FROM students;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值