MySQL 自定义函数.txt

=====================MySQL基础~~编程语法============================
常量
1.数值
  字符串:单引号或者双引号括起来。包括普通字符串或者日期格式的字符串。
  布尔值:false(FALSE)对应数字值为0、true(TRUE)对应数字值为1。
     NULL:可以参考http://www.cnblogs.com/-beyond/p/8554483.html


变量
2.定义用户变量

  mysql中变量分为用户变量和系统变量。

  用户变量要先定义和初始化赋值,否则变量的值为NULL。

  用户变量只在本次连接阶段有效,其他用户的连接不能使用另外一个用户定义的变量,并且当连接释放后,变量就会销毁。

  声明变量格式:set @key = value,可以一次性声明多个。

  如果变量名中有特殊符号,那么可以用引号将变量名括起来,比如 set @'abc def' = 123;


3. 访问用户变量
  select @name;

4. 系统变量

系统变量是以2个@@开头。
mysql> select @@version;

5. 获得系统变量列表  

mysql> show variables;
mysql> show variables like '%test%';

6. 算数运算符

+ - * / %  
+和-还可以用来计算日期; 

mysql> select now(),now() + interval 22 day;
+---------------------+-------------------------+
| now()               | now() + interval 22 day |
+---------------------+-------------------------+
| 2018-06-19 22:55:02 | 2018-07-11 22:55:02     |
+---------------------+-------------------------+
1 row in set (0.00 sec)


7. 在mysql里面,判断等于只用一个等号=,不像其他编程语言一样使用双等或者三等。判断不等使用!=和<>。
其他比较运算符和其他编程语言一样使用。


8. 和其他语言一样。注意or比and的优先级低,所以在where子句中进行判断时,为了保证准确性,尽量使用()保证顺序。



9.选择判断
  mysql的选择判断一般是使用case,格式如下:
case
    when 条件1 then 表达式1
    when 条件2 then 表达式2
    else 表达式n
end
  示例:
mysql> select id,name,
    -> case
    ->     when price>10 then "expensive"
    ->     when price>0 then "cheap"
    ->     else "free"
    -> end as level
    -> from cate;


10. 循环结构

delimiter $$
create procedure test_while()
begin
    declare sum int default 0;
    declare t int default 5;
    while t>0 do
        set sum=sum+1;
        set t=t-1;
    end while;
    select sum;
end
$$
delimiter ;


11. repeat

delimiter $$
create procedure _repeat()
begin
    declare a int default 10;
    repeat
    set a=a-1;
    until a<5
    end repeat;
    select a;
end
$$
delimiter ;


12. loop

delimiter $$
create procedure test_loop()
begin
    declare t int default 0;
    label:loop
        set t=t+1;
        if t>10 then leave label;
    end if;
    end loop label;
    select t;
end
$$
delimiter ;





一、基本语法

delimiter 自定义符号  -- 如果函数体只有一条语句, begin和end可以省略, 同时delimiter也可以省略

create function 函数名(形参列表) returns 返回类型  -- 注意是retruns

begin

  函数体    -- 函数内定义的变量如:set @x = 1; 变量x为全局变量,在函数外面也可以使用

  返回值

end

自定义符号

delimiter ;


二、示例
delimiter $$
CREATE FUNCTION hc(a int,b int) RETURNS INT
BEGIN
    RETURN a + b;
END
$$
delimiter ;


三、查看函数
  1. show function status [like 'pattern'];  -- 查看所有自定义函数, 自定义函数只能在本数据库使用。

  2. show create function 函数名;  -- 查看函数创建语句

四、删除函数

  drop function 函数名;

五、综合应用

1. 使用全局变量
    
delimiter $$
CREATE FUNCTION my_sum(x int) RETURNS INT
BEGIN
    set @i = 1;
    set @sum = 0;
    while @i <= x do
        set @sum = @sum + @i;
        set @i = @i + 1;
    end while;
    RETURN @sum;
end
$$
delimiter ;


SELECT my_sum(100);


2. 使用局部变量

