Chinaunix首页 | 论坛 | 博客
  • 博客访问: 437675
  • 博文数量: 121
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 540
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-16 16:28
文章分类

全部博文(121)

文章存档

2021年(3)

2018年(1)

2017年(5)

2016年(9)

2015年(23)

2014年(80)

我的朋友

分类: Mysql/postgreSQL

2015-10-14 17:20:22

原文地址:mysql自定义函数示例 作者:digdeep126

oracle数据库向mysql数据库迁移时,遇到了一个oracle函数: instr(str, '|', pos), 在字符串str中pos的位置开始,查找字符'|',如果存在,则返回其位置。而mysql中有函数instr只有两个参数:instr(str, substr)。于是自动动手写了个函数来代替:

点击(此处)折叠或打开

  1. DELIMITER $$
  2. CREATE FUNCTION myinstr(str VARCHAR(255), str2 VARCHAR(255), pos INT)
  3. RETURNS INT NO SQL
  4. BEGIN
  5.     DECLARE newstr VARCHAR(255);
  6.     DECLARE j INT;
  7.     DECLARE r INT;    
  8.     
  9.     IF(pos >= 1 && pos <= LENGTH(str)) THEN        -- 开始查找的位置必须是:[1, length(str)]
  10.         SET newstr = SUBSTRING(str, pos);
  11.         SET j = INSTR(newstr, str2);
  12.     
  13.         IF(j <= 0) THEN        -- 没有查找到str2
  14.             SET r = 0;
  15.         ELSE
  16.             SET r = pos - 1 + j;
  17.         END IF;
  18.     ELSE
  19.         SET r = 0;
  20.     END IF;
  21.     
  22.     RETURN r;
  23. END
  24. $$
测试结果:

点击(此处)折叠或打开

  1. mysql> select myinstr('aaa|bbb', '|', 0);
  2. +----------------------------+
  3. | myinstr('aaa|bbb', '|', 0) |
  4. +----------------------------+
  5. | 0 |
  6. +----------------------------+
  7. 1 row in set (0.00 sec)

  8. mysql> select myinstr('aaa|bbb', '|', 1);
  9. +----------------------------+
  10. | myinstr('aaa|bbb', '|', 1) |
  11. +----------------------------+
  12. | 4 |
  13. +----------------------------+
  14. 1 row in set (0.00 sec)

  15. mysql> select myinstr('aaa|bbb', '|', 2);
  16. +----------------------------+
  17. | myinstr('aaa|bbb', '|', 2) |
  18. +----------------------------+
  19. | 4 |
  20. +----------------------------+
  21. 1 row in set (0.00 sec)

  22. mysql> select myinstr('aaa|bbb', '|', 3);
  23. +----------------------------+
  24. | myinstr('aaa|bbb', '|', 3) |
  25. +----------------------------+
  26. | 4 |
  27. +----------------------------+
  28. 1 row in set (0.00 sec)

  29. mysql> select myinstr('aaa|bbb', '|', 4);
  30. +----------------------------+
  31. | myinstr('aaa|bbb', '|', 4) |
  32. +----------------------------+
  33. | 4 |
  34. +----------------------------+
  35. 1 row in set (0.01 sec)

  36. mysql> select myinstr('aaa|bbb', '|', 5);
  37. +----------------------------+
  38. | myinstr('aaa|bbb', '|', 5) |
  39. +----------------------------+
  40. | 0 |
  41. +----------------------------+
  42. 1 row in set (0.00 sec)

  43. mysql> select myinstr('aaa|bbb', '|', 9);
  44. +----------------------------+
  45. | myinstr('aaa|bbb', '|', 9) |
  46. +----------------------------+
  47. | 0 |
  48. +----------------------------+
在创建函数时,如果返回类型说明:RETURNS INT NO SQL 的后面没有带NO SQL时,会报下面的错误:
错误代码: 1418
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)
产生该错误的原因如下:
因为我们开启了日志 bin_log,那么如果我们创建的函数在执行时,就涉及到在master和slave上执行的结果是否一样的问题,
也就是函数是否是确定性的(DETERMINISTIC),是否是可重复的,或者是否改变数据库的数据。不然会导致master和
slave两者的数据不一致,所以mysql强制要求:
在master上,除非子程序被声明为确定性的或者不更改数据库中的数据,否则创建或者替换子程序将被拒绝。
这意味着当创建一个子程序的时候,必须要么声明它是确定性的,要么它不改变数据。

所以解决方法有两种:
1)声明我们创建的函数是确定的
    这里要说明的是:使用NOW() 函数(或它的同义)或者RAND() 函数不会使一个子程序变成非确定性的。
    对NOW()而言,二进制日志包括时间戳并会被正确的执行。RAND()只要在一个子程序内被调用一次也可以被正确的复制。
    所以,可以认为时间戳和随机数种子是子程序的确定性输入,它们在主服务器和从服务器上是一样的。
2)声明函数是否改变数据库中的数据
    CONTAINS SQL, NO SQL, READS SQL DATA, MODIFIES SQL用来指出子程序是读还是写数据的。
    无论NO SQL还是READS SQL DATA都指出,子程序没有改变数据,但是必须明确地指定其中一个。

所以该错误的解决方法有如下几种:
1)RETURNS INT NO SQL :明确说明,我们创建的函数中不包含sql语句,所以肯定不会修改数据库中的数据;
2)RETURNS INT READS SQL DATA :说明我们的函数仅仅只是读取数据库,不会修改数据库;
3)RETURNS INT DETERMINISTIC:明确说明,我们创建的函数是确定的。

注:后来发现其实mysql中的函数:locate(substr, str, pos) 正好可以实现oracle中instr函数的功能,只是需要调换一下第一个和第二个参数的位置,所以其实没有必要自己定义一个函数了。

阅读(790) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~