MySOL自定義函數及存儲過程

先介紹下MySQL自帶的一些函數:
結構:sql --> 結果 #作用

以下都是運行結果:
字符串相關函數
select concat('zhou','yi');  --> zhouyi  #字符串拼接,可多參數
select concat_ws('&',zhou'','yi'); --> zhou&yi #指定分割符號進行字符串鏈接
# FOMRAT(N,D,locale); N對象,D小數位數,locale可選
select format(2019.011,1); --> 2019.0 #數字格式化
select lower('ZY'); --> zy # 轉小寫;upper 轉大寫
select replace('zhouyibaba','zhouyi',''); --> baba# 替換
SELECT left('chinese', 4); --> chin # 左截取; right(str, len)右截取;substring指定截取
select length('zhouyi'); --> 6 # 返回長度
select char_length("周毅"); --> 2 # 如果是length返回6
select ltrim('    space  A'); --> space  A #刪除前空格; rtrim刪除後空格;trim 刪除前後空格
select trim(both '?'from '??zY?zy??'); --> zY?zy
select trim(leading '?'from '??zY?zy??'); --> zY?zy??
select trim(trailing '?'from '??zY?zy??'); --> ??zY?zy
判斷子串:
select locate('ho','zhouyi');---> 2 #從字符串zhouyi中獲取ho的開始位置,0代表無


日期時間函數
select now(); --> 2019-12-03 09:11:53 #當前日期和時間
select curdate(); --> 2019-12-03 # 當前日期; curtime()當前時間
SELECT DATE_ADD(now(),INTERVAL 2 DAY); --> 2019-12-05 09:19:48 #向日期添加指定的時間間隔 時間間隔有很多
select DATE_FORMAT(NOW(),'%b %d %Y %h:%i %p'); --> Dec 03 2019 09:15 AM # 時間格式化

數值運算(用的叫少帶過)
div() 整數除法 mod() 取餘數 power() 冪運算 truncate() 數字截取 ceil() 進一取整 floor 舍1取整

以及基本的聚合函數:avg() count() max() min() sum()

1,自定義函數:

創建自定義函數語法格式如下:
CREATE FUNCTION <函數名> ( [ <參數1> <類型1> [ , <參數2> <類型2>] ] … )
RETURNS <類型>
<函數主體>

語法說明如下:
<函數名>:指定自定義函數的名稱。注意,自定義函數不能與存儲過程具有相同的名稱。
<參數><類型>:用於指定自定義函數的參數。這裏的參數只有名稱和類型,不能指定關鍵字 IN、OUT 和 INOUT。
RETURNS<類型>:用於聲明自定義函數返回值的數據類型。其中,<類型>用於指定返回值的數據類型。
<函數主體>:自定義函數的主體部分,也稱函數體。所有在存儲過程中使用的 SQL 語句在自定義函數中同樣適用,包括前面所介紹的局部變量、SET 語句、流程控制語句、遊標等。除此之外,自定義函數體還必須包含一個 RETURN<值> 語句,其中<值>用於指定自定義函數的返回值。
即是:

CREATE FUNCTION function_name
RETURNS
{STRING | INTEGER | REAL | DECIMAL}
Routine_body

刪除自定義函數語法如下:

DROP FUNCTION [ IF EXISTS ] <自定義函數名>

實際舉例:
1,無參數舉例:

mysql> create function getName()
    -> returns varchar(45)
    -> return 
    -> (select 'zhouyi');
Query OK, 0 rows affected (0.34 sec)

mysql> select getname();
+-----------+
| getname() |
+-----------+
| zhouyi    |
+-----------+
1 row in set (0.11 sec)

mysql> 

2,有參數舉例:

mysql> CREATE FUNCTION twoAvg(num1 int,num2 int)
    -> RETURNS FLOAT(10,2)
    -> RETURN (num1+num2)/2;
Query OK, 0 rows affected (0.00 sec)

mysql> select twoAvg(2,3);
+-------------+
| twoAvg(2,3) |
+-------------+
|        2.50 |
+-------------+
1 row in set (0.12 sec)

mysql> 

這裏遺留問題。字符串的操作,嘗試了好幾遍都失敗了。有空看到這一定要裏,一定要補充完整。

更進一步,帶複合結構的函數體。
注意:當使用 DELIMITER 命令時,應該避免使用反斜槓“\”字符,因爲反斜槓是 MySQL 的轉義字符。
定義語法:

DELIMITER //
CREATE FUNCTION function_name(parameter_nametype,[parameter_name type,...])
RETURNS {STRING|INTEGER|REAL}
BEGIN
//body
END
//      /* 此處的”//“爲告訴系統函數定義結束 */

