2018-03-27mysql学习心得

Mysql学习

mysql概述-->安装数据库-->NavicatPremium使用-->SQL操作-->创建表-->表结构-->表记录操作-->表查询-->系统函数-->自定义函数-->控制语句-->存储过程-->备份

-- cmd命令(管理员身份)
net start mysql 启用数据库
net stop mysql 停用数据库

-- mysql cmd命令
show databases ;查询所有表
use mysql  查询用户信息
select user,host,password from user;查询用户账号,密码,地址

-- mysql快捷键
注释三种快捷键:#  ,  --空格 ,  /*  */

-- 名词解释
列,字段值
行,记录
结果集,符合SQL语句中条件的所有集合集,
结果集一般是一个表,其中有查询所返回的列标题及相应的值

-- 创建数据库
navicat可视化页面点击右键创建/SQL创建create database lemon1;
-- 创建表
CREATE TABLE member(
id int(11) primary key,
regName varchar(50),
pwd varchar(50),
mobilePhone varchar(20),
type TINYINT,
leaveAmount decimal(18,2),
regTime TIMESTAMP
)DEFAULT CHARSET=UTF8;

create table 表名(字段,字段类型);

-- 约束分类:
1.主键约束primary key counstraint
2.默认约束 default counstraint
3.唯一约束 unique key counstraint
4.外键约束foreign key counstraint
5.检查约束check counstraint

主键约束
字段 primary key
自增长
auto_increment
重置自增初始值
alter table s auto_increment=0;(在自增长小于设置值才会有效)
truncate table s;(截断当前自增长值,重0开始自增长)

默认约束
default
时间默认值 default CURRENT_TIMESTAMP
数据默认值 default 1 / default 0.00

唯一约束 (一个表只有一个主键,但是可以存在多个唯一约束)
unique key (针对有值数据,null不受控制)
非空约束
not null1指定字段不能为空
null空值

外键约束
foreign key counstraint
CREATE TABLE loan(
ID INT(11) not null primary key auto_increment,
memberId int(11) not null comment'用户id',
title varchar(50) not null comment'标题',
amount decimal(18,2) not null comment'借款金额',
loanRate decimal(3,1) not null comment'年利率,如年化18.0%,存储为18.0',
loanTerm tinyint(1) not null comment'借款期限,如6个月为6,,30天为30',
loanDateTime TINYINT(1) not null comment'借款期限类型 借款期限单位 0-按月,1-按天',
createTime TIMESTAMP not null default CURRENT_TIMESTAMP comment'创建时间',
fullTime TIMESTAMP  null default null comment'满标时间',
status TINYINT(1) default 1 comment'1:审核中2:竞标中3:还款中4:还款完成',
foreign key (memberId) references member(id)
)default CHARSET=UTF8;
注意点;
1.外键和参照列字段类型要一致
2.字表和父表存储引擎要一样innoDB引擎
3.外键和参照列必须创建索引
4.这种物理外键并不常用,一般在表设计的时候指定逻辑外键约束
用show ENGINES;查看支持的引擎
5.检查约束check counstraint

-- 数据库操作
1增alter table s add c1 ,add c2 after c3;
2删alter table s drop c1,arop c2,add c3
3改字段类型,列名,表名
/alter table s modify c int UNSIGNED DEFAULT 2 first;设置默认值
/ALTER table s ALTER c set default 4;设置默认值
/alter TABLE s alter c drop default;删除默认值
/ALTER table c change column  createtime regTime TIMESTAMP;列column
/alter table member rename member2;
/RENAME table member2 to member;修改表rename
注意:新增字段需要写完整数据类型

-- 删除数据库和表
drop database db_name;
drop table table_name;
帮助命令 help drop/help drop database查看帮助语法
drop table  if EXISTS member;
drop database if exists lemon;

-- 添加约束,删除约束
添加主键约束,
alter table member add primary key(id);
添加唯一约束,
alter table member add unique key(regName);
添加外键约束
alter table loan add CONSTRAINT fk_id FOREIGN key (memberid) REFERENCES member(id);
添加默认约束
alter table member alter type set default 3;
删除外键约束
alter table loan drop foreign key fk_id;
删除默认约束
ALTER table member alter type drop DEFAULT;

insert
添加一行数据
insert into member VALUES(2,'ros','123','13666666',1,0.00,2);
添加一行部分数据(非空并且未赋默认值的必须要给值)
insert member(regName,pwd,mobilePhone,TYPE)VALUES('nik','123','13777777',1);
添加多行数据(主键不能重复)
insert member(id,regName,pwd,mobilePhone,TYPE)VALUES(3,'nike','123','13777777',1),(4,'js','123','13777777',1);
使用null让id自增
INSERT member(id,pwd)values(null,'123');
使用default让id自增
INSERT member(id,pwd)values(default,'123');
使用default插入默认值
INSERT member(id,pwd,type,leaveamount,regtime)values(default,'67',default,default,default);
新增记录插入某表设置某值
insert set
INSERT member set regname='ros2',pwd='123';
新增某表,数据来源某表
insert select
INSERT member(regname,pwd,mobilephone) SELECT regname,pwd,mobilephone FROM member;
insert  s set c='';

删除表delete
delete from s;
delete from s where c='';
truncate table s;截断表

where子句,用and和or链接,多于update,delete,select使用;
where子句操作符,=,<>/!=,>,>=,<,<=;
delete from member where id>30;
delete from member where mobilephone!=13000000005;
delete from member where mobilephone<>13000000005;
delete from member where id=5 and mobilephone=13000000006;
delete from member where id=5 or mobilephone=13000000006;

修改表update
update member set pwd='123456';修改所有的记录
update member set leaveamount=0.00 where id=1;修改指定字段
update member set leaveAmount=1000.00,pwd='abc' where id =1;修改指定字段

