mysql细嚼

mysql虽然用的很多了,但是功能仅仅限于那几样,现在随着业务的增多和逻辑的复杂,那么要了解更多的东西,以便能够更好的工作.


存储过程

像编程一样,处理更加复杂的逻辑,可以进行条件判断,变量申明等.和存储函数相比,就像一段程序一样,实现一个功能.
前久有需求要求能够实现自动审核,于是想用这个方案解决,copy上代码和注释,看看可以明了许多:

drop procedure if exists auto_check;
delimiter | 
-- 输入的变量in,要输出的变量out
create procedure auto_check(in check_num int)
    begin 
        -- 一定要定义变量和类型,这个是局部变量,用declare
        -- 而且这里命名要注意不要和表名,数据库名字一样,或者数据库里面的字段一样,否则很混淆
        declare user_id_var int;
        declare id_var int;
        declare politics_var varchar(20);
        declare residence_var varchar(50);
        declare idcard_var varchar(100);
        declare real_name_var varchar(50);
        declare mobile_var  varchar(100);
        declare company_unit_var  varchar(100);
        declare count_num int;
        declare tv varchar(5);
        declare tu varchar(5);
        -- 定义的变量不用马上赋值
        set tv = 'tv';
        set tu = 'tu';
        set count_num = 0;
        while count_num<check_num do
            -- 多个变量赋值也只能用一个into,set单复值,select多赋值
            select tv.id,tv.user_id,tv.politics,tv.residence,
            tv.idcard,tu.real_name,tu.mobile,tv.company_unit 
            into 
            id_var,user_id_var,politics_var,residence_var,
            idcard_var,real_name_var,mobile_var,company_unit_var   
            from tb_volunteer as tv left join 
            tb_users as tu on tv.user_id=tu.id 
            ORDER BY FIELD(tv.is_qualified,0,-1,1) limit count_num,1; 
            if (politics_var<>"" and politics_var is not null) 
                and (residence_var<>"" and residence_var is not null) 
                and (mobile_var<>"" and mobile_var is not null) 
                and (company_unit_var<>"" and company_unit_var is not null) 
                and (idcard_var<>"" and idcard_var is not null) 
                and (real_name_var<>"" and real_name_var is not null) then
                update tb_volunteer set is_qualified=1 where user_id=user_id_var;
            end if;
            set count_num = count_num+1;
        end while;
    end |
delimiter ;
-- 用户变量用@,不可用declare,全局变量用@@
set @check_num = 20;
-- 调用执行存储过程
call auto_check(@check_num);

再来一个循环的实例,用来实现查询修改数据库中重复的编号,很好的说明了过程使用:

DROP PROCEDURE IF EXISTS get_rid_of_repeated_code;
DELIMITER |
CREATE PROCEDURE get_rid_of_repeated_code()
BEGIN 
    DECLARE max_age_group_67 BIGINT; -- 存储最大的67开头组
    DECLARE max_age_group_23 BIGINT; -- 存储最大的23开头组
    DECLARE repeat_code BIGINT; -- 存储重复的每个code
    DECLARE repeat_code_count INT; -- 重复的code的个数
    DECLARE finished INT DEFAULT 0; -- 默认default为0 
    DECLARE volunteer_id int DEFAULT 0;
    DECLARE age_group_var int DEFAULT 0;
    DECLARE list text default ''; -- 测试输出的变量
    -- 所有相关的变量都要定义在cursor之前算是发现了
    DECLARE repeat_code_list CURSOR FOR (SELECT code FROM tb_volunteer WHERE code IS NOT NULL GROUP BY code HAVING COUNT(*) > 1);
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; -- 当cursor(游标)没有记录时候赋值为1,要定义在变量的最后才行

    select max(code) into max_age_group_67 from tb_volunteer where age_group = 1;
    select max(code) into max_age_group_23 from tb_volunteer where age_group = 2;
    select count(*) into repeat_code_count from (SELECT code FROM tb_volunteer WHERE code IS NOT NULL GROUP BY code HAVING COUNT(*) > 1) as n;
    -- select max_age_group_67,max_age_group_23,repeat_code_count;

    OPEN repeat_code_list;
        get_code:LOOP  -- 循环名
            FETCH repeat_code_list into repeat_code;  -- 从游标获取数据
            IF finished THEN
                LEAVE get_code;  -- 终止循环
            END IF;
                -- 循环的操作
                -- 需要处理的数据的顺序:未通过的优先改变,后注册志愿者的优先改变
                select id,age_group into volunteer_id,age_group_var from tb_volunteer where code = repeat_code ORDER BY is_qualified asc ,id desc limit 0,1;
                IF (age_group_var=1) THEN
                    SET max_age_group_67 = max_age_group_67+1;
                    update tb_volunteer set code = max_age_group_67 where id = volunteer_id;
                ELSEIF (age_group_var=2) THEN
                    SET max_age_group_23 = max_age_group_23+1;
                    update tb_volunteer set code = max_age_group_23 where id = volunteer_id;
                END IF;
            -- SET list = CONCAT(list,'-',repeat_code); -- 测试打开该行数据【1】
        END LOOP get_code;
        -- select list;  -- 测试打开该行数据【2】
    CLOSE repeat_code_list;

