zoukankan      html  css  js  c++  java
  • MySQL学习笔记之MySQL自定义函数

    一、什么是函数
    函数存储着一系列sql语句,调用函数就是一次性执行这些语句。所以函数可以降低语句重复。【但注意的是函数注重返回值,不注重执行过程,所以一些语句无法执行。所以函数并不是单纯的sql语句集合。】

    二、函数和存储过程的区别
    关于存储过程,可以查看MySQL学习笔记之MySQL存储过程
    1)存储过程可以没有返回值,也可以有多个返回值,比较适合做批量插入、批量更新等操作
    2)函数有且仅有一个返回值,比较适合做处理数据后返回一个结果

    三、创建函数

      语法:
      create function 函数名([参数列表]) returns 返回类型
      begin
            函数体
      end
      参数格式:参数名 参数类型
    

    四、调用函数
    语法:select 函数名(参数列表)

    五、系统变量log_bin_trust_function_creators

      首先查看一个系统变量:log_bin_trust_function_creators
      
      select @@log_bin_trust_function_creators;
      mysql> select @@log_bin_trust_function_creators;
      +-----------------------------------+
      | @@log_bin_trust_function_creators |
      +-----------------------------------+
      |                                 0 |
      +-----------------------------------+
      1 row in set (0.00 sec)
    

    变量说明:
    当二进制日志启用后,这个变量就会启用。它控制是否可以信任存储函数创建者,不会创建写入二进制日志引起不安全事件的存储函数。如果设置为0(默认值),用户不得创建或修改存储函数,除非它们具有除CREATE ROUTINE或ALTER ROUTINE特权之外的SUPER权限。 设置为0还强制使用DETERMINISTIC特性或READS SQL DATA或NO SQL特性声明函数的限制。 如果变量设置为1,MySQL不会对创建存储函数实施这些限制。 此变量也适用于触发器的创建。
    当log_bin_trust_function_creators的值为0时创建存储函数将会报错:ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable),如下:

      mysql> delimiter $$
      mysql> create function get_students_total() returns int
            -> begin
            -> declare total int default 0; # 定义total变量,默认值为0
            -> select count(*) into total from students;
            -> return total;
            -> end $$
      ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
      
      mysql> set @@global.log_bin_trust_function_creators = 1;
      Query OK, 0 rows affected (0.00 sec)
    
      mysql> delimiter $$
      mysql> create function get_students_total() returns int
            -> begin
            -> declare total int default 0;
            -> select count(*) into total from students;
            -> return total;
            -> end $$
      Query OK, 0 rows affected (0.02 sec)
    
      mysql> select get_students_total();
      +----------------------+
      | get_students_total() |
      +----------------------+
      |                    7 |
      +----------------------+
      1 row in set (0.06 sec)
    

    那么为什么MySQL有这样的限制呢? 因为二进制日志的一个重要功能是用于主从复制,而存储函数有可能导致主从的数据不一致。
    所以当开启二进制日志后,参数log_bin_trust_function_creators就会生效,限制存储函数的创建、修改、调用。
    如何解决这个问题呢?
    1)如果数据库没有使用主从复制,那么就可以将参数log_bin_trust_function_creators设置为1。

      mysql> set @@global.log_bin_trust_function_creators = 1;
    

    这个动态设置的方式会在服务重启后失效,所以我们还必须在my.cnf中设置,加上log_bin_trust_function_creators=1,这样就会永久生效。
    2)明确指明函数的类型,如果我们开启了二进制日志, 那么我们就必须为我们的function指定一个参数。
    其中下面几种参数类型里面,只有 DETERMINISTIC, NO SQL 和 READS SQL DATA 被支持。
    这样一来相当于明确的告知MySQL服务器这个函数不会修改数据。

      ① DETERMINISTIC 不确定的
      ② NO SQL 没有SQl语句,当然也不会修改数据
      ③ READS SQL DATA 只是读取数据,当然也不会修改数据
      ④ MODIFIES SQL DATA 要修改数据
      ⑤ CONTAINS SQL 包含了SQL语句
      mysql> delimiter $$
      mysql> create function get_total() returns int reads sql data
            -> begin
            -> declare total int default 0;
            -> select count(*) into total from students;
            -> return total;
            -> end $$
      Query OK, 0 rows affected (0.08 sec)
    
      mysql> delimiter ;
      mysql> select get_total();
      +-------------+
      | get_total() |
      +-------------+
      |           7 |
      +-------------+
      1 row in set (0.09 sec)
    

    六、存储函数使用示例

      例1:创建存储函数,获取所有学生的总成绩
      mysql> delimiter $$
      mysql> create function get_students_totalScore() returns int reads sql data
            -> begin
            -> declare totalScore int default 0;
            ->  select sum(ifnull(t.总成绩,0)) into totalScore from students st left join (select s.student_id,sum(s.score) 总成绩 from subject su left join score s on su.id=s.subject_id group by s.student_id order by 总成绩 desc) t on st.id=t.student_id;
            ->  return totalScore;
            -> end $$
      Query OK, 0 rows affected (0.00 sec)
    
      mysql> delimiter ;
      mysql> select get_students_totalScore();
      +---------------------------+
      | get_students_totalScore() |
      +---------------------------+
      |                       576 |
      +---------------------------+
      1 row in set (0.04 sec)
    
      例2:创建存储函数根据传入的学生姓名,获取该学生的总成绩
      
      mysql> delimiter $$
      mysql> create function get_totalScore(name varchar(20)) returns int reads sql data
            -> begin
            -> declare totalScore int default 0;
            -> select ifnull(t.总成绩,0) into totalScore from students st left join (select s.student_id,sum(s.score) 总成绩 from subject su left join score s on su.id=s.subject_id group by s.student_id order by 总成绩 desc) t on st.id=t.student_id where st.name=name;
            -> return totalScore;
            -> end $$
      Query OK, 0 rows affected (0.06 sec)
    
      mysql> delimiter ;
      mysql> select get_totalScore('李四');
      +--------------------------+
      | get_totalScore('李四')   |
      +--------------------------+
      |                      268 |
      +--------------------------+
      1 row in set (0.06 sec)
    

    七、查看存储函数

      语法:show create function 函数名
      
      mysql> show create function get_totalScoreG;
      *************************** 1. row ***************************
            Function: get_totalScore
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
     Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION `get_totalScore`(name varchar(20)) RETURNS int
                      READS SQL DATA
                        begin
                              declare totalScore int default 0;
                              select ifnull(t.总成绩,0) into totalScore from students st left join (select s.student_id,sum(s.score) 总成绩 from subject su left join score s on su.id=s.subject_id group by s.student_id order by 总成绩 desc) t on st.id=t.student_id where st.name=name;
                              return totalScore;
                        end
      character_set_client: utf8mb4
      collation_connection: utf8mb4_0900_ai_ci
        Database Collation: utf8mb4_unicode_ci
      1 row in set (0.00 sec)
    

    八、删除存储函数

      语法:drop function 函数名
  • 相关阅读:
    BigDecimal
    android sdk manager 无法更新,解决连不上dl.google.com的问题
    程序卡在 while(SPI_I2S_GetFlagStatus(W5500_SPI, SPI_I2S_FLAG_TXE) == RESET) 处
    获取本设备IP地址
    Xamarin Android 监听音量键(下)
    xamarin Android 监听音量键(上)
    最大子序列和
    2.找出单独出现的数字
    编程题常见输入格式处理方法
    二进制比较:破解 LuaJIT 加密脚本的一种新思路。直接修改,无需反编译
  • 原文地址:https://www.cnblogs.com/huige185/p/14074414.html
Copyright © 2011-2022 走看看