1 MySQL存儲過程和函數
過程和函數,它們被編譯后保存在數據庫中,稱為持久性存儲模塊(Persistent Stored Module,PSM),可以反復調用,運行速度快。
1.1 存儲過程
存儲過程是由過程化 SQL 語句書寫的過程,這個過程經編譯和優化后存儲在數據庫服務器中,因此稱它為存儲過程,使用時只要調用即可。
1.2 函數
這里指自定義函數,因為是用戶自己使用過程化 SQL 設計定義的。函數和存儲過程類似,都是持久性存儲模塊。函數的定義和存儲過程也類似,不同之處是函數必須指定返回類型。
MySQL 命令的執行過程:
存儲過程和函數可以簡化語法分析和編譯的過程,提高運行速度。
2 我的 MySQL 數據表
數據庫名:peng
表名: imooc_goddess
我的創建數據庫、建表和插入數據 SQL 語句:
-
/*
-
Navicat MySQL Data Transfer
-
-
Source Server : localhost_3306
-
Source Server Version : 50712
-
Source Host : localhost:3306
-
Source Database : peng
-
-
Target Server Type : MYSQL
-
Target Server Version : 50712
-
File Encoding : 65001
-
-
Date: 2016-10-04 20:53:44
-
*/
-
-
SET FOREIGN_KEY_CHECKS=0;
-
-
-- ----------------------------
-
-- Table structure for imooc_goddess
-
-- ----------------------------
-
DROP TABLE IF EXISTS `imooc_goddess`;
-
CREATE TABLE `imooc_goddess` (
-
`id` int(11) NOT NULL AUTO_INCREMENT,
-
`user_name` varchar(30) NOT NULL,
-
`sex` int(11) DEFAULT NULL,
-
`age` int(11) DEFAULT NULL,
-
`birthday` date DEFAULT NULL,
-
`email` varchar(30) DEFAULT NULL,
-
`mobile` varchar(11) DEFAULT NULL,
-
`create_user` varchar(30) DEFAULT NULL,
-
`create_date` date DEFAULT NULL,
-
`update_user` varchar(30) DEFAULT NULL,
-
`update_date` date DEFAULT NULL,
-
`isdel` int(11) DEFAULT NULL,
-
PRIMARY KEY (`id`)
-
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
-
-
-- ----------------------------
-
-- Records of imooc_goddess
-
-- ----------------------------
-
INSERT INTO `imooc_goddess` VALUES ('2', '小彭', null, '23', null, null, null, null, null, null, null, null);
-
INSERT INTO `imooc_goddess` VALUES ('6', '胖子', '0', '78', '2016-10-03', 'hongming@qq.com', '1211555599', 'admin', '2016-10-03', 'admin', '2016-10-03', '1');
-
INSERT INTO `imooc_goddess` VALUES ('7', '小溪', '0', '34', '2016-10-03', 'hongming@qq.com', '1211555599', 'admin', '2016-10-03', 'admin', '2016-10-03', '1');
-
INSERT INTO `imooc_goddess` VALUES ('9', '小霞', null, '23', '1990-09-09', 'xiaoxia@qq.com', '232445455', null, '2016-10-03', null, '2016-10-03', null);
-
INSERT INTO `imooc_goddess` VALUES ('10', 'hh', '1', '23', '1990-09-09', 'jkjfskf', '12323', 'Admin', '2016-10-03', 'admin', '2016-10-03', '1');
-
INSERT INTO `imooc_goddess` VALUES ('11', '平', '1', '23', '2998-04-09', 'jjjj@ww.com', '1323', 'admin', '2016-10-03', 'admin', '2016-10-03', '1');
-
INSERT INTO `imooc_goddess` VALUES ('12', '航母', '1', '23', '2333-09-09', 'jkksjkjf', '1232', 'admin', '2016-10-03', 'admin', '2016-10-03', '1');
-
INSERT INTO `imooc_goddess` VALUES ('13', '胖紙', '1', '23', '1991-09-09', 'jjijijij', '1323244', 'admin', '2016-10-03', 'admin', '2016-10-03', '1');
-
INSERT INTO `imooc_goddess` VALUES ('14', '校長', '1', '18', '1998-09-09', 'jkjijij@qq.com', '112323424', 'admin', '2016-10-03', 'admin', '2016-10-03', '1');
3 存儲過程的創建模板和調用模板
3.1 創建存儲過程模板
[ ] 表示可以省略
DEFINER 創建者,省略為默認用戶
sp_name 為過程名
sp_name 的參數(proc_paramenter) 可以無或多個
routine_body 過程體
proc_paramenter 類型 :IN 必須在調用存儲過程時指定
OUT 可以被存儲過程改變,並且可以返回
INOUT 調用時指定,並且可以被改變和返回
過程體如果是復合結構,則使用 BEGIN …END 語句。
-
CREATE PROCEDURE sp_name(proc_paramenter)
-
BEGIN
-
routine_body
-
END
3.2 調用存儲過程
-
1. CAll sp_name([parameter[,.....]])
-
-
2. CALL sp_name[()]
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
4 創建的存儲過程
存儲過程的創建的方式有很多,但是存儲過程的創建所需的代碼都大同小異。
- 在 電腦的 CMD 命令行創建
- 在 Navicat 表中函數模塊新建函數
- 在 Navicat 新建查詢(類似命令行方式)
其實 Navicat for mysql 只是一個圖形化界面而已,其中的原理都是一樣的,CMD 方式還是最經典的,最基礎的。
示例
當我們登錄到 MySQL 數據庫中時,可以通過SELECT VERSION();
,查詢到當前 MySQL 版本信息,如下
下面是把 SELECT VERSION();
作為一個過程體,寫入到新建的一個存儲過程中的三種方式。
方式一 CMD命令行方式
因為數據庫本來就有自己的函數,創建存儲過程名,盡量避免使用數據庫相關的名詞,可以使用比較獨特的名詞。
創建名為 v1 的存儲過程,存儲在數據庫中,創建其他存儲過程時,就不能使用 v1這個名字創建了,否則會發生重名錯誤。
方式二 Navicat 新建查詢
創建名為 v3 的存儲過程
方式三 Navicat 新建函數
創建名為 v2 的存儲過程
1.在函數上右擊新建函數。
2.選擇過程。
3.這個存儲過程沒有參數,不填寫,點完成。
4.在過程體中輸入SELECT VERSION();
,點擊保存,輸入過程名 v2 ,確認。
還是GIF圖來的快
當然,調用這 3 種存儲過程,都可以在 Navicat 新建查詢或 CMD 中通過
-
CALL v1();
-
CALL v2();
-
CALL v3();
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
來調用
4.1 創建不帶參數的存儲過程
在 CMD 中執行下面的語句。
4.2 創建帶有IN類型參數的存儲過程
DELIMITER 是MySQL的一個定界符,是告訴mysql解釋器,該段命令是否已經結束了,mysql可以執行了
但是,在復合結構中,sql 語句用“;”結尾,但是我們並沒有結束輸入命令,所以通過DELIMITER //
修改 默認為 “;”的定界符為”//”, 以后輸入 “//”代表命令輸入結束,mysql 可以執行了。DELIMITER ;
改回默認的定界符。
參數名不能和數據表名相同,上面例子的 p_id不能寫成 id。
不能更改已經保存的存儲過程的函數體,必須先刪除該存儲過程,再創建新的存儲過程。
4.3 創建帶有 IN和OUT類型參數的存儲過程
這是一個有輸入值和返回值的存儲過程。輸入要刪除的行號 p_id ,之后數據庫計算剩余行數 返回到 userNums 中。
1.要輸入的值為 p_id,返回的值為 userNums。
2.在過程體中輸入
-
DELETE FROM imooc_goddess WHERE id = p_id;
-
SELECT COUNT(id) FROM imooc_goddess INTO userNums;
- 1
- 2
- 1
- 2
- 1
- 2
3.點擊進入函數,點擊運行
結果:
-
時間: 00:00.08
-
-
Procedure executed successfully
-
受影響的行: 1
-
-
Parameters: IN `p_id` int,OUT `userNums` int
-
14,@nums
-
Return values: 14, 4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
1.在 CMD 命令行的寫法
-
DELIMITER //
-
CREATE PROCEDURE removeUserAndReturnUserNums(IN p_id INT UNSIGNED,OUT userNums INT UNSIGNED)
-
BEGIN
-
DELETE FROM imooc_goddess WHERE id = p_id;
-
SELECT COUNT(id) FROM imooc_goddess INTO userNums;
-
END
-
DELIMITER ;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
注意如果數據中含有 removeUserAndReturnUserNums 存儲過程,更改名稱,再創建新的存儲過程。
- 在 CMD 命令行調用
4.4 創建帶有多個OUT類型的存儲過程
輸入年齡,返回刪除的行數,和剩余行數。
SQL 語句
-
CREATE PROCEDURE removeUserByAgeAndReturnInfos(IN p_age SMALLINT UNSIGNED,OUT
-
deleteUsers SMALLINT UNSIGNED,OUT userCounts SMALLINT UNSIGNED)
-
BEGIN
-
DELETE FROM imooc_goddess WHERE age = p_age;
-
SELECT ROW_COUNT() INTO deleteUsers;
-
SELECT COUNT(id) FROM imooc_goddess INTO userCounts;
-
END
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
5 自定義函數
用戶自定義函數(user-defined function,UDP)是一種對MySQL 擴展的途徑,其用法與內置函數相同。
5.1 創建自定義函數模板
-
CREATE FUNCTION function_name
-
RETURNS
-
{STRING|INTEGER|REAL|DECIMAL}
-
routine_body
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
關於函數體
函數體由合法的SQL語句構成
函數體可以是簡單的SELECT或INSERT語句
函數體如果為復合結構則使用 BEGIN….END 語句
復合結構可以包含聲明,循環,控制結構
5.2 自定義函數的創建和調用
1 自定義不帶參數的函數
-
CREATE FUNCTION f1() RETURNS VARCHAR(30)
-
RETURN DATE_FORMAT(NOW(),'%Y年%m月%d日:%H時:%i分:%s秒');
- 1
- 2
- 1
- 2
- 1
- 2
SELECT f1();
- 1
- 1
- 1
在 Java 項目上調用函數(函數有返回值)時
CallableStatement cs = conn.prepareCall("{?= call f1()}");
- 1
- 1
- 1
2 自定義兩個參數的函數
輸入兩個值,計算其平均值。
-
CREATE FUNCTION f2(num1 SMALLINT UNSIGNED,num2 SMALLINT UNSIGNED)
-
RETURNS FLOAT(10,2) UNSIGNED
-
RETURN (num1+num2)/2;
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
3 創建具有復合機構函數體的函數
插入一條新數據,user_name,返回該行的id。
-
CREATE FUNCTION adduser(username VARCHAR(20))
-
RETURNS INT UNSIGNED
-
BEGIN
-
INSERT imooc_goddess(user_name) VALUES (username);
-
return LAST_INSERT_ID();
-
END
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
6 通過 Navicat 查看存儲過程和函數的創建語句
在 Navicat 中點開函數欄,選擇你要查看的函數,右擊選擇對象信息。
選擇DDL欄(數據定義語言)
-
CREATE DEFINER=`root`@`localhost` PROCEDURE `selectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
語句中的
DEFINER=`root`@`localhost`
- 1
- 1
- 1
是數據庫自己默認添加的。
復制數據定義語言創建過程時-發生錯誤
當我想直接復制數據定義語言,更改一個名稱創建另一個存儲過程時,總是創建不成功。
1、更改名稱(Error)
-
CREATE DEFINER=`root`@`localhost` PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
2、修改DEFINER(下面的語句都是不能成功創建)
-
CREATE DEFINER={'root`@`localhost`} PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
CREATE DEFINER={'root`@`%`} PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
CREATE DEFINER={root|localhost} PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
CREATE DEFINER={root} PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
CREATE DEFINER=root PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
CREATE DEFINER=`CURRENT_USER`() PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
CREATE DEFINER=CURRENT_USER PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
3、刪除DEFINER
刪除DEFINER,可以創建成功
-
CREATE PROCEDURE `myselectAll`()
-
BEGIN
-
SELECT * FROM imooc_goddess;
-
END
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
然而創建函數時卻可以帶 DEFINER
下面的語句可以創建成功
-
CREATE DEFINER=`root`@`localhost` FUNCTION `f2`(num1 SMALLINT UNSIGNED,num2 SMALLINT UNSIGNED) RETURNS float(10,2) unsigned
-
RETURN (num1+num2)/2
- 1
- 2
- 1
- 2
- 1
- 2
復制數據定義語言,創建存儲過程要刪除DEFINER。
7 存儲過程與自定義函數的區別
-
存儲過程實現的功能要復雜一些,而函數的的針對性更強
-
存儲的過程可以返回多個值,函數只能有一個返回值
-
存儲過程一般獨立的執行,而函數可以作為其他 SQL語句的組成部分來實現。
-
過程 通俗易懂的說法:它只是將其中的程序執行一遍
-
函數 通俗易懂的說法:它不但將其中的程序執行一遍,還返回一個值