當函數體內需要執行的是多條語句時,要使用BEGIN…END語句,複合結構可以包括聲明、循環、控制結構(包括IF語句、CASE語句、LOOP語句、LEAVE語句、ITERATE語句、REPEAT語句和WHILE);且當編寫函數體內容的時候,需要使用DELIMITER關鍵字將分隔符先修改爲別的,否則編寫語句的時候寫到’;’的時候會直接執行,導致函數編寫失敗。

另外還需要了解自定函數內常量和變量定義:
用戶變量:以”@”開始,形式爲”@變量名”。用戶變量跟mysql客戶端是綁定的,設置的變量,只對當前用戶使用的客戶端生效
語法:

set @name =;

全局變量:定義時,以如下兩種形式出現,set GLOBAL 變量名 或者 set @@global.變量名,對所有客戶端生效。只有具有super權限纔可以設置全局變量
語法:

set GLOBAL name =;

會話變量:只對連接的客戶端有效。
局部變量:作用範圍在begin到end語句塊之間。在該語句塊裏設置的變量。declare語句專門用於定義局部變量。set語句是設置不同類型的變量,包括會話變量和全局變量
局部變量:
變量定義的語法:

DECLARE var_name[,varname]...date_type [DEFAULT VALUE];

爲變量賦值的語法:

SET parameter_name = value[,parameter_name = value...]
SELECT INTO parameter_name

3,複雜一點的自定義函數。

  1. 自定義隨機生成姓名的自定義函數。
mysql> #自定義開始結束符
mysql> DELIMITER $$
mysql> drop function if exists createRandomName$$
Query OK, 0 rows affected (0.00 sec)

mysql> create function createRandomName()
    -> returns varchar(3)
    -> begin
    -> # 用來存可隨機姓 名  形如LMN
    -> declare ln varchar(500);
    -> declare mn varchar(500);
    -> declare nn varchar(500);
    -> # 用來存隨機ln mn nn的長度。char_length
    -> declare ln_le int;
    -> declare mn_le int;
    -> declare nn_le int;
    -> # 變量賦值
    -> set ln='ABCDEFGH';
    -> set mn='IJKLMN';
    -> set nn='OPQRYZST';
    -> set ln_le=char_length(ln);
    -> set mn_le=char_length(mn);
    -> set nn_le=char_length(nn);
    -> return (concat(substring(ln,ceil(rand()*ln_le),1),
    -> substring(mn,ceil(rand()*mn_le),1),substring(nn,ceil(rand()*nn_le),1)));
    -> end $$
Query OK, 0 rows affected (0.01 sec)

mysql> DELIMITER ;
mysql> select createRandomName();
+--------------------+
| createRandomName() |
+--------------------+
| EMR                |
+--------------------+
1 row in set (0.00 sec)

mysql> 


解釋:

#自定義開始結束符
DELIMITER $$
drop function if exists createRandomName$$
create function createRandomName()
returns varchar(3)
begin
# 申明局部變量,用來存可隨機姓 名  形如LMN
declare ln varchar(500);
declare mn varchar(500);
declare nn varchar(500);
# 用來存隨機ln mn nn的長度。char_length
declare ln_le int;
declare mn_le int;
declare nn_le int;
# 變量賦值 ,這裏由於本人創建數據庫時,未指定UTF-8,不能使用。
set ln='ABCDEFGH';
set mn='IJKLMN';
set nn='OPQRYZST';
set ln_le=char_length(ln);
set mn_le=char_length(mn);
set nn_le=char_length(nn);
return (concat(substring(ln,ceil(rand()*ln_le),1),
substring(mn,ceil(rand()*mn_le),1),substring(nn,ceil(rand()*nn_le),1)));
end $$
DELIMITER ;

進一步深入就必須瞭解控制結構,因爲這是學一個東西能實際運用的基礎。
IF語句語法:
IF…END IF爲一組

IF search_condition THEN statement_list 
   [ELSEIF search_condition THEN statement_list] ... 
   [ELSE statement_list] 
END IF

search_condition表示條件判斷語句;statement_list表示條件成立執行的語句。

CASE語句語法:

CASE...END CASE爲一組
CASE case_value 
     WHEN when_value THEN statement_list 
     [WHEN when_value THEN statement_list] ... 
     [ELSE statement_list] 
END CASE 

case_value表示條件判斷的變量;when_value表示變量的取值;
statement_list表示不同when_value值執行的語句。

loop語句語法:

[begin_label:] LOOP 
statement_list
#LEAVE語句 主要用於跳出整個循環控制
LEAVE begin_label 
END LOOP [end_label] 

ITERATE語句語法:
ITERATE語句是跳出本次循環,然後直接進入下一次循環。
ITERATE語句只可以出現在LOOP、REPEAT、WHILE語句內

ITERATE label

begin_label和end_label分別表示循環開始和結束的標誌,兩個標誌必須相同,而且都可以省略;
statement_list表示需要循環執行的語句。

while語句語法:

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

WHILE循環需要使用END WHILE來結束。
其中,search_condition參數表示循環執行的條件,滿足該條件時循環執行;

