• 数据库之存储过程


    存储过程

    1.什么是存储过程?

    存储过程就类似于python中的自定义的函数,它的内部包含了一系列可以执行的sql语句,存储过程存放于mysql服务端中,你可以直接通过调用存储过程触发内部sql语句的执行

    2.存储过程的基本使用

    procedure /prəˈsiːdʒə(r) 程序, 过程

    -- 创建语法
    delimiter //
    create procedure 存储过程的名字([形参1,形参2,...])
    begin
    	sql代码
    end //
    delimiter ;
    
    -- mysql 中调用存储过程语法
    call 存储过程的名字([实参1,实参2,...]);
    
    -- python中基于pymysql调用
    cursor.callproc("存储过程的名字")
    print(cursor.fetchall())
    

    3.三种开发模式: 程序与数据库结合开发

    # 第一种
    """  
    应用程序: 程序员写业务代码开发
    mysql: dba提前编写好存储过程,供应用程序调用
    好处: 开发效率提升了,执行效率也上去了
    缺点: 考虑到人为因素,需要跨部门沟通问题,后续的存储过程的扩展性差
    """
    
    # 第二种
    """
    应用程序: 程序员写代码开发之外 涉及到数据库操作也要自己手写
    优点: 解决了跨部门不方便扩展的问题
    缺点: 开发效率低,都是程序员干活.程序员不仅要会多种编程语言,还要考虑sql语句的执行效率问题
    """
    
    # 第三种
    """
    应用程序: 程序员只写程序代码 不写sql语句了.而是用别人写好的操作sql的框架即可
    比如: 后面要讲的ORM框架对象关系映射
    优点: 开发效率比前俩种开发效率都要高
    缺点: 语句的扩展性差,可能会出现效率低下的问题.
    """
    # 第一种基本不用,一般都是第三种方法,当出现效率低下的情况,再去手动的写一些sql语句
    

    4.创建存储过程并调用(无参)

    创建库并准备表和数据

    create database procedure_test charset utf8;
    use procedure_test;
    
    CREATE TABLE blog (
        id INT PRIMARY KEY auto_increment,
        NAME CHAR (32),
        sub_time datetime
    );
    
    INSERT INTO blog (NAME, sub_time)
    VALUES
        ('第1篇','2015-03-01 11:31:21'),
        ('第2篇','2015-03-11 16:31:21'),
        ('第3篇','2016-07-01 10:21:31'),
        ('第4篇','2016-07-22 09:23:21'),
        ('第5篇','2016-07-23 10:11:11'),
        ('第6篇','2016-07-25 11:21:31'),
        ('第7篇','2017-03-01 15:33:21'),
        ('第8篇','2017-03-01 17:32:21'),
        ('第9篇','2017-03-01 18:31:21');
    

    mysql种创建及调用

    delimiter //
    create procedure p1()
    begin
    	select * from blog;
    	insert into blog(name,sub_time) values('ldsb',now());
    end //
    delimiter ;
    
    # 调用
    call p1();
    

    python中基于pymysql调用

    import pymysql
    
    conn = pymysql.connect(
    	host = '127.0.0.1',
        port=3306,
        user='root',
        password='jzd123',
        database='procedure_test',
        charset='utf8'
    )
    
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    
    # 在python中 通过游标下的callproc方法调用存储过程p1
    cursor.callproc('p1')
    print(cursor.fetchall())
    
    cursor.close()
    conn.close()
    

    5.创建存储过程并调用(有参)

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

    in , out 和 inout

    -- n n int      ---> 声明变量n为外部传入的值, 类型为int. 可以为存储过程定义的形参in直接传值,
    -- out res int  ---> 声明变量res为返回值, 类型为int. 为存储过程定义的形参out传值, 需要实现使用set声明才能传.
    -- inout x int  --->  声明变量x既能收值又能返回值. 虽然inout既能接收又能充当返回值, 但是为了保证int和out的传值的统一性, 因此也需要事先使用set声明才能传.
    
    • in: 传入参数
    Copydelimiter //
    create procedure p2(
        in n1 int,
        in n2 int
    )
    BEGIN
        select * from blog where id > n1;
    END //
    delimiter ;
    
    
    # 在mysql中调用
    call p2(3,2)
    
    # 在python中基于pymysql调用
    cursor.callproc('p2',(3,2))
    print(cursor.fetchall())
    
    • out:返回值
    Copydelimiter //
    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;       # 定义全局变量用于给out定义的res形参. 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()
    
    • inout: 既可以传入又可以返回
    Copydelimiter //
    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())
    

    6. 执行存储过程: int+out

    • 创建库并准备表和数据
    Copydrop database procedure_test;  # 小心
    create database procedure_test charset utf8;
    use procedure_test;
    
    create table emp(
      id int not null unique auto_increment,
      name varchar(20) not null,
      sex enum('male','female') not null default 'male', #大部分是男的
      age int(3) unsigned not null default 28,
      hire_date date not null,
      post varchar(50),
      post_comment varchar(100),
      salary double(15,2),
      office int, #一个部门一个屋子
      depart_id int
    );
    
    #插入记录
    #三个部门:教学,销售,运营
    insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
    ('jason','male',18,'20170301','张江第一帅形象代言',7300.33,401,1), #以下是教学部
    ('tom','male',78,'20150302','teacher',1000000.31,401,1),
    ('kevin','male',81,'20130305','teacher',8300,401,1),
    ('tony','male',73,'20140701','teacher',3500,401,1),
    ('owen','male',28,'20121101','teacher',2100,401,1),
    ('jack','female',18,'20110211','teacher',9000,401,1),
    ('jenny','male',18,'19000301','teacher',30000,401,1),
    ('sank','male',48,'20101111','teacher',10000,401,1),
    ('哈哈','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
    ('呵呵','female',38,'20101101','sale',2000.35,402,2),
    ('西西','female',18,'20110312','sale',1000.37,402,2),
    ('乐乐','female',18,'20160513','sale',3000.29,402,2),
    ('拉拉','female',28,'20170127','sale',4000.33,402,2),
    ('僧龙','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
    ('程咬金','male',18,'19970312','operation',20000,403,3),
    ('程咬银','female',18,'20130311','operation',19000,403,3),
    ('程咬铜','male',18,'20150411','operation',18000,403,3),
    ('程咬铁','female',18,'20140512','operation',17000,403,3);
    
    • mysql中创建及调用
    Copydrop procedure p1;
    
    # 定义存储过程
    delimiter $$
    create procedure p1(
        in m int,  # 该形参m只负责接收值, m不能当作参数返回。
        in n int,  
        out res int  # 该形参res只负责返回值,不能直接接收参数,需要使用set先定义变量。 针对out存储过程的返回值参数一定要设置一个变量, 通常用返回值判断你这天sql语句运行成功与否, 返回值为0通常代表成功
    )
    begin
        select tname from teacher where tid>m and tid<n;
        set res=0;  # 将res变量修改, 用来标识当前的存储过程代码确实执行了。(修改成啥都行)
    end  $$
    delimiter ;
    
    # 定义变量
    set @xxx=10;  # 争对形参res不能直接传数据,因该传一个变量命。
    
    # 查看变量对应得值
    set @xxx;
    
    # 调用存储过程
    """
    第一个第二个参数: 为存储过程in定义的参数传值
    第二个参数: 为存储过程out定义的返回值传值, out需要使用set声明才能传
    """
    call p1(1, 10, @xxx);
    
    # 删除存储过程
    drop procedure p1;
    
    • pymysql模块使用存储过程
    Copyimport pymysql
    
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='jzd123',
        database='procedure_test',
        charset='utf8',
    )
    
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    
    # 调用存储过程
    cursor.callproc('p1', (1, 5, 10))
    """
    pymysql底层实现. 
    set @_p1_0 = 1
    set @_p1_1 = 5
    set @_p1_2 = 10
    """
    print(cursor.fetchall())  
    
    # 执行select语句验证
    cursor.execute('select @_p1_0')  
    print(cursor.fetchall())  # [{'@_p1_0:1'}]
    
    cursor.close()
    conn.close()
    

    7. 删除存储过程

    Copydrop procedure 存储过程的名字;
    
  • 相关阅读:
    C#枚举中使用Flags特性
    WPF 设置输入只能英文
    PHP array_merge_recursive() 函数
    PHP array_merge() 函数
    PHP array_map() 函数
    PHP array_keys() 函数
    PHP array_key_exists() 函数
    [HNOI2016]网络
    WPF 设置输入只能英文
    WPF 设置输入只能英文
  • 原文地址:https://www.cnblogs.com/jkeykey/p/14457468.html
Copyright © 2020-2023  润新知