delimiter $$
CREATE FUNCTION my_sum2(x int) RETURNS INT
BEGIN
    DECLARE i INT DEFAULT 1;
    DECLARE sum INT DEFAULT 0;
    sumwhile:WHILE i <= x do
        IF i % 5 = 0 then
            SET i = i + 1;
            ITERATE sumwhile;  --退出当前循环iterate 相当于 continue
        END IF;
        SET sum = sum + i;
        set i = i + 1;
    END WHILE;  --退出整个循环leave 相当于break
    RETURN sum;
END
$$
delimiter ;

SELECT my_sum2(10);


#MySQL存储过程中declare和set定义变量的区别
1、declare定义的变量类似java类中的局部变量,仅在类中生效。即只在存储过程中的begin和end之间生效。
 
2、@set定义的变量,叫做会话变量,也叫用户定义变量,在整个会话中都起作用(比如某个应用的一个连接过程中),即这个变量可以在被调用的存储过程或者代码之间共享数据。如何理解呢?可以看下面这个简单例子,很好理解。

(1)先执行下面脚本,创建一个存储过程,分别有declare形式的变量和@set形式的变量
DROP PROCEDURE IF EXISTS temp;
DELIMITER //
CREATE PROCEDURE temp()
BEGIN  
    DECLARE a INT DEFAULT 1;   
    SET a=a+1;  
    SET @b=@b+1;  
    SELECT a,@b;
END
//
DELIMITER ;

(2)接着为b变量初始化。
 
SET @b=1;

(3)然后重复调用这个存储过程。
 
CALL temp();

declare定义的类似是局部变量,@set定义的类似全局变量。



===================MySQL (Unix 时间戳、日期)转换函数===================

unix_timestamp(),
unix_timestamp(date),
from_unixtime(unix_timestamp),
from_unixtime(unix_timestamp,format)

下面是示例:
select unix_timestamp(); -- 1218290027
select unix_timestamp('2008-08-08'); -- 1218124800
select unix_timestamp('2008-08-08 12:30:00'); -- 1218169800

select from_unixtime(1218290027); -- '2008-08-09 21:53:47'
select from_unixtime(1218124800); -- '2008-08-08 00:00:00'
select from_unixtime(1218169800); -- '2008-08-08 12:30:00'

select from_unixtime(1218169800, '%Y %D %M %h:%i:%s %x'); -- '2008 8th August 12:30:00 2008'




删除函数我们可以使用 DROP FUNCTION IF EXISTS function_name;

修改函数ALTER FUNCTION  function_name  函数选项


1.IF语句
语法:
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF

实例:
IF age>20 THEN SET @count1=@count1+1;  
ELSEIF age=20 THEN SET @count2=@count2+1;  
ELSE SET @count3=@count3+1;  
END IF;

2.CASE语句
语法:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE

CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE

实例:
CASE age
WHEN 20 THEN SET @count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE ;

CASE
WHEN age=20 THEN SET @count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE ;


3. WHILE语句

语法:
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]



实例:
WHILE @count<100 DO
SET @count=@count+1;
END WHILE ;



3. ITERATE语句
ITERATE语句也是用来跳出循环的语句


4. REPEAT语句是有条件控制的循环语句。


5. LEAVE语句主要用于跳出循环控制。

6. LOOP语句可以使某些特定的语句重复执行,实现一个简单的循环。

语法:
[begin_label:] LOOP
statement_list
END LOOP [end_label]

实例:
add_num: LOOP  
SET @count=@count+1;  
END LOOP add_num ;



===================================存储过程==============================
https://www.cnblogs.com/mark-chan/p/5384139.html

1. MySQL存储过程的创建
语法:
CREATE PROCEDURE  过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...] 过程体

“DELIMITER //”声明当前段分隔符

IN:参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
OUT:该值可在存储过程内部被改变,并可返回
INOUT:调用时指定,并且可被改变和返回

过程体:
过程体的开始与结束使用BEGIN与END进行标识。


#在MySQL客户端使用用户变量
SELECT 'Hello World' into @x;
SELECT @x;
Hello World

SET @y='Goodbye Cruel World';
SELECT @y;
Goodbye Cruel World

SET @z=1+2+3;
SELECT @z;
6

#在存储过程中使用用户变量
CREATE PROCEDURE GreetWorld() SELECT CONCAT(@greeting,' World');
SET @greeting='Hello';
CALL GreetWorld();
Hello World

#在存储过程间传递全局范围的用户变量