END |
DELIMITER ;
CALL get_rid_of_repeated_code();

事件

要让数据库没隔一段时间执行一个操作,这个很方便,代码也很简洁,这里是没60s就执行上面的自动审核的事务,如下:

drop event if exists runautocheck;
delimiter |
create event runautocheck 
on schedule 
every 60 SECOND 
on completion preserve enable 
do 
    begin 
        call auto_check(50);
    end |
delimiter ;

函数

就像一个方法,给过程调用,返回一个值,如max(),sum(),count()这些内置的方法.

CREATE FUNCTION test() RETURNS int 
BEGIN 
    DECLARE user_id INT;
    SELECT id into user_id FROM tb_users WHERE real_name = '曹孟德';
    RETURN user_id;
END;
SELECT test();

视图

在有的时候,一个表示很抽象的,可能仅仅有一些int类型的id,或者需要的数据来自于很多表的关联,实在不方便查看,于是,便有了视图这个东西.可能成天都在输入sql语句进行相关的查询,当sql很熟的时候但是又不得不重复输入的时候,它起了很大作用【注:视图实际上相当于子查询,从视图查询,实际上是相当于基于】.

当发现对一件事情厌恶的时候,不要去厌恶它,证明自己该去突破它了.
语法很简单,就是:

CREATE VIEW nameOfView AS ...[sql select]...

例子:

DROP VIEW IF EXISTS vw_activity_users ; 
CREATE VIEW vw_activity_users AS 
SELECT u.real_name AS vol_true_name,u.id as user_id,
va.title,va.work_date,va.activity_status,
uva.status AS status_code,u.nickname  
FROM tb_user_volunteer_activity AS uva 
LEFT JOIN tb_volunteer_activity AS va ON uva.volunteer_activity_id=va.id 
LEFT JOIN tb_users AS u ON uva.user_id=u.id 

备份


报表


索引


引擎

  • INNODB
  • MYISAM
  • MEMORY

部分经典语句详解

  1. 子查询的别名与否
select * from 
(
        select name,count(*) as people_number from  -- 将查询出来的部分当做表,那么一定是需要别名的
        (
                select d.name from tb_department d right join  -- 将查询出来的部分当做表,那么一定是需要别名的
                (
                    select department_id from tb_volunteer where user_id in -- 查询出来的部分当做范围,就不需要别名
                        (
                            select id from tb_users where union_id in  -- 查询出来的部分当做范围,就不需要别名
                                (
                                SELECT union_id FROM tb_score where flag = 1
                                )
                        )
                ) as v 
                on d.id=v.department_id 
        ) as r GROUP BY name
) n where name in ('xxx','yyy','mmm')
  1. 一些常用的语法结构
SELECT
    count(r.total_score >= 2500 OR NULL) AS '2500及以上',
    count(
        (r.total_score >= 2000 AND r.total_score < 2500)
        OR NULL
    ) AS '大于等于2000小于2500',
FROM
    (
        SELECT
            user_id,
            (
                volunteer_work_hour * 25 + volunteer_work_score + cw_work_hour * 25 + cw_work_score 
                + IF(youth_work_hour IS NULL,0,youth_work_hour) * 25 
                + IF(youth_work_score IS NULL,0,youth_work_score)
            ) AS total_score
        FROM
            tb_volunteer
    ) r -- 这里是作为一个新表,所以需要有别名
  1. if作为表达式【而非语句控制】
SELECT IF(gender=1,'男','女') AS sex,real_name FROM tb_users 
  1. case用法
SELECT CASE gender 
WHEN 1 THEN '男' 
WHEN 0 THEN '女' 
END AS sex 
FROM tb_users

设计方面

  1. 三范式
1NF:表的所有的属性【所有列】都是原子级别的,也就是不可再分解;
2NF:表的每个属性都仅仅依赖于此表的主键,即一张表仅仅做一件事请;
3NF:表内的每个属性都和主键直接联系,其中属性不存在传递【包含】关系
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容