zoukankan      html  css  js  c++  java
  • 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);

  • 相关阅读:
    Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶
    《开讲啦》 20160910 颜宁:女科学家去哪儿了?
    pysam
    Python项目实战
    最小二乘估计法
    最大似然估计(Maximum Likelihood,ML)
    HMM隐马尔科夫模型
    贝叶斯推断|朴素贝叶斯分类|贝叶斯定理
    解决“tar:Exiting with failure status due to previous errors”【转】
    df -h执行卡住不动问题解决【转】
  • 原文地址:https://www.cnblogs.com/AIME/p/8657423.html
Copyright © 2011-2022 走看看