repeat語句語法:

[begin_label:] REPEAT 
statement_list 
UNTIL search_condition 
END REPEAT [end_label] 

簡單舉個栗子:
判斷員工優秀?

#自定義開始結束符
DELIMITER $$
drop function if exists getGreade$$
create function getGreade(grade int)
returns varchar(10)
begin
declare ret varchar(10);
CASE 
WHEN grade=1 THEN SET ret='優秀'; 
ELSE SET ret='非常優秀'; 
END CASE ; 
return ret;
end $$
DELIMITER ;
# 以;結束

單從邏輯而言,作爲程序員的你理解不難。以上你瞭解,但是這種東西實際中會需要很多問題,主要時sql報錯需要經驗。沒有相關經驗你基本看不出來,而且百度也沒有什麼效果,網上學習課程教的又很淺,我學習這部分花了很大的時間去調通各種代碼問題。且行且珍惜。

2,存儲過程
爲什麼我寫了自定義函數。其實我們可以發現這兩者有很多相似之處。他就是一種爲了方便快捷的一組具有特定功能的SQL語句集組成的可編程的、經編譯創建並保存在數據庫的函數。(**注:**不同的數據庫,語法上存在的差異)。
上面自定函數都可以用到這裏來。

存儲過程的語法:

CREATE
    #指定當前用戶
    [DEFINER = { user | CURRENT_USER }]
 PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body
( #上面的參數細化
proc_parameter:
   [ IN | OUT | INOUT ] param_name type

#上面指定數據庫引擎細化
characteristic:
    COMMENT 'string'
  | LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }

#上面主體細化
routine_body:
  Valid SQL routine statement )
  
[begin_label:] BEGIN
  [statement_list]   
END [end_label]

IN/OUT/INOUT 字面意思in只做輸入不可改變,out只做輸出可變,inout兩者都可萬能。
刪除及查看存儲過程:

#刪除
drop procedure sp_name;
#查看
show procedure status;/create procedure sp_name;

前期數據表準備:

mysql> create table `grade`(
    -> `id` int(11) not null auto_increment primary key,
    -> `stu_number` varchar(11) not null,
    -> `math` int(4) not null,
    -> `chinese` int(4) not null,
    -> `english` int(4) not null
    -> )engine=innodb default charset=utf8 comment='學生成績表';
Query OK, 0 rows affected (0.76 sec)

mysql> drop table if exists student;
Query OK, 0 rows affected, 1 warning (0.13 sec)

mysql> create table `student`(
    -> `id` int(11) not null auto_increment primary key,
    -> `stu_number` varchar(11) not null,
    -> `stu_name` varchar(12) not null,
    -> `class` int(4) not null
    -> )engine=innodb default charset=utf8 comment='學生信息表';
Query OK, 0 rows affected (0.15 sec)

mysql> show tables;                                                             +-----------------------------+
| Tables_in_activiti_database |
+-----------------------------+
| grade                       |
| student                     |
+-----------------------------+
2 rows in set (0.00 sec)

// sql+數據預置

#學生信息表
drop table if exists student;
create table `student`(
`id` int(11) not null auto_increment primary key,
`stu_number` varchar(11) not null,
`stu_name` varchar(12) not null,
`class` int(4) not null
)engine=innodb default charset=utf8 comment='學生信息表';

#學生成績表
drop table if exists grade;
create table `grade`(
`id` int(11) not null auto_increment primary key,
`stu_number` varchar(11) not null,
`math` int(4) not null,
`chinese` int(4) not null,
`english` int(4) not null,
`total` int(5) not null
)engine=innodb default charset=utf8 comment='學生成績表';

insert into student(stu_number,stu_name,class) values
('10000','張一',101),
('10001','張二',101),
('10002','張三',101),
('10003','張四',101),
('10004','張二',102),
('10005','張三',102),
('10006','張四',102);

insert into grade(stu_number,math,chinese,english,total) values
('10000',80,90,101,271),
('10001',82,70,101,253),
('10002',80,60,101,241),
('10003',85,10,101,196),
('10004',80,88,101,269),
('10005',87,77,101,265),
('10006',83,90,101,274);

1,創建一個存儲過程找到前全年級總分最高前三名。

drop procedure if exists getavgthree;
#不帶參數
create procedure getavgthree()
begin
select s.stu_name,s.class from student s left join grade g on s.stu_number=g.stu_number order by total desc limit 3;
end;

2,找到學號最大的學生,將學號存儲到輸出參數。

create procedure getMaxSIDByClass(IN classname int, out maxid varchar(11))
BEGIN
select MAX(stu_number) into maxid from student where class=classname;
END;

當然除了上述查詢,存儲過程更刪改查都是可以的,此外也可以使用存儲過程備份還原數據(簡單來說就是將一張表的數據複製到另一張表)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章