zoukankan      html  css  js  c++  java
  • 数据库---mysql内置功能

    一、视图

    简介:

      视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,可以将该结果集当做表来使用。使用视图我们可以把查询过程中的临时表摘出来,用视图去实现,这样以后再想操作该临时表的数据时就无需重写复杂的sql了,直接去视图中查找即可,但视图有明显地效率问题,并且视图是存放在数据库中的,如果我们程序中使用的sql过分依赖数据库中的视图,即强耦合,那就意味着扩展sql极为不便,因此并不推荐使用。

    使用方法:

    #两张有关系的表
    mysql> select * from course;
    +-----+--------+------------+
    | cid | cname  | teacher_id |
    +-----+--------+------------+
    |   1 | 生物   |          1 |
    |   2 | 物理   |          2 |
    |   3 | 体育   |          3 |
    |   4 | 美术   |          2 |
    +-----+--------+------------+
    rows in set (0.00 sec)
    
    mysql> select * from teacher;
    +-----+-----------------+
    | tid | tname           |
    +-----+-----------------+
    |   1 | 张磊老师        |
    |   2 | 李平老师        |
    |   3 | 刘海燕老师      |
    |   4 | 朱云海老师      |
    |   5 | 李杰老师        |
    +-----+-----------------+
    rows in set (0.00 sec)
    
    #查询李平老师教授的课程名
    mysql> select cname from course where teacher_id = (select tid from teacher where tname='李平老师');
    +--------+
    | cname  |
    +--------+
    | 物理   |
    | 美术   |
    +--------+
    rows in set (0.00 sec)
    
    #子查询出临时表,作为teacher_id等判断依据
    select tid from teacher where tname='李平老师'
    
    临时表应用举例
    视图的使用方法

    1.创建视图

    #语法:CREATE VIEW 视图名称 AS  SQL语句
    create view teacher_view as select tid from teacher where tname='李平老师';
    
    #于是查询李平老师教授的课程名的sql可以改写为
    mysql> select cname from course where teacher_id = (select tid from teacher_view);
    +--------+
    | cname  |
    +--------+
    | 物理   |
    | 美术   |
    +--------+
    rows in set (0.00 sec)
    
    #!!!注意注意注意:
    #1. 使用视图以后就无需每次都重写子查询的sql,但是这么效率并不高,还不如我们写子查询的效率高
    
    #2. 而且有一个致命的问题:视图是存放到数据库里的,如果我们程序中的sql过分依赖于数据库中存放的视图,
    那么意味着,一旦sql需要修改且涉及到视图的部分,则必须去数据库中进行修改,而通常在公司中数据库有专门的DBA负责,
    你要想完成修改,必须付出大量的沟通成本DBA可能才会帮你完成修改,极其地不方便
    创建视图

    2.使用视图

    #修改视图,原始表也跟着改
    mysql> select * from course;
    +-----+--------+------------+
    | cid | cname  | teacher_id |
    +-----+--------+------------+
    |   1 | 生物   |          1 |
    |   2 | 物理   |          2 |
    |   3 | 体育   |          3 |
    |   4 | 美术   |          2 |
    +-----+--------+------------+
    rows in set (0.00 sec)
    
    mysql> create view course_view as select * from course; #创建表course的视图
    Query OK, 0 rows affected (0.52 sec)
    
    mysql> select * from course_view;
    +-----+--------+------------+
    | cid | cname  | teacher_id |
    +-----+--------+------------+
    |   1 | 生物   |          1 |
    |   2 | 物理   |          2 |
    |   3 | 体育   |          3 |
    |   4 | 美术   |          2 |
    +-----+--------+------------+
    rows in set (0.00 sec)
    
    mysql> update course_view set cname='xxx'; #更新视图中的数据
    Query OK, 4 rows affected (0.04 sec)
    Rows matched: 4  Changed: 4  Warnings: 0
    
    mysql> insert into course_view values(5,'yyy',2); #往视图中插入数据
    Query OK, 1 row affected (0.03 sec)
    
    mysql> select * from course; #发现原始表的记录也跟着修改了
    +-----+-------+------------+
    | cid | cname | teacher_id |
    +-----+-------+------------+
    |   1 | xxx   |          1 |
    |   2 | xxx   |          2 |
    |   3 | xxx   |          3 |
    |   4 | xxx   |          2 |
    |   5 | yyy   |          2 |
    +-----+-------+------------+
    rows in set (0.00 sec)
    使用视图

     注意:我们不应该修改视图中的记录,而且在涉及多个表的情况下是根本无法修改视图中的记录的,如下图

    3.修改视图

    #语法:ALTER VIEW 视图名称 AS SQL语句
            mysql> alter view teacher_view as select * from course where cid>3;
            Query OK, 0 rows affected (0.04 sec)
            
            mysql> select * from teacher_view;
            +-----+-------+------------+
            | cid | cname | teacher_id |
            +-----+-------+------------+
            |   4 | xxx   |          2 |
            |   5 | yyy   |          2 |
            +-----+-------+------------+
            rows in set (0.00 sec)
    修改视图

    4.删除视图

    语法:DROP VIEW 视图名称
    
    DROP VIEW teacher_view
    删除视图

    二、触发器

    简介

      使用触发器可以定制用户对表进行【增、删、改】操作时前后的行为,注意:没有查询。这是mysql内部实现得触发器得功能;

    1.创建触发器

    # 插入前
    CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 插入后
    CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 删除前
    CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 删除后
    CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 更新前
    CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 更新后
    CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    #准备表
    CREATE TABLE cmd (
        id INT PRIMARY KEY auto_increment,
        USER CHAR (32),
        priv CHAR (10),
        cmd CHAR (64),
        sub_time datetime, #提交时间
        success enum ('yes', 'no') #0代表执行失败
    );
    
    CREATE TABLE errlog (
        id INT PRIMARY KEY auto_increment,
        err_cmd CHAR (64),
        err_time datetime
    );
    
    #创建触发器
    delimiter //
    CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW
    BEGIN
        IF NEW.success = 'no' THEN #等值判断只有一个等号
                INSERT INTO errlog(err_cmd, err_time) VALUES(NEW.cmd, NEW.sub_time) ; #必须加分号
          END IF ; #必须加分号
    END//
    delimiter ;
    
    
    #往表cmd中插入记录,触发触发器,根据IF的条件决定是否插入错误日志
    INSERT INTO cmd (
        USER,
        priv,
        cmd,
        sub_time,
        success
    )
    VALUES
        ('egon','0755','ls -l /etc',NOW(),'yes'),
        ('egon','0755','cat /etc/passwd',NOW(),'no'),
        ('egon','0755','useradd xxx',NOW(),'no'),
        ('egon','0755','ps aux',NOW(),'yes');
    
    
    #查询错误日志,发现有两条
    mysql> select * from errlog;
    +----+-----------------+---------------------+
    | id | err_cmd         | err_time            |
    +----+-----------------+---------------------+
    |  1 | cat /etc/passwd | 2017-09-14 22:18:48 |
    |  2 | useradd xxx     | 2017-09-14 22:18:48 |
    +----+-----------------+---------------------+
    rows in set (0.00 sec)
    
    插入后触发触发器
    创建触发器

    2.使用触发器

    触发器无法由用户直接调用,而知由于对表的【增//改】操作被动引发的。
    查看触发器:show triggersG;

    3.删除触发器

    drop trigger tri_after_insert_cmd; 

    三、储存过程

    1.储存过程介绍

      存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql

    优点:

    • 用于替代程序写的SQL语句实现程序与sql解耦
    • 基于网络传输,传别名的数据量小,而直接传sql数据量大

    缺点:

    • 程序员扩展不方便

    补充

    #方式一:
        MySQL:存储过程
        程序:调用存储过程
    
    #方式二:
        MySQL:
        程序:纯SQL语句
    
    #方式三:
        MySQL:
        程序:类和对象,即ORM(本质还是纯SQL语句)

    2.创建简单的存储过程(无参)

    create table blog(
        id int primary key auto_increment,
        name varchar(16),
        sub_time datetime
    );
    insert into blog(name,sub_time) values('alice',now());  
    
    delimiter //
    create procedure p1()
    begin
        select * from blog;
        insert into blog(name,sub_time) values('xxx',now());
    end //
    delimiter ;
    
    #在mysql中调用
    call p1(); 
    
    #在python中基于pymysql调用
        cursor.callproc('p1') 
        print(cursor.fetchall())
        conn.commit()   # 一定要有,否则在增删改时,不能更新到数据库;
    示例代码

    3.创建简单的储存过程(有参)

    对于存储过程,可以接收参数,其参数有三类:

    • in 仅用于传入参数用
    • out 仅用于返回值用
    • inout 既可以传入又可以当作返回值 
    1.in:传入参数   
                delimiter //
                create procedure p2(in n1 int,in n2 int)
                begin
                    select * from blog where id between n1 and n2;
                end //
                delimiter ;
                
                #在mysql中调用
                    call p2(2,15);
                
                #在python中基于pymysql调用 
                    cursor.callproc('p2',(2,15))
                    print(cursor.fetchall())
                    conn.commit()   # 一定要有,否则在增删改时,不能更新到数据库;    
            2.out:返回值 
                delimiter //
                create procedure p3(in n1 int,out res int)
                begin
                    select * from blog where id > n1; 
                    set res = 1;
                end //
                delimiter ;
                
                #在mysql中调用
                    set @res=0; #0代表假(执行失败),1代表真(执行成功)
                    call p3(3,@res);
                    select @res; 
                #在python中基于pymysql调用
                    cursor.callproc('p3',(3,0)) #0相当于set @res=0
                    print(cursor.fetchall()) #查询select的查询结果
                    
                    cursor.execute('select @_p3_0,@_p3_1;') #@p3_0代表第一个参数,@p3_1代表第二个参数,即返回值
                    print(cursor.fetchall())   #((3, 1),) 
            3.inout:既可以传入又可以返回   
                delimiter //
                create procedure p4(inout n1 int)
                begin
                    select * from blog where id > n1;
                    set n1 = 1;
                end // 
                delimiter ;
                
                #在mysql中调用
                    set @x=3;
                    call p4(@x);
                    select @x;
                
                #在python中基于pymysql调用
                    cursor.callproc('p4',(3,)) # 逗号(,)一定要写,否则会报错,是元祖
                    print(cursor.fetchall()) #查询select的查询结果
                    
                    cursor.execute('select @_p4_0;') 
                    print(cursor.fetchall())
    示例代码

    4.执行储存过程

            -- 无参数
            call proc_name()
    
            -- 有参数,全in
            call proc_name(1,2)
    
            -- 有参数,有in,out,inout
            set @t1=0;
            set @t2=3;
            call proc_name(1,2,@t1,@t2)
            2.在python中基于pymysql执行存储过程
            #!/usr/bin/env python
            # -*- coding:utf-8 -*-
            import pymysql
    
            conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
            cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
            # 执行存储过程
            cursor.callproc('p1', args=(1, 22, 3, 4))
            # 获取执行完存储的参数
            cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
            result = cursor.fetchall()
    
            conn.commit()
            cursor.close()
            conn.close()
    
            print(result)
    示例代码

    5.删除储存过程

    drop procedure proc_name; 

    四、事物

    简介

    事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。
    一堆sql语句:要么同时执行成功,要么同时失败 原子性
    场景: 转账;

    create table user(
    id int primary key auto_increment,
    name char(32),
    balance int
    );
    
    insert into user(name,balance)
    values
    ('wsb',1000),
    ('egon',1000),
    ('ysb',1000);
    
    #原子操作
    start transaction;
    update user set balance=900 where name='wsb'; #买支付100元
    update user set balance=1010 where name='egon'; #中介拿走10元
    update user set balance=1090 where name='ysb'; #卖家拿到90元
    commit;
    
    #出现异常,回滚到初始状态
    start transaction;
    update user set balance=900 where name='wsb'; #买支付100元
    update user set balance=1010 where name='egon'; #中介拿走10元
    uppdate user set balance=1090 where name='ysb'; #卖家拿到90元,出现异常没有拿到
    rollback;
    commit;
    mysql> select * from user;
    +----+------+---------+
    | id | name | balance |
    +----+------+---------+
    |  1 | wsb  |    1000 |
    |  2 | egon |    1000 |
    |  3 | ysb  |    1000 |
    +----+------+---------+
    rows in set (0.00 sec)
    示例代码

    介绍:

    delimiter //
                create procedure p4(
                    out status int
                )
                BEGIN
                    1. 声明如果出现异常则执行{
                        set status = 1;
                        rollback;
                    }
    
                    开始事务
                        -- 由秦兵账户减去100
                        -- 方少伟账户加90
                        -- 张根账户加10
                        commit;
                    结束
    
                    set status = 2;
    
    
                END //
                delimiter ;
    介绍

    实现:

    delimiter //
    create PROCEDURE p5(
        OUT p_return_code tinyint
    )
    BEGIN 
        DECLARE exit handler for sqlexception 
        BEGIN 
            -- ERROR 
            set p_return_code = 1; 
            rollback; 
        END; 
    
        DECLARE exit handler for sqlwarning 
        BEGIN 
            -- WARNING 
            set p_return_code = 2; 
            rollback; 
        END; 
    
        START TRANSACTION; 
            DELETE from tb1; #执行失败
            insert into blog(name,sub_time) values('yyy',now());
        COMMIT; 
    
        -- SUCCESS 
        set p_return_code = 0; #0代表执行成功
    
    END //
    delimiter ;
    
    #在mysql中调用存储过程
    set @res=123;
    call p5(@res);
    select @res;
    
    #在python中基于pymysql调用存储过程
    cursor.callproc('p5',(123,))
    print(cursor.fetchall()) #查询select的查询结果
    
    cursor.execute('select @_p5_0;')
    print(cursor.fetchall())
    
    事务
    实现

    五、函数

    参考:https://www.luffycity.com/python-book/di-8-zhang-mysql-shu-ju-ku/87-mysqlnei-zhi-gong-neng/875-han-shu.html

       

  • 相关阅读:
    1063. Set Similarity
    A1047. Student List for Course
    A1039. Course List for Student
    最大公约数、素数、分数运算、超长整数计算总结
    A1024. Palindromic Number
    A1023. Have Fun with Numbers
    A1059. Prime Factors
    A1096. Consecutive Factors
    A1078. Hashing
    A1015. Reversible Primes
  • 原文地址:https://www.cnblogs.com/Mryang123/p/9039533.html
Copyright © 2011-2022 走看看