CREATE PROCEDURE p1() SET @last_proc='p1';
CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_proc);
CALL p1();
CALL p2();
Last procedure was p1



#MySQL存储过程的查询
#查询存储过程
SELECT name FROM mysql.proc WHERE db='xy7_s9';
SELECT routine_name FROM information_schema.routines WHERE routine_schema='xy7_s9';
SHOW PROCEDURE STATUS WHERE db='xy7_s9';

#查看存储过程详细信息
SHOW CREATE PROCEDURE 数据库.存储过程名;

#MySQL存储过程的修改
ALTER PROCEDURE 更改用CREATE PROCEDURE 建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。

ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
characteristic:
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
sp_name参数表示存储过程或函数的名称;
characteristic参数指定存储函数的特性。
CONTAINS SQL表示子程序包含SQL语句,但不包含读或写数据的语句;
NO SQL表示子程序中不包含SQL语句;
READS SQL DATA表示子程序中包含读数据的语句;
MODIFIES SQL DATA表示子程序中包含写数据的语句。
SQL SECURITY { DEFINER | INVOKER }指明谁有权限来执行,DEFINER表示只有定义者自己才能够执行;INVOKER表示调用者可以执行。
COMMENT 'string'是注释信息。
实例:

#将读写权限改为MODIFIES SQL DATA,并指明调用者可以执行。
ALTER  PROCEDURE  num_from_employee
  MODIFIES SQL DATA
  SQL SECURITY INVOKER ;
#将读写权限改为READS SQL DATA,并加上注释信息'FIND NAME'。
ALTER  PROCEDURE  name_from_employee
  READS SQL DATA
  COMMENT 'FIND NAME' ;

#MySQL存储过程的删除
DROP PROCEDURE [过程1[,过程2…]]
从MySQL的表格中删除一个或多个存储过程。


#MySQL存储过程的控制语句

变量作用域

内部变量在其作用域范围内享有更高的优先权,当执行到end时,内部变量消失,不再可见了,在存储
过程外再也找不到这个内部变量,但是可以通过out参数或者将其值指派给会话变量来保存其值。

#变量作用域
DELIMITER //
  CREATE PROCEDURE proc()
    BEGIN
      DECLARE x1 VARCHAR(5) DEFAULT 'outer';
        BEGIN
          DECLARE x1 VARCHAR(5) DEFAULT 'inner';
          SELECT x1;
        END;
      SELECT x1;
    END;
    //
DELIMITER ;
#调用
CALL proc();
执行结果:
image
image
 
条件语句

IF-THEN-ELSE语句

#条件语句IF-THEN-ELSE
DROP PROCEDURE IF EXISTS proc3;
DELIMITER //
CREATE PROCEDURE proc3(IN parameter int)
  BEGIN
    DECLARE var int;
    SET var=parameter+1;
    IF var=0 THEN
      INSERT INTO t VALUES (17);
    END IF ;
    IF parameter=0 THEN
      UPDATE t SET s1=s1+1;
    ELSE
      UPDATE t SET s1=s1+2;
    END IF ;
  END ;
  //
DELIMITER ;
CASE-WHEN-THEN-ELSE语句

#CASE-WHEN-THEN-ELSE语句
DELIMITER //
  CREATE PROCEDURE proc4 (IN parameter INT)
    BEGIN
      DECLARE var INT;
      SET var=parameter+1;
      CASE var
        WHEN 0 THEN
          INSERT INTO t VALUES (17);
        WHEN 1 THEN
          INSERT INTO t VALUES (18);
        ELSE
          INSERT INTO t VALUES (19);
      END CASE ;
    END ;
  //
DELIMITER ;
 
循环语句
WHILE-DO…END-WHILE
DELIMITER //
  CREATE PROCEDURE proc5()
    BEGIN
      DECLARE var INT;
      SET var=0;
      WHILE var<6 DO
        INSERT INTO t VALUES (var);
        SET var=var+1;
      END WHILE ;
    END;
  //
DELIMITER ;
 
REPEAT...END REPEAT
此语句的特点是执行操作后检查结果
DELIMITER //
  CREATE PROCEDURE proc6 ()
    BEGIN
      DECLARE v INT;
      SET v=0;
      REPEAT
        INSERT INTO t VALUES(v);
        SET v=v+1;
        UNTIL v>=5
      END REPEAT;
    END;
  //