查询表select
select * from member;查询全部字段
select regname,pwd,mobilephone from member;查询指定字段
select regname,mobilephone,leaveamount from member where leaveamount>20000;-- 条件查询
select 1;-- 常量
select 1+2;-- 计算器
select now();-- 当前时间
select version();-- 当前版本
select member.regName,member.pwd from member;-- 表名点字段查询
select member.regName as 用户名,member.pwd as 密码 from member;-- 用别名查询

sql脚本导入
个性化查询
--LIKE模糊查询子句
SELECT * from member where regname like '小鱼儿';like 代替等于=
select * from member where regname ='小鱼儿';
select * from member where regname LIKE '小%';以百分号匹配like语句
select * from member where regname LIKE '%小';
select * from member where regname LIKE '%小%';
select * from member where regname LIKE '小__';以英文下的横杆占字符,匹配like语句
select * from member where regname LIKE '___小';

-- between and /not between AND 范围限定
select * from member where leaveamount between 20000 and 30000;
select * from member where leaveamount >=20000 and leaveamount<=30000;
select * from member where leaveamount  not between 20000 and 30000;
select regname, mobilephone,leaveamount,
leaveamount between 20000 and 30000 from member;-- (20000-30000返回1,其他返回0)
select 18 between 20 and 25;--表达式返回布尔类型;true1,false0;

-- DISTINCT 去重
select distinct memberid from invest order by memberid DESC;统计中去重

-- group by 分组
/*
第50期共30名学生
分别求男,女同学数量;-->根据学生性别先分组,在进行统计
分别求男,女同学平均年龄;
分别求班上最小男,女同学年龄;
分别男,女同学年龄总和;
*/
group by 字段1,字段2
select * from invest where memberid =2 order by amount desc;
select memberid 用户id,
min(amount) 最小投资额,
max(amount) 最大投资额,
sum(amount) 投资总额,
count(1) 投资次数,
avg(amount) 平均投资额
from invest group by  memberid;


having 分组筛选语句,与group by联合使用
WHERE在group by前,在聚合函数前
having在group后,在聚合函数后
select memberid 用户id,
min(amount) 最小投资额,
max(amount) 最大投资额,
sum(amount) 投资总额,
count(1) 投资次数,
avg(amount) 平均投资额
from invest group by  memberid
having sum(amount)>50000;


-- 排序 order by desc /ASC
select memberid 用户id,
min(amount) 最小投资额,
max(amount) 最大投资额,
sum(amount) 投资总额,
count(1) 投资次数,
avg(amount) 平均投资额
from invest group by  memberid
having sum(amount)>50000
ORDER BY sum(amount) DESC;

-- LIMIT分页 在排序后面使用
-- LIMIT M,N,N表示要查询多少记录,M表示从M+1条记录开始取,M可称为索引/偏移量
select * from member limit 0,10;
select * from member limit 10,10;
select * from member limit 20,10;
select * from member limit 30,10;
-- OFFSET 偏移量
select * from member limit 10 OFFSET 0;
select * from member limit 10 OFFSET 10;
select * from member limit 10 OFFSET 20;
-- top 语法,取最顶部数据
select * from member limit 1;
select* from member order by leaveamount DESC limit 1;

初始化项目数据
drop table if exists girls;
CREATE table girls(
girlNum varchar(20),
matchNum int(10)
);
insert into girls
(girlNum,matchnum)VALUES
("girl-001",1),
("girl-002",2),
("girl-003",3),
("girl-004",4),
("girl-005",5),
("girl-006",6);

drop table if exists boys;
CREATE table boys(
boyNum varchar(20),
matchNum int(10)
);
insert into boys
(boyNum,matchnum)VALUES
("boy-001",1),
("boy-002",2),
("boy-003",3),
("boy-004",7),
("boy-005",8),
("boy-006",9);

-- INNER JOIN 内连接
select * from boys INNER JOIN girls;
select * from boys,girls;-- 笛卡尔积
select * from boys inner join girls where boys.matchNum=girls.matchNum;
-- on的方式,using
select * from boys INNER JOIN girls on boys.matchNum=girls.matchNum;-- on
select * from boys INNER JOIN girls using(matchNum);-- USING
-- join 、cross JOIN 隐式内连接
select * from boys CROSS JOIN girls;
select * from boys JOIN girls;
-- LEFT JOIN左外连接
select * from boys LEFT JOIN girls ON boys.matchNum=girls.matchNum
where girls.matchNum is not NULL;-- is not null、is null 查询该字段不为空的记录
-- right join 右外连接
select * from boys RIGHT JOIN girls on boys.matchNum=girls.matchNum;
select boys.boyNum,boys.matchNum from girls RIGHT JOIN boys on boys.matchNum=girls.matchNum
WHERE girlNum is null;
-- full join 完全连接,UNION
select * from girls full join boys;-- 笛卡尔积
select girlNum 嘉宾编号,matchNum 牵手编号 from girls
UNION
select boyNum 嘉宾编号,matchNum 牵手编号 from boys;

select girls.girlNum 嘉宾编号,girls.matchNum 牵手编号 from boys RIGHT  JOIN girls
ON boys.matchNum=girls.matchNum
where boyNum is not NULL
union
select boys.boyNum 嘉宾编号,boys.matchNum 牵手编号 from boys left  JOIN girls
ON boys.matchNum=girls.matchNum
where girlNum is not NULL;
-- union all /union(去除重复)
SELECT 1 UNION SELECT 1;-- 结果1
SELECT 1 UNION all SELECT 1;-- 结果两个1

-- 连接查询
select DISTINCT t1.id,t1.leaveAmount,t1.mobilePhone from member t1,invest t2
where t1.id=t2.memberId ORDER BY t1.id;
select DISTINCT t1.id,t1.leaveAmount,t1.mobilePhone  from member t1 LEFT JOIN invest t2 on t1.id=t2.memberid
where t2.id is  not null ORDER BY t1.id;