DELIMITER ;
 
LOOP...END LOOP
DELIMITER //
  CREATE PROCEDURE proc7 ()
    BEGIN
      DECLARE v INT;
      SET v=0;
      LOOP_LABLE:LOOP
        INSERT INTO t VALUES(v);
        SET v=v+1;
        IF v >=5 THEN
          LEAVE LOOP_LABLE;
        END IF;
      END LOOP;
    END;
  //
DELIMITER ;
 
LABLES标号
标号可以用在begin repeat while 或者loop 语句前,语句标号只能在合法的语句前面使用。可以跳出循环,使运行指令达到复合语句的最后一步。

ITERATE迭代

通过引用复合语句的标号,来从新开始复合语句

#ITERATE
DELIMITER //
  CREATE PROCEDURE proc8()
  BEGIN
    DECLARE v INT;
    SET v=0;
    LOOP_LABLE:LOOP
      IF v=3 THEN
        SET v=v+1;
        ITERATE LOOP_LABLE;
      END IF;
      INSERT INTO t VALUES(v);
      SET v=v+1;
      IF v>=5 THEN
        LEAVE LOOP_LABLE;
      END IF;
    END LOOP;
  END;
  //
DELIMITER ;




#MySQL存储过程的基本函数
字符串类
CHARSET(str) //返回字串字符集
CONCAT (string2 [,... ]) //连接字串
INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0
LCASE (string2 ) //转换成小写
LEFT (string2 ,length ) //从string2中的左边起取length个字符
LENGTH (string ) //string长度
LOAD_FILE (file_name ) //从文件读取内容
LOCATE (substring , string [,start_position ] ) 同INSTR,但可指定开始位置
LPAD (string2 ,length ,pad ) //重复用pad加在string开头,直到字串长度为length
LTRIM (string2 ) //去除前端空格
REPEAT (string2 ,count ) //重复count次
REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str
RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length
RTRIM (string2 ) //去除后端空格
STRCMP (string1 ,string2 ) //逐字符比较两字串大小,
SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符,
注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1
TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符
UCASE (string2 ) //转换成大写
RIGHT(string2,length) //取string2最后length个字符
SPACE(count) //生成count个空格


数学类

ABS (number2 ) //绝对值
BIN (decimal_number ) //十进制转二进制
CEILING (number2 ) //向上取整
CONV(number2,from_base,to_base) //进制转换
FLOOR (number2 ) //向下取整
FORMAT (number,decimal_places ) //保留小数位数
HEX (DecimalNumber ) //转十六进制
注:HEX()中可传入字符串,则返回其ASC-11码,如HEX('DEF')返回4142143
也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19
LEAST (number , number2 [,..]) //求最小值
MOD (numerator ,denominator ) //求余
POWER (number ,power ) //求指数
RAND([seed]) //随机数
ROUND (number [,decimals ]) //四舍五入,decimals为小数位数] 注:返回类型并非均为整数,
SIGN (number2 ) // 正数返回1,负数返回-1

日期时间类
ADDTIME (date2 ,time_interval ) //将time_interval加到date2
CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区
CURRENT_DATE ( ) //当前日期
CURRENT_TIME ( ) //当前时间
CURRENT_TIMESTAMP ( ) //当前时间戳
DATE (datetime ) //返回datetime的日期部分
DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间
DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime
DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间
DATEDIFF (date1 ,date2 ) //两个日期差
DAY (date ) //返回日期的天
DAYNAME (date ) //英文星期
DAYOFWEEK (date ) //星期(1-7) ,1为星期天
DAYOFYEAR (date ) //一年中的第几天
EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分
MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串
MAKETIME (hour ,minute ,second ) //生成时间串
MONTHNAME (date ) //英文月份名
NOW ( ) //当前时间
SEC_TO_TIME (seconds ) //秒数转成时间
STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示
TIMEDIFF (datetime1 ,datetime2 ) //两个时间差
TIME_TO_SEC (time ) //时间转秒数]
WEEK (date_time [,start_of_week ]) //第几周
YEAR (datetime ) //年份
DAYOFMONTH(datetime) //月的第几天
HOUR(datetime) //小时
LAST_DAY(date) //date的月的最后日期
MICROSECOND(datetime) //微秒
MONTH(datetime) //月
MINUTE(datetime) //分返回符号,正负或0
SQRT(number2) //开平方
 

===================================存储函数===================================

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

===================================触发器===================================

after触发器—是在记录操纵之后触发,是先完成数据的增删改,再触发,触发的语句晚于监视的增删改操作,无法影响前面的增删改动作

before触发器—是在记录操纵之前触发,是先完成触发,再增删改,触发的语句先于监视的增删改,我们就有机会判断,修改即将发生的操作,
如:我们在触发之前需要判断new值和old值的大小或关系,如果满足要求就触发,不通过就修改再触发;如:表之间定义的有外键,在删除主键时,
必须要先删除外键表,这时就有先后之分,这里before相当于设置了断点,我们可以处理删除外键。

对于INSERT语句, 只有NEW是合法的;

对于DELETE语句,只有OLD才合法;

对于UPDATE语句,NEW、OLD可以同时使用。


创建触发器的语法如下:
CREATE TRIGGER trigger_name trigger_time trigger_event ON tb_name FOR EACH ROW trigger_stmt

CREATE TRIGGER 触发器名 BEFORE|AFTER 触发事件
ON 表名 FOR EACH ROW
BEGIN
    执行语句列表
END

trigger_name:触发器的名称
tirgger_time:触发时机,为BEFORE或者AFTER
trigger_event:触发事件,为INSERT、DELETE或者UPDATE
tb_name:表示建立触发器的表明,就是在哪张表上建立触发器
trigger_stmt:触发器的程序体,可以是一条SQL语句或者是用BEGIN和END包含的多条语句
所以可以说MySQL创建以下六种触发器:
BEFORE INSERT,BEFORE DELETE,BEFORE UPDATE
AFTER INSERT,AFTER DELETE,AFTER UPDATE

BEFORE和AFTER参数指定了触发执行的时间,在事件之前或是之后

FOR EACH ROW表示任何一条记录上的操作满足触发事件都会触发该触发器


触发类型             激活触发器的语句
INSERT                    INSERT,LOAD DATE,REPLACE
UPDATE                     UPDATE
DELETE                     DELETE,REPLACE
#load data语句是将文件的内容插入到表中,相当于是insert语句,而replace语句在一般的情况下和insert差不多,但是如果表中存在primary 或者unique索引的时候,如果插入的数据和原来的primary key或者unique相同的时候,会删除原来的数据,然后增加一条新的数据,所以有的时候执行一条replace语句相当于执行了一条delete和insert语句。

触发类型        NEW和OLD的使用
INSERT            NEW 表示将要或者已经新增的数据
UPDATE             OLD 用来表示将要或者已经被删除的语句,NEW将要或者已经修改的数据
DELETE             OLD 表示将要或者已经被删除的数据

 delimiter $$
 CREATE TRIGGER upd_check BEFORE UPDATE ON account
 FOR EACH ROW
 BEGIN
   IF NEW.amount < 0 THEN
     SET NEW.amount = 0;
   ELSEIF NEW.amount > 100 THEN
     SET NEW.amount = 100;
   END IF;
 END $$
 delimiter ;


二、查看触发器

1、SHOW TRIGGERS语句查看触发器信息
mysql> SHOW TRIGGERSG;

结果,显示所有触发器的基本信息;无法查询指定的触发器。

2、在information_schema.triggers表中查看触发器信息
mysql> SELECT * FROM information_schema.triggersG

show create trigger trigger_name;

结果,显示所有触发器的详细信息;同时,该方法可以查询制定触发器的详细信息。
mysql> select * from information_schema.triggers where trigger_name='upd_check'G;
Tips:
所有触发器信息都存储在information_schema数据库下的triggers表中,可以使用SELECT语句查询,如果触发器信息过多,最好通过TRIGGER_NAME字段指定查询。

三、删除触发器

DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
删除触发器之后最好使用上面的方法查看一遍;同时,也可以使用database.trig来指定某个数据库中的触发器。
Tips:
如果不需要某个触发器时一定要将这个触发器删除,以免造成意外操作,这很关键。


===================================事件===================================