初始数据准备
create table tb_lemon_grade(
id INT(10) not null auto_increment primary key,
s_name VARCHAR(20) default null,
score int(3) default 0,
c_name VARCHAR(20) default null
)COMMENT'学生成绩表';
insert into tb_lemon_grade (s_name,score,c_name)value
("刘一",79,'18期'),
("陈二",71,'18期'),
("张三",85,'18期'),
("李四",60,'19期'),
("王五",67,'19期'),
("赵六",70,'19期'),
("孙七",100,'20期'),
("周八",88,'20期'),
("吴九",89,'21期'),
("郑十",92,'21期');

-- 非相关子查询
-- 查询平均分
select avg(score) from tb_lemon_grade;
-- 查询高于平均分学生信息
select * from tb_lemon_grade where score>(select avg(score) from tb_lemon_grade);
-- 查询每期平均分
select avg(score),c_name from tb_lemon_grade GROUP BY c_name;

-- 相关子查询
-- 查询高于本期的平均分学生信息
select * from tb_lemon_grade t1
where t1.score>
(select avg(t2.score) from tb_lemon_grade t2 where t1.c_name=t2.c_name);

-- 比较运算符
-- 查询出id最大的学生
SELECT * from tb_lemon_grade ORDER BY id desc limit 1;
select *from tb_lemon_grade where id=(select max(id)from tb_lemon_grade);

-- 子查询 in和not_in型子查询
-- select * from 表名 where 字段 in(数据集合);
select * from member where id=1 or id=2 or id=3;
select * from member where id in(1,2,3);
-- 查询出没有投资的用户信息
select * from member where id not in(select distinct memberid from invest);

-- 子查询 EXISTS,NOT EXISTS子查询,强调是否返回结果集返回ture,不返回false
select * from member where EXISTS(select 1);-- 返回ture
select * from member where EXISTS(select *from member where id =0);-- 返回false
select * from member where not EXISTS(select *from member where id =0);-- 返回ture
select * from member t1 where EXISTS (select * from invest t2 where t2.memberid=t1.id);-- 返回ture
select * from member t1 where NOT EXISTS (select * from invest t2 where t2.memberid=t1.id);

-- 74临时表创建
CREATE TEMPORARY TABLE member_tmp(
regname VARCHAR(20),
mobilephone char(11));
insert into member_tmp values ('tp','123')
select * from member_tmp
drop table member_tmp;-- 删除临时表

-- 复制表,通过show create table语句复制表
show create table member;
CREATE TABLE `member_tmp` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `regName` varchar(10) DEFAULT NULL COMMENT '注册名',
  `pwd` varchar(16) NOT NULL COMMENT '密码',
  `mobilePhone` char(11) DEFAULT NULL,
  `type` tinyint(1) DEFAULT '1',
  `leaveAmount` double(18,2) DEFAULT '0.00',
  `regTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `regName` (`regName`)
) ENGINE=MyISAM AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 COMMENT='会员表'
drop table member_tmp;-- 删除复制表

-- 只复制表结构like
create table member_tmp like member;
drop table member_tmp;
-- 复制数据和结构as
create table member_tmp as select * from member;
select * from member_tmp;
drop table member_tmp;
-- 实战查询数据到临时表
CREATE temporary table member_tohao as select * from member where leaveamount >40000;
select * from member_tohao;
drop table member_tohao;

-- 75视图
-- VIEW 视图create view 表2 as 表2数据
-- 创建一个view 保持土豪数据(leaveamount>40000)昵称,手机号
CREATE view v_tuhao1 as
select regname,mobilePhone from member where leaveamount >40000;
select * from v_tuhao1
-- 修改视图create or replace view  表2 as 表2数据
create or replace  VIEW v_tuhao1 as
select regname,mobilePhone from member where leaveamount >40000;
-- 删除视图
drop view v_tuhao1;
-- 查询视图
show TABLES;
show TABLES like '%tuhao%';
-- 查看视图详情
desc v_tuhao1;
show fields from v_tuhao1;

-- 76聚合函数
-- AVG() ,COUNT(),NAX(),MIN(),SUM(),一般与select语句的group by子句一起使用
select avg(amount) from invest;
select count(amount) from invest;-- 计数
select max(amount) from invest;
select min(amount) from invest;
select sum(amount) from invest;-- 忽略null值

-- 77比较运算符和函数
-- not between and, not in,is not null,least(),greatest(),
select least(1,3,5,7,9);-- 比较最小值
select greatest(1,3,5,7,9);-- 比较最大值
select greatest ('A','B','C','Z');-- 比较最大值,根据ascii值比较
-- 横向统计
select greatest(id,memberid,amount)from invest;-- 横向统计最大数据

-- 78字符函数
-- concat(),concat_ws(),lower(),upper(),left(),right(),format(),
-- concat
select concat('my','s','ql');-- 拼接字符串,返回mysql
select concat('my',null,'ql')-- 返回null
select concat(regname,'-',mobilephone)from member;-- 字符拼接
-- CONCAT_WS(separator,str1,str2,...)以分割符连接字符串
select concat_ws('-',regname,mobilephone,leaveAmount)from member;
-- LOWER(str),UPPER(str)
select LOWER(regName),UPPER(regName)from member;-- 转换大小写字符
-- LEFT(str,len),RIGHT(str,len),截取最左,最右字符长度
select mobilephone,left(mobilephone ,5),right(mobilephone,5)from member;
-- FORMAT(X,D)数字格式化
select FORMAT(12334884.33335,4)-- 返回12,334,884.3334

-- SUBSTR(str FROM pos FOR len),SUBSTR(str FROM pos),SUBSTR(str,pos),SUBSTR(str,pos,len)
select mobilephone,substr(mobilephone ,5)from member;-- 从第5个字符串开始截取
select mobilephone,substr(mobilephone from 5)from member;
select mobilephone,substr(mobilephone from 2 for 5)from member;-- 从第2个字符串开始截取,截取5位
select mobilephone,substr(mobilephone,2,5)from member;
select mobilephone,substr(mobilephone,-2,5)from member;-- 从倒数第2个字符串开始截取,截取5位

-- 79数值函数
-- ABS(X),返回数值绝对值
select ABS(-5);-- 返回5
-- CEIL(X),进一取整,返回不小于X的最小整数值
select CEIL(-9.8);-- 返回-9
-- DIV,整数除法,类似于floor
select 10 div 3;-- 返回3
-- FLOOR(X)  进一取整,返回不大于X的最大整数值
select FLOOR(9.8),FLOOR(-9.8);-- 返回9,-10
-- MOD,取余数(取模)
select MOD(10,3);-- 返回1
-- POW(X,Y),POWER(X,Y),幂运算
select POW(2,3),POWER(2,4);-- 返回8,16
-- ROUND(X),ROUND(X,D),四舍五入
select ROUND(1.23),ROUND(1.51);-- 整数位四舍五入,返回1,2
select ROUND(1.23,1),ROUND(1.51,1);-- 小数位四舍五入,返回1.2,1.5
-- TRUNCATE(X,D),数值截取
select TRUNCATE(1.23,1);-- 返回1.2
-- RAND(),返回一个随机浮点值v,范围在0到1之间(即,其范围为0<=v<=1.0)
select RAND();-- 随机返回值
select RAND(1);-- 固定返回值

-- 80日期函数
-- NOW(),CURDATE(),CURTIME(),
select NOW(),CURDATE(),CURTIME();-- 返回当前日期
-- DATE_ADD(date,INTERVAL expr unit),DATE_SUB(date,INTERVAL expr unit),对时间加减计算
select NOW(),-- 当前时间
DATE_ADD(NOW(),INTERVAL 1 DAY),-- 加一天
ADDDATE(NOW(),INTERVAL 1 day),-- 加一天
DATE_SUB(NOW(),INTERVAL 1 day),-- 减一天
SUBDATE(NOW(),INTERVAL 1 day);-- 减一天
-- DATEDIFF(expr1,expr2),
SELECT DATEDIFF('2018-03-20','2018-04-20');-- 前面减后面时间的差值
-- DATE_FORMAT(date,format)指定时间的格式
SELECT DATE_FORMAT('2018-03-20 18:15:00','%h-%i-%s');-- 用横杆符号连接

-- 81信息函数
select DATABASE(),CONNECTION_ID(),LAST_INSERT_ID(),USER(),VERSION();-- 查询数据库,连接id,最后一条数据id,当前用户,版本
INSERT member( regname,pwd,mobilephone) VALUES ('tom1','123456','123456');-- 插入数据
select LAST_INSERT_ID();-- 查询最后一条插入数据id

-- 82加密函数
-- MD5(str),PASSWORD(str)
select MD5('123456');
select PASSWORD('123456');-- 用于对mysql密码加密

-- 83IF 控制函数
-- IF(expr1,expr2,expr3),第一个表达式为ture,返回表达式2,为false返回表达式3
select regname,mobilephone,leaveAmount,IF(leaveAmount>=4000,'是土豪','不是土豪')from member;

-- 84case...WHEN...THEN,case的值满足when的时候,取then的结果,可以为多对when/then
select case 1 when 1 then 'one' when 2  then 'two' else 'more' end;-- 返回one
select case 4 when 1 then 'one' when 2  then 'two' else 'more' end;-- 返回more
select case when 1>2 then '1大于2' when 1<2 then '1小于2' else '1等于2' end;-- 返回1小于2
select regname,mobilephone,leaveAmount,
case when leaveAmount>=40000 then '土豪'
when leaveAmount<40000 and leaveAmount>=20000 then '中产阶级'
else '无产阶级'end
from member;
-- 查询会员信息,如果是内部用户标记为'内部',普通用户标记为'普通',否则为'其他'
select regname,mobilephone,leaveAmount,
case type when 1 then '内部' when 2 then '普通' else '其他' end
from member;

-- 85 NULLIF(expr1,expr2)不为空,返回表达式1,为空,返回表达式2
select * from loan where fulltime is null;
select title,amount,fulltime,ifnull(fulltime,'未满标')from loan;

-- 86分隔符修改 delimiter,设置mysql的结束符
delimiter ;-- sql以分好号结尾

-- 87新增函数
delimiter //-- 定义结束符
drop function if exists f_say_hello;
create function f_say_hello()-- 创建自定义函数名
returns varchar (20)-- 返回值类型定义
begin  
-- 多条sql
return 'hello world';
end//
delimiter ;-- 定义结束符

/*即create function 函数名称(参数列表)
returns 返回值类型
函数体
备注:函数体由begin end;语句块包含
*/
-- 删除函数
drop function f_say_hello;
-- 调用函数
select f_say_hello();-- 函数名加括号,表示函数

-- 88带参函数的自定义函数,单个参数
delimiter //
DROP function if exists f_say_a_word;
create function f_say_a_word(word varchar (20))
returns varchar (20)
begin
-- SQL
return word;
end//
delimiter ;
-- 调用函数,单个参数
select f_say_a_word('hello world');
-- 带参函数的自定义函数,多个参数
--a+b,两个参数的加法运算
delimiter //
drop function if exists f_add_num;
create function f_add_num(a int,b int)
returns int
begin
return a+b;
end//
delimiter ;
select f_add_num(1,2);-- 返回3

-- 89变量与自定义函数实战
-- 得到某用户平均的投资额
delimiter //
drop function if exists f_get_avg_amount;
create function f_get_avg_amount(userid int)
returns decimal(18,2)
begin
-- 定义一个变量:保存该用户的投资总额
declare _sumamount decimal(18,2) default 0.00;
-- 定义一个变量:保存该用户的投资次数
declare _countamount int default 0;
-- 为变量赋值
-- set _sumamount=100.00;
-- 求出该用户的投资总额,赋值给_sumamount
select sum(amount) into _sumamount from invest where memberid=userid;
-- 求出该用户的投资次数,赋值给_countamount
select count(1) into _countamount from invest where memberid=userid;
return _sumamount;
end//
delimiter ;
select f_get_avg_amount(2);-- 返回用户id为2的平均投资金额36900.00

-- 90控制语句模板
delimiter//
drop function if exists f_name;
create function f_name()
returns  varchar(20)
begin
return 'hello';
end//
delimiter ;
select f_name();

-- 91if 语句
-- 传入一个memberID,返回会员是否是土豪(leaveamount>40000)、无产(10000)、中产(>10000,<40000)
delimiter//
drop function if exists f_is_tohao;
create function f_is_tohao(memberid int)-- 传入参数
returns  varchar (20)
begin
declare _msg varchar (20);-- 定义一个msg 保存输出信息
declare _amount decimal (18,2);-- 定义一个局部变量,保存查询出来的该会员的余额
select leaveamount into _amount from member where id=memberid;-- 查询会员余额保存到局部变量中
if _amount <10000 then set _msg='我是无产';-- 通过if分支结构对局部变量进行判断
ELSEIF _amount>=10000 and _amount<40000 then set _msg='我是中产';
else set _msg='我是土豪';
end if;-- 结束if语句
return _msg;-- 返回值
end//
delimiter ;
-- 去掉注释查看
delimiter //
DROP FUNCTION IF EXISTS f_is_tuhao;
CREATE FUNCTION f_is_tuhao (memberid INT)
RETURNS VARCHAR (20)
BEGIN
DECLARE _msg VARCHAR (20);
DECLARE _amount DECIMAL (18, 2);
SELECT
    leaveamount INTO _amount
FROM member
WHERE id = memberid;
IF _amount <10000 THEN
SET _msg = '我是无产' ;
ELSEIF _amount >= 10000 AND _amount < 40000 THEN
SET _msg = '我是中产';
ELSE
SET _msg = '我是土豪';
END IF;
RETURN _msg;
end//
delimiter ;
select f_is_tuhao(1);


-- 92 case 条件判断语句
-- 创建一个方法,传入一个memberid,返回用户类型(1:普通 2:内部 3:其他)
delimiter//
drop function if exists f_get_member_type_msg;
create function f_get_member_type_msg(memberid int)
returns  varchar(20)
begin
declare _msg varchar(20);
declare _type tinyint;
select type into _type from member where id=memberid;
case _type
when 1 then set _msg='普通';
when 2 then set _msg='内部';
else set _msg='其他';
end case;
return _msg;
end//
delimiter ;
select f_get_member_type_msg(1);
-- case 与if对比
delimiter //
DROP FUNCTION IF EXISTS f_is_tuhao1;
CREATE FUNCTION f_is_tuhao1 (memberid INT)
RETURNS VARCHAR (20)
BEGIN
DECLARE _msg VARCHAR (20);
DECLARE _amount DECIMAL (18, 2);
SELECT
    leaveamount INTO _amount
FROM member
WHERE id = memberid;
case
when _amount<10000 then SET _msg = '我是无产' ;
when _amount >= 10000 AND _amount < 40000 THEN SET _msg = '我是中产';
ELSE SET _msg = '我是土豪';
end CASE;
/*IF
_amount <10000 THEN SET _msg = '我是无产' ;
ELSEIF _amount >= 10000 AND _amount < 40000 THEN SET _msg = '我是中产';
ELSE SET _msg = '我是土豪';
END IF;
*/
RETURN _msg;
end//
delimiter ;
select f_is_tuhao1(1);

-- 93loop 循环控制语句
insert into tb_lemon_grade (s_name,score,c_name)values ('tom',80,'30期');

delimiter//
drop function if exists f_loop_insert_1;
create function f_loop_insert_1()
returns  varchar(20)
begin
  insert_loop:LOOP
insert into tb_lemon_grade (s_name,score,c_name)values ('tom',80,'30期');
end loop insert_loop;
return "1";
end//
delimiter ;
select f_loop_insert_1();
select count(1) from tb_lemon_grade;
TRUNCATE tb_lemon_grade;

-- 94leave结束循环语句
-- 循环插入100条数据
delimiter//
drop function if exists f_loop_insert_1;
create function f_loop_insert_1()
returns  varchar(20)
begin
declare _num int;
set _num=1;
insert_loop:LOOP
insert into tb_lemon_grade (s_name,score,c_name)values ('tom',80,'30期');
set _num=_num+1;
if _num>100
then LEAVE insert_loop;
end if;
end LOOP insert_loop;
return "2";
end//
delimiter ;
select f_loop_insert_1();
select count(1) from tb_lemon_grade;
TRUNCATE tb_lemon_grade;

-- 95 跳出本次循环
delimiter//
drop function if exists f_loop_insert_2;
create function f_loop_insert_2()
returns  varchar(20)
begin
declare _num int;
set _num=0;
insert_loop:LOOP
set _num=_num+1;
-- 当_num为偶数时,跳出本次循环
if _num%2=0 then ITERATE insert_loop;-- 跳出循环
end if;
if _num>100 then LEAVE insert_loop;-- 结束循环
end if;

insert into tb_lemon_grade (s_name,score,c_name)values ('tom',80,'30期');

if _num%2=0
then LEAVE insert_loop;
end if;
end LOOP insert_loop;
return "1";
end//
delimiter ;
select f_loop_insert_2();
select count(1) from tb_lemon_grade;
TRUNCATE tb_lemon_grade;

-- 96 repeat条件控制语句
delimiter//
drop function if exists f_loop_insert_3;
create function f_loop_insert_3()
returns  varchar(20)
begin
declare _num int;
set _num=0;
insert_repeat:REPEAT
set _num =_num+1;
insert into tb_lemon_grade (s_name,score,c_name)values ('tom',80,'30期');
until _num=100  -- repeat until end repeat语句
end REPEAT insert_repeat;
return "1";
end//
delimiter ;
select f_loop_insert_3();
select count(1) from tb_lemon_grade;
TRUNCATE tb_lemon_grade;

-- 97 while  DO循环
-- 当条件满足的时候执行循环体
delimiter//
drop function if exists f_loop_insert_4;
create function f_loop_insert_4()
returns  varchar(20)
BEGIN
declare _num int;
set _num=1;
insert_while:WHILE _num<=100 DO
insert into tb_lemon_grade (s_name,score,c_name)values (concat('tom',_num),80,concat(_num,'期'));
set _num=_num+1;
end WHILE insert_while;
return "1";
end//
delimiter ;
select f_loop_insert_4();
select count(1) from tb_lemon_grade;
TRUNCATE tb_lemon_grade;
select * from tb_lemon_grade;

-- 98 PROCEDURE 存储过程
-- 创建存储过程
delimiter //
create procedure proc_get_mysql_version()
select version()//
delimiter;
-- 使用begin/end 作为结束
delimiter //
create procedure proc_get_mysql_version()
begin
select version();
end//
delimiter;
-- 修改存储过程 drop
delimiter //
drop PROCEDURE if exists proc_get_mysql_version;-- 删除在创建
create procedure proc_get_mysql_version()
begin
select version();
end//
delimiter;
-- 调用存储过程 call
call proc_get_mysql_version();
call proc_get_mysql_version;-- 可以不加括号

-- 99存储过程和自定义函数区别
返回值:
存储过程 可以有多个返回值
函数 只能有一个返回值

参数:
存储过程 可以有多个in.out,inout参数
函数 只有输入参数,而且不能带in

使用:
存储过程一般作为独立的部分进行执行
函数可以作为查询表达式部分进行调用

存储过程可以调用函数
函数不能调用存储过程

存储功能语句功能更强大,可实现复杂的业务逻辑
函数的针对性则更强

-- 100 存储过程参数
-- in 必须在调用存储过程时指定使用
-- 表示输入一个值,你需要一个值,我给你一个值
-- 创建一个存储过程,删除一个投资用户相关的信息:投资、回款计划信息、用户信息
delimiter //
drop procedure if exists proc_delete_member_info;
create procedure proc_delete_member_info(in userid INT UNSIGNED)-- in 参数
BEGIN
-- 删除所有的回款计划信息
delete  from repayment where  investid in (select id from invest where memberid=userid);
-- 删除投资记录
delete  from invest where  memberid=userid;
-- 删除用户信息
delete  from member  where  id=userid;
end //
delimiter ;
-- 调用函数
call proc_delete_member_info(42);-- 调用函数
select * from invest where memberid =42;-- 记录执行函数后,被删除,返回空


-- 101 out参数
-- 该参数的值可能被存储过程改变,并且可以返回
-- 往外输出一个值(输出的这个值可以拿一个变量来接收)
--
-- 创建一个存储过程,删除一个投资用户相关的信息:投资、回款计划信息、用户信息,返回剩下的用户数量
delimiter //
drop procedure if exists proc_delete_member_info;
create procedure proc_delete_member_info(in userid INT UNSIGNED,out count_num int UNSIGNED )-- in/out
BEGIN
-- 删除所有的回款计划信息
delete  from repayment where  investid in (select id from invest where memberid=userid);
-- 删除投资记录
delete  from invest where  memberid=userid;
-- 删除用户信息
delete  from member  where  id=userid;
-- 查询当前的用户总数
select count(1) from member into count_num;
end //
delimiter ;
select count(1) from member;-- 统计数量
call proc_delete_member_info(28,@count_num);-- 调用函数,使用@接收变量(@符合+参数名称)
call proc_delete_member_info(27,@count_num);-- 调用函数,使用变量接收
select @count_num;-- 查询变量
set @num=1;-- 定义变量
select @num+1;-- 查询变量+1,返回2
select @num;-- 查询变量,返回1

-- 102 INOUT
-- 该参数的值在调用存储过程时指定,并且可以被改变和返回
-- 数据传入存储过程,经过计算在传出返回值
delimiter //
drop procedure if exists proc_in_out_inout;
create procedure proc_in_out_inout(
in in_num int,
OUT out_num int,
INOUT inout_num int
)
BEGIN
set in_num=in_num+1;
set @in_num2=in_num+1;
set out_num=out_num+1;
set inout_num=inout_num+1;
end//
delimiter ;

set @a=1;
set @b=10;
set @c=100;
call proc_in_out_inout(@a,@b,@c);
select @a,@b,@c,@in_num2;
-- a=1,in类型,输入
-- b为空,out类型,输出
-- c=101,1inout类型,输入并输出
-- in_num2=3,变量接收

--103 条件和处理程序
delimiter //
drop PROCEDURE if exists p_condition_handler;
create procedure p_condition_handler()
begin
select * from hello;
end//
delimiter;
call p_condition_handler();-- 调用错误,错误分析
-- [Err] 1146(42s02):Table 'lemon.hello' doesn't exist
-- 1.已经发生错误
-- 2.1146:错误码
-- 3.42s02:sql状态值

-- 104 定义条件
delimiter //
drop PROCEDURE if exists p_condition_handler;
create procedure p_condition_handler()
begin
-- 定义处理程序
DECLARE  does_not_exist condition for sqlstate '42S02';
DECLARE  does_not_exist condition for '1146';
select * from hello;
insert into member(id)VALUES(10087);
end//
delimiter;
call p_condition_handler();
-- [Err] 1146(42s02):Table 'lemon.hello' doesn't exist
-- 1.已经发生错误
-- 2.1146:错误码
-- 3.42s02:sql状态值

-- 105 定义处理程序(待定)
delimiter //
drop PROCEDURE if exists p_condition_handler;
create procedure p_condition_handler()
begin
-- 定义条件两种发式,sqlstate_value/mysql_error_code
-- DECLARE  does_not_exist condition for sqlstate '42S02';
-- DECLARE  does_not_exist condition for '1146'
-- 处理程序几种方式
-- 捕获 SALSTATE_VALUE/捕获mysql_error_code/does_not_exist CONDITION for 1146
-- DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' set @flag=1;
-- DECLARE CONTINUE HANDLER FOR 1146 set @flag=1;
DECLARE  does_not_exist condition for 1146;
DECLARE CONTINUE HANDLER for  does_not_exist set @flag=1;
set @flag=2;
select * from hello;
insert into member(id)VALUES(66);
end//
delimiter;
CALL p_condition_handler();
select * from member ORDER BY id desc limit 1;
select @flag;

-- 106光标 CURSOR
/*
光标的操作步骤
声明光标
打开光标
使用光标
关闭光标
*/
-- 声明光标,光标名cur_member
declare cur_member CURSOR for select id,name from member;

delimiter //
drop PROCEDURE if EXISTS p_cursor;
CREATE PROCEDURE p_cursor()
BEGIN
DECLARE _id int;
-- 声明光标
declare cur_member cursor for select id FROM member;
-- 打开光标
open cur_member;
-- 使用光标
FETCH cur_member into _id;
-- 关闭光标
close cur_member;
END//
delimiter ;
-- eg
delimiter //
drop PROCEDURE if EXISTS proc_cursor;
create PROCEDURE proc_cursor()
BEGIN
declare _id  int;
declare cur_member cursor for select id FROM member;
open cur_member;
FETCH cur_member into _id;
FETCH cur_member into _id;
FETCH cur_member into _id;
close cur_member;
select _id;
END//
delimiter ;
call proc_cursor();-- 返回3

-- 107编写还款存储过程,查询还款计划,循环每条记录,更新用户余额,更新还款计划状态
-- 写一个存储过程,用来处理还款功能
delimiter//
drop PROCEDURE if EXISTS proc_repayment;
create PROCEDURE proc_repayment()
BEGIN
-- 定义全局变量
DECLARE _repaymentid int;
declare _investid int;
DECLARE _principal decimal(18,0);
DECLARE _interest decimal(18,0);
DECLARE _memberid int;
declare _done int default 0;
-- 定义一个光标,保存所有当前要还款的记录
DECLARE cur_repayment CURSOR FOR
-- 查询需要还款的还款计划列表
select id,investId,unfinishedPrincipal,unfinishedInterest
from repayment
where STATUS = 0 and repaymentDate<ADDDATE(CURDATE(),INTERVAL 1 DAY);
-- 定义一个处理程序
DECLARE CONTINUE HANDLER for not found set _done=1;
-- 打开光标
open cur_repayment;
-- 然后循环每条记录,进行对应的还款
repayment_repeat:REPEAT
-- 使用光标赋值给四个全局变量
FETCH cur_repayment into _repaymentid ,_investid,_principal,_interest;
-- 找到投资记录 (memberid)
select memberid into _memberid from invest where id=_investid;
-- 根据memberid找出该用户,更新余额信息
update member set leaveAmount=leaveAmount+(_interest+_principal)where id=_memberid;
-- 更新汇款状态为1
UPDATE repayment set status =1 where id=_repaymentid;
until _done=1 end repeat repayment_repeat;
end //
delimiter;


-- 108修改存储过程,添加if循环语句
delimiter//
drop PROCEDURE if EXISTS proc_repayment;
create PROCEDURE proc_repayment()
BEGIN
-- 定义全局变量
DECLARE _repaymentid int;
declare _investid int;
DECLARE _principal decimal(18,0);
DECLARE _interest decimal(18,0);
DECLARE _memberid int;
declare _done int default 0;
-- 定义一个光标,保存所有当前要还款的记录
DECLARE cur_repayment CURSOR FOR
-- 查询需要还款的还款计划列表
select id,investId,unfinishedPrincipal,unfinishedInterest
from repayment
where STATUS = 0 and repaymentDate<ADDDATE(CURDATE(),INTERVAL 1 DAY);
-- 定义一个处理程序
DECLARE CONTINUE HANDLER for not found set _done=1;
-- 打开光标
open cur_repayment;
-- 然后循环每条记录,进行对应的还款
repayment_repeat:REPEAT
-- 使用光标,赋值给四个全局变量
FETCH cur_repayment into _repaymentid ,_investid,_principal,_interest;
if _done =1 THEN
LEAVE repayment_repeat;
end if;
-- 找到投资记录 (memberid)
select memberid into _memberid from invest where id=_investid;
-- 根据memberid找出该用户,更新余额信息
update member set leaveAmount=leaveAmount+(_interest+_principal)where id=_memberid;
-- 更新汇款状态为1
UPDATE repayment set status =1 where id=_repaymentid;
until _done=1 end repeat repayment_repeat;
end //
delimiter;

-- 108功能验证和错误修复
select * from repayment;
select ADDDATE(CURDATE(),INTERVAL 1 DAY)
-- 记录还款总金额,79555.00
select sum(unfinishedPrincipal+unfinishedInterest)
from repayment
where STATUS = 0 and repaymentDate<ADDDATE(CURDATE(),INTERVAL 1 DAY);

update repayment set status=0 where id in(4572,4573);
update member set leaveAmount=0;

select sum(leaveamount)from member;
-- 调用函数
call proc_repayment();

-- 109功能验证和错误修复2,精度导致数据有差别,优化存储过程,decimal(18,2);
select * from repayment;
select ADDDATE(CURDATE(),INTERVAL 1 DAY)
-- 记录还款总金额,79555.00
select sum(unfinishedPrincipal+unfinishedInterest)
from repayment
where STATUS = 0 and repaymentDate<ADDDATE(CURDATE(),INTERVAL 1 DAY);
-- 还款记录数据
select count(1)
from repayment
where STATUS = 0 and repaymentDate<ADDDATE(CURDATE(),INTERVAL 1 DAY);
update repayment set status=0 where id in(4572,4573);
-- 清空member表还款金额
update member set leaveAmount=0;
select sum(leaveamount)from member;
-- 调用函数
call proc_repayment();

-- 存储过程优化,
delimiter//
drop PROCEDURE if EXISTS proc_repayment;
create PROCEDURE proc_repayment()
BEGIN
-- 定义全局变量
DECLARE _repaymentid int;
declare _investid int;
DECLARE _principal decimal(18,2);
DECLARE _interest decimal(18,2);
DECLARE _memberid int;
declare _done int default 0;
-- 定义一个光标,保存所有当前要还款的记录
DECLARE cur_repayment CURSOR FOR
-- 查询需要还款的还款计划列表
select id,investId,unfinishedPrincipal,unfinishedInterest
from repayment
where STATUS = 0 and repaymentDate<ADDDATE(CURDATE(),INTERVAL 1 DAY);
-- 定义一个处理程序
DECLARE CONTINUE HANDLER for not found set _done=1;
-- 打开光标
open cur_repayment;
-- 然后循环每条记录,进行对应的还款
repayment_repeat:REPEAT
-- 使用光标,赋值给四个全局变量
FETCH cur_repayment into _repaymentid ,_investid,_principal,_interest;
if _done =1 THEN
LEAVE repayment_repeat;
end if;
-- 找到投资记录 (memberid)
select memberid into _memberid from invest where id=_investid;
-- 根据memberid找出该用户,更新余额信息
update member set leaveAmount=leaveAmount+(_interest+_principal)where id=_memberid;
-- 更新汇款状态为1
UPDATE repayment set status =1 where id=_repaymentid;
until _done=1 end repeat repayment_repeat;
end //
delimiter;

-- 110触发器trigger
-- 特殊的存储过程
-- 当表上预定义时间发生时会被mysql自动调用
/*
INSERT,插入表数据时激活触发程序,如insert,load data,replace;
UPDATE,更新表记录某一行时激活触发程序,如update
DELETE,从表中删除某一行时激活触发程序,如dalete,replace;
*/
-- 当向member表中插入一行记录时,触发直接向invest插入一条记录
delimiter //
drop trigger if exists t_insert_invest;
create trigger t_insert_invest AFTER INSERT
ON MEMBER FOR EACH ROW
BEGIN
INSERT INTO invest(memberid,loanid,amount)values(10,10,1000.00);
END//
delimiter;
-- 验证触发器
select count(1) from invest;
INSERT INTO member (regname,mobilephone,pwd)values('1231','123',123);

-- 111new ,old 用于表示触发器的所在表中触发了触发器的那一行数据
/*
INSERT,new 表示将要或者已经插入的新数据
UPDATE,old表示将要或者已经被修改的原数据,new 表示将要或者已经插入的新数据
DELETE,old表示将要或者已经被修改的原数据
old.columnName老数据列,new.columnName新数据,相应某一列数据
*/
delimiter //
drop trigger if exists t_delete_member_info;
create trigger t_delete_member_info BEFORE DELETE
ON MEMBER FOR EACH ROW
BEGIN
-- 删除所有的回款计划信息
delete  from repayment where  investid in (select id from invest where memberid=old.id);
-- 删除投资记录
delete  from invest where  memberid=old.id;
END//
delimiter;
-- 验证触发器
select * from member where id=15;
select * from invest where memberid=15;
select * from repayment where investid in(select id from invest where memberid=15);
delete from member where id=15;-- 执行删除操作,触发器执行

-- 112 问题描述和解决方案
-- 统计所有投资用户的投资次数、投资总额
select memberid,sum(amount),count(1)
from invest where status=
-- 问题1:每条重复统计会耗费性能,以空间换时间(用一种冗余字段)
-- 解决方案:设计字段,保存统计数据
-- memberid,invescount,investsum
-- 问题2:字段是建立在member表中,还是另外新建一个表
-- 解决方案:新建扩展表,保存member的一些统计信息或者额外信息
create table member_ext(
memberid int,
investcount int,
investsum DECIMAL(10,2)
);

-- 113同步已存在的数据到新建表
-- 问题3:已经存在的用户信息怎么办
-- 解决方案:循环每个投资人,计算出各自投资次数和投资总额,然后插入一条记录
select* from member_ext;
insert into member_ext SELECT memberid,sum(amount),count(1)
from invest where status=1
GROUP BY memberId;

-- 114
-- 问题4
-- 用户第一次投资(2,10000):往扩展表中插入一条记录(2,10000,1)
-- 用户在一次投资(2,5000):更新扩展表中对应的用户统计信息(2,15000,1)
-- 解决方案:使用触发器
-- invest(当用户投资后,往invest插入一条记录)
delimiter//
drop trigger if EXISTS t_invest_data;
create trigger t_invest_data after INSERT
on invest for each ROW
BEGIn
DECLARE _count TINYINT;
select count(1) INTO _count from member_ext where memberid=new.memberid;
-- 用户第一次投资(2,10000):往扩展表中插入一条记录(2,10000,1)
-- if 第一次投资插入数据,if不是第一次,更新数据
if _count=0 then INSERT into member_ext VALUES(new.memberid,1,new.amount);
else update member_ext
set investcount=investcount+1,investsum=investsum+new.amount
where memberid=new.memberid;
end if;
-- 用户在一次投资(2,5000):更新扩展表中对应的用户统计信息(2,15000,1)
end//
delimiter;

-- 115验证触发器
-- 1.找到一个没有投资的用户
select * from invest where memberID=42;
select * from member_ext where memberID=42;
-- 2.对用户进行投资
insert into invest(memberid,loanid,amount)values(42,9,10000);
-- 对用户进行再次投资
insert into invest(memberid,loanid,amount)values(42,9,300);

 

posted @ 2018-03-27 14:48  AIME2020  阅读(204)  评论(0编辑  收藏  举报