男女主網(wǎng)站上做的popo網(wǎng)站建設(shè)優(yōu)化
MySQL
- 一、觸發(fā)器
- 1、觸發(fā)器簡介
- 2、創(chuàng)建觸發(fā)器
- 3、一些常見示例
- 二、存儲(chǔ)過程
- 1、什么是存儲(chǔ)過程或者函數(shù)
- 2、優(yōu)點(diǎn)
- 3、存儲(chǔ)過程創(chuàng)建與調(diào)用
- 三、存儲(chǔ)函數(shù)
- 1、存儲(chǔ)函數(shù)創(chuàng)建和調(diào)用
- 2、修改存儲(chǔ)函數(shù)
- 3、刪除存儲(chǔ)函數(shù)
- 四、游標(biāo)
- 1、聲明游標(biāo)
- 2、打開游標(biāo)
- 3、使用游標(biāo)
- 4、關(guān)閉游標(biāo)
- 游標(biāo)案例
一、觸發(fā)器
1、觸發(fā)器簡介
觸發(fā)器(trigger)是一個(gè)特殊的存儲(chǔ)過程,它的執(zhí)行不是由程序調(diào)用,也不是手工啟動(dòng),而是由事件來觸發(fā),比如當(dāng)對一個(gè)表進(jìn)行操作( insert,delete, update)時(shí)就會(huì)激活它執(zhí)行。
觸發(fā)器經(jīng)常用于加強(qiáng)數(shù)據(jù)的完整性約束和業(yè)務(wù)規(guī)則等。例如,當(dāng)學(xué)生表中增加了一個(gè)學(xué)生的信息時(shí),學(xué)生的總數(shù)就應(yīng)該同時(shí)改變。因此可以針對學(xué)生表創(chuàng)建一個(gè)觸發(fā)器,每次增加一個(gè)學(xué)生記錄時(shí),就執(zhí)行一次學(xué)生總數(shù)的計(jì)算操作,從而保證學(xué)生總數(shù)與記錄數(shù)的一致性。
2、創(chuàng)建觸發(fā)器
語法結(jié)構(gòu):
CREATE TRIGGER 觸發(fā)器名稱 BEFORE|AFTER 觸發(fā)事件
ON 表名 FOR EACH ROW
BEGIN觸發(fā)器程序體;END
# 說明:<觸發(fā)器名稱> 最多64個(gè)字符,它和MySQL中其他對象的命名方式一樣{ BEFORE | AFTER } 觸發(fā)器時(shí)機(jī){ INSERT | UPDATE | DELETE } 觸發(fā)的事件ON <表名稱> 標(biāo)識(shí)建立觸發(fā)器的表名,即在哪張表上建立觸發(fā)器FOR EACH ROW 觸發(fā)器的執(zhí)行間隔:FOR EACH ROW子句通知觸發(fā)器 每隔一行執(zhí)行一次動(dòng)作,而不是對整個(gè)表執(zhí)行一次<觸發(fā)器程序體> 要觸發(fā)的SQL語句:可用順序,判斷,循環(huán)等語句實(shí)現(xiàn)一般程序需要的邏輯功能
3、一些常見示例
1、示例1:
-
- 創(chuàng)建表
mysql>create table student(id int unsigned auto_increment primary key not null,name varchar(50)
);
mysql>insert into student(name) values('jack');create table student_total(total int);insert into student_total values(1);
-
- 創(chuàng)建觸發(fā)器student_insert_trigger
mysql> delimiter $$
mysql> create trigger student_insert_trigger after inserton student for each rowBEGINupdate student_total set total=total+1;# 其他SQLEND$$
mysql> delimiter ;
查看觸發(fā)器
-
- 通過SHOW TRIGGERS語句查看
SHOW TRIGGERS\G
-
- 通過系統(tǒng)表triggers查看
USE information_schema
SELECT * FROM triggers\G
SELECT * FROM triggers WHERE TRIGGER_NAME='觸發(fā)器名稱'\G
刪除觸發(fā)器
通過DROP TRIGGERS語句刪除
sql> DROP TRIGGER 解發(fā)器名稱
2、示例2
- 1、創(chuàng)建表tab1
DROP TABLE IF EXISTS tab1;
CREATE TABLE tab1(id int primary key auto_increment,name varchar(50),sex enum('m','f'),age int
);
- 2、創(chuàng)建表tab2
DROP TABLE IF EXISTS tab2;
CREATE TABLE tab2(id int primary key auto_increment,name varchar(50),salary double(10,2)
);
觸發(fā)器tab1_after_delete_trigger
作用:tab1表刪除記錄后,自動(dòng)將tab2表中對應(yīng)記錄刪除
mysql> \d /
mysql> create trigger tab1_after_delete_trigger after delete on tab1 for each row begin delete from tab2 where name=old.name; end/
觸發(fā)器tab1_after_update_trigger
作用:當(dāng)tab1更新后,自動(dòng)更新tab2
mysql> \d $$
mysql> create trigger tab1_after_update_trigger after update on tab1 for each row begin update tab2 set name=new.name where name=old.name; end$$
觸發(fā)器tab1_after_insert_trigger
作用:當(dāng)tab1增加記錄后,自動(dòng)增加到tab2
mysql> \d /
mysql> create trigger tab1_after_insert_triggerafter insert on tab1 for each rowbegin insert into tab2 values(null, name, 5000); end/
二、存儲(chǔ)過程
1、什么是存儲(chǔ)過程或者函數(shù)
存儲(chǔ)過程和函數(shù)是事先經(jīng)過編譯并存儲(chǔ)在數(shù)據(jù)庫中的一段sql語句集合,調(diào)用存儲(chǔ)過程函數(shù)可以簡化應(yīng)用開發(fā)人員的很多工作,減少數(shù)據(jù)在數(shù)據(jù)庫和應(yīng)用服務(wù)器之間的傳輸,對于提高數(shù)據(jù)處理的效率是有好處的。
存儲(chǔ)過程和函數(shù)的區(qū)別:
- 函數(shù)必須有返回值,而存儲(chǔ)過程沒有。
- 存儲(chǔ)過程的參數(shù)可以是IN、OUT、INOUT類型,函數(shù)的參數(shù)只能是IN
2、優(yōu)點(diǎn)
- 存儲(chǔ)過程只在創(chuàng)建時(shí)進(jìn)行編譯;而SQL語句每執(zhí)行一次就編譯一次,所以使用存儲(chǔ)過程可以提高數(shù)據(jù)庫執(zhí)行速度
- 簡化復(fù)雜操作,結(jié)合事務(wù)一起封裝
- 復(fù)用性好
- 安全性高,可指定存儲(chǔ)過程的使用權(quán)
注意:并發(fā)量少的情況下,很少使用存儲(chǔ)過程。并發(fā)量高的情況下,為了提高效率,用存儲(chǔ)過程比較多。
3、存儲(chǔ)過程創(chuàng)建與調(diào)用
創(chuàng)建存儲(chǔ)過程語法 :
create procedure sp_name(參數(shù)列表)[特性...]過程體存儲(chǔ)過程的參數(shù)形式:[IN | OUT | INOUT]參數(shù)名 類型IN 輸入?yún)?shù)OUT 輸出參數(shù)INOUT 輸入輸出參數(shù)delimiter $$create procedure 過程名(參數(shù)列表)beginSQL語句end $$delimiter ;調(diào)用:call 存儲(chǔ)過程名(實(shí)參列表)
存儲(chǔ)過程三種參數(shù)類型:IN, OUT, INOUT:
===================NONE========================
mysql> \d $
mysql> create procedure p1()
begin
select count(*) from mysql.user;
end$
mysql> \d ;
mysql> call p1();
mysql> create table t1(
id int,
name varchar(50)
);
mysql> delimiter $$
mysql> create procedure autoinsert1()
begin
declare i int default 1; # int i = 1;
while(i<20000)do
insert into t1 values(i, md5(i));
set i=i+1;
end while;
end$$
mysql> delimiter ;
====================IN==========================
mysql> create procedure autoinsert2(IN a int)
BEGIN
declare i int default 1;
while(i<=a)do
insert into t1 values(i,md5(i));
set i=i+1;
end while;
END$$
mysql> call autoinsert2(10);
mysql> set @num=20;
mysql> select @num;
+------+
| @num |
+------+
| 20 |
+------+
mysql> call autoinsert2(@num);
====================OUT=======================
mysql> delimiter $$
mysql> CREATE PROCEDURE p2 (OUT param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM t1;
END$$
mysql> delimiter ;
mysql> select @a;
+------+
| @a |
+------+
| NULL |
+------+
mysql> CALL p2(@a);
mysql> SELECT @a;
+------+
| @a |
+------+
| 30 |
+------+
===================IN 和 OUT=====================
作用:統(tǒng)計(jì)指定部門的員工數(shù)
mysql> create procedure count_num(IN p1 varchar(50), OUT p2 int)
BEGIN
select count(*) into p2 from employee where post=p1;
END$$
mysql> \d ;
mysql> call count_num('hr',@a);
mysql>select @a;
作用:統(tǒng)計(jì)指定部門工資超過例如5000的總?cè)藬?shù)
mysql> create procedure count_num(IN p1 varchar(50), IN p2 float(10,2), OUT p3 int)
BEGIN
select count(*) into p3 from employee where post=p1 and salary>=p2;
END$$
mysql> \d ;
mysql> call count_num('hr',5000,@a);
====================INOUT======================
mysql> create procedure proce_param_inout(inout p1 int)
begin
if (p1 is not null) then
set p1=p1+1;
else
select 100 into p1;
end if;
end$$
mysql> \d ;
mysql> select @h;
+------+
| @h |
+------+
| NULL |
+------+
mysql> call proce_param_inout(@h);
mysql> select @h;
+------+
| @h |
+------+
| 100 |
+------+
mysql> call proce_param_inout(@h);
mysql> select @h;
+------+
| @h |
+------+
| 101 |
+------+
三、存儲(chǔ)函數(shù)
MySQL存儲(chǔ)函數(shù)(自定義函數(shù)),函數(shù)一般用于計(jì)算和返回一個(gè)值,可以將經(jīng)常需要使用的計(jì)算或功能寫成一個(gè)函數(shù)。函數(shù)和存儲(chǔ)過程類似。
存儲(chǔ)過程和函數(shù)的區(qū)別:
- 函數(shù)必須有返回值,而存儲(chǔ)過程可以沒有。
- 存儲(chǔ)過程的參數(shù)可以是IN、OUT、INOUT類型,函數(shù)的參數(shù)只能是IN
1、存儲(chǔ)函數(shù)創(chuàng)建和調(diào)用
創(chuàng)建存儲(chǔ)函數(shù)
在MySQL中,創(chuàng)建存儲(chǔ)函數(shù)使用CREATE FUNCTION關(guān)鍵字,其基本形式如下:
CREATE FUNCTION func_name ([param_name type[,...]])
RETURNS type
[characteristic ...]
BEGIN
routine_body
END;
參數(shù)說明:
- (1)func_name :存儲(chǔ)函數(shù)的名稱。
- (2)param_name type:可選項(xiàng),指定存儲(chǔ)函數(shù)的參數(shù)。type參數(shù)用于指定存儲(chǔ)函數(shù)的參數(shù)類型,該類型可以是MySQL數(shù)據(jù)庫中所有支持的類型。
- (3)RETURNS type:指定返回值的類型。
- (4)characteristic:可選項(xiàng),指定存儲(chǔ)函數(shù)的特性。
- (5)routine_body:SQL代碼內(nèi)容。
調(diào)用存儲(chǔ)函數(shù)
在MySQL中,存儲(chǔ)函數(shù)的使用方法與MySQL內(nèi)部函數(shù)的使用方法基本相同。用戶自定義的存儲(chǔ)函數(shù)與MySQL內(nèi)部函數(shù)性質(zhì)相同。區(qū)別在于,存儲(chǔ)函數(shù)是用戶自定義的。而內(nèi)部函數(shù)由MySQL自帶。其語法結(jié)構(gòu)如下:
SELECT func_name([parameter[,…]]);
常見示例
MySQL開啟bin-log后,調(diào)用存儲(chǔ)過程或者函數(shù)以及觸發(fā)器時(shí),會(huì)出現(xiàn)錯(cuò)誤號(hào)為1418的錯(cuò)誤:
在MySQL中創(chuàng)建函數(shù)時(shí)出現(xiàn)這種錯(cuò)誤的解決方法:
- 方法1:第一種是在創(chuàng)建子程序(存儲(chǔ)過程、函數(shù)、觸發(fā)器)時(shí),聲明為DETERMINISTIC或NO SQL與READS SQL DATA中的一個(gè), 例如:
CREATE DEFINER = CURRENT_USER PROCEDURE `NewProc`() DETERMINISTIC
BEGIN #Routine body goes here...
END;
- 方法2:第二種是信任子程序的創(chuàng)建者,禁止創(chuàng)建、修改子程序時(shí)對SUPER權(quán)限的要求,設(shè)置log_bin_trust_routine_creators全局系統(tǒng)變量為1。
-
- (1)在客戶端上執(zhí)行 SET GLOBAL log_bin_trust_function_creators = 1。
-
- (2)MySQL啟動(dòng)時(shí),加上–log-bin-trust-function-creators選項(xiàng),參數(shù)設(shè)置為1。
-
- (3)在MySQL配置文件my.ini或my.cnf中的[mysqld]段上加log-bin-trust-function-creators=1。
################1、無參有返回值#########################
# 統(tǒng)計(jì)emp表中員工個(gè)數(shù)
mysql> \d $
mysql> CREATE FUNCTION myf1()
RETURNS int
BEGIN
DECLARE c INT DEFAULT 0;
SELECT COUNT(1) INTO c FROM emp;
RETURN c;
END$
mysql> \d;
mysql> select myf1();
+--------+
| myf1() |
+--------+
| 15 |
+--------+
#################2、有參有返回值#####################
示例1:根據(jù)員工名返回工資
mysql> \d $
mysql> CREATE FUNCTION myf2(empName varchar(20))
RETURNS INT
BEGIN
DECLARE sal INT;
SELECT sai INTO sal FROM emp WHERE ename=empName;
RETURN sal;
END $
mysql> \d;
mysql> select myf2('劉備');
+----------------+
| myf2('劉備') |
+----------------+
| 29750 |
+----------------+
示例2:根據(jù)部門編號(hào),返回平均工資
mysql> \d $
mysql> CREATE FUNCTION myf3(d_No int)
RETURNS DOUBLE
BEGIN
DECLARE avg_sal DOUBLE;
SELECT AVG(sai) INTO avg_sal FROM emp WHERE deptno=d_No;
RETURN avg_sal;
END $
mysql> \d ;
mysql> select myf3(20);
+----------+
| myf3(20) |
+----------+
| 21750 |
+----------+
2、修改存儲(chǔ)函數(shù)
MySQL中,通過ALTER FUNCTION 語句來修改存儲(chǔ)函數(shù),其語法格式如下:
ALTER FUNCTION func_name [characteristic ...]
characteristic:COMMENT 'string'| LANGUAGE SQL| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }| SQL SECURITY { DEFINER | INVOKER }
上面這個(gè)語法結(jié)構(gòu)是MySQL官方給出的,修改的內(nèi)容可以包SQL語句也可以不包含。
3、刪除存儲(chǔ)函數(shù)
MySQL中使用DROP FUNCTION語句來刪除存儲(chǔ)函數(shù)。
示例:刪除存儲(chǔ)函數(shù)。
DROP FUNCTION IF EXISTS func_user;
四、游標(biāo)
游標(biāo)(Cursor)是處理多行數(shù)據(jù)的,游標(biāo)需要開啟,抓取,關(guān)閉的。
在 MySQL 中,存儲(chǔ)過程或函數(shù)中的查詢有時(shí)會(huì)返回多條記錄,而使用簡單的 SELECT 語句,沒有辦法得到第一行、下一行或前十行的數(shù)據(jù),這時(shí)可以使用游標(biāo)來逐條讀取查詢結(jié)果集中的記錄。游標(biāo)在部分資料中也被稱為光標(biāo)。
關(guān)系數(shù)據(jù)庫管理系統(tǒng)實(shí)質(zhì)是面向集合的,在 MySQL 中并沒有一種描述表中單一記錄的表達(dá)形式,除非使用 WHERE 子句來限制只有一條記錄被選中。所以有時(shí)我們必須借助于游標(biāo)來進(jìn)行單條記錄的數(shù)據(jù)處理。
一般通過游標(biāo)定位到結(jié)果集的某一行進(jìn)行數(shù)據(jù)修改。
結(jié)果集是符合 SQL 語句的所有記錄的集合。
個(gè)人理解游標(biāo)就是一個(gè)標(biāo)識(shí),用來標(biāo)識(shí)數(shù)據(jù)取到了什么地方,如果你了解編程語言,可以把他理解成數(shù)組中的下標(biāo)。
不像多數(shù) DBMS,MySQL 游標(biāo)只能用于存儲(chǔ)過程和函數(shù)。
下面介紹游標(biāo)的使用,主要包括游標(biāo)的聲明、打開、使用和關(guān)閉。
1、聲明游標(biāo)
MySQL 中使用 DECLARE 關(guān)鍵字來聲明游標(biāo),并定義相應(yīng)的 SELECT 語句,根據(jù)需要添加 WHERE 和其它子句。其語法的基本形式如下:
DECLARE cursor_name CURSOR FOR select_statement;
其中,cursor_name 表示游標(biāo)的名稱;select_statement 表示 SELECT 語句,可以返回一行或多行數(shù)據(jù)。
下面聲明一個(gè)名為 nameCursor 的游標(biāo),代碼如下:
mysql> DELIMITER //
mysql> CREATE PROCEDURE processnames()
BEGIN
DECLARE nameCursor CURSOR
FOR
SELECT name FROM tb_student;
END//
以上語句定義了 nameCursor 游標(biāo),游標(biāo)只局限于存儲(chǔ)過程中,存儲(chǔ)過程處理完成后,游標(biāo)就消失了。
2、打開游標(biāo)
聲明游標(biāo)之后,要想從游標(biāo)中提取數(shù)據(jù),必須首先打開游標(biāo)。在 MySQL 中,打開游標(biāo)通過 OPEN 關(guān)鍵字來實(shí)現(xiàn),其語法格式如下:
OPEN cursor_name;
其中,cursor_name 表示所要打開游標(biāo)的名稱。需要注意的是,打開一個(gè)游標(biāo)時(shí),游標(biāo)并不指向第一條記錄,而是指向第一條記錄的前邊。
在程序中,一個(gè)游標(biāo)可以打開多次。用戶打開游標(biāo)后,其他用戶或程序可能正在更新數(shù)據(jù)表,所以有時(shí)會(huì)導(dǎo)致用戶每次打開游標(biāo)后,顯示的結(jié)果都不同。
3、使用游標(biāo)
游標(biāo)順利打開后,可以使用 FETCH…INTO 語句來讀取數(shù)據(jù),其語法形式如下:
FETCH cursor_name INTO var_name [,var_name]...
上述語句中,將游標(biāo) cursor_name 中 SELECT 語句的執(zhí)行結(jié)果保存到變量參數(shù) var_name 中。變量參數(shù) var_name 必須在游標(biāo)使用之前定義。使用游標(biāo)類似高級語言中的數(shù)組遍歷,當(dāng)?shù)谝淮问褂糜螛?biāo)時(shí),此時(shí)游標(biāo)指向結(jié)果集的第一條記錄。
MySQL 的游標(biāo)是只讀的,也就是說,你只能順序地從開始往后讀取結(jié)果集,不能從后往前,也不能直接跳到中間的記錄。
4、關(guān)閉游標(biāo)
游標(biāo)使用完畢后,要及時(shí)關(guān)閉,在 MySQL 中,使用 CLOSE 關(guān)鍵字關(guān)閉游標(biāo),其語法格式如下:
CLOSE cursor_name;
CLOSE 釋放游標(biāo)使用的所有內(nèi)部內(nèi)存和資源,因此每個(gè)游標(biāo)不再需要時(shí)都應(yīng)該關(guān)閉。
在一個(gè)游標(biāo)關(guān)閉后,如果沒有重新打開,則不能使用它。但是,使用聲明過的游標(biāo)不需要再次聲明,用 OPEN 語句打開它就可以了。
如果你不明確關(guān)閉游標(biāo),MySQL 將會(huì)在到達(dá) END 語句時(shí)自動(dòng)關(guān)閉它。游標(biāo)關(guān)閉之后,不能使用 FETCH 來使用該游標(biāo)。
游標(biāo)案例
創(chuàng)建 users 數(shù)據(jù)表,并插入數(shù)據(jù),SQL 語句和運(yùn)行結(jié)果如下:
mysql> CREATE TABLE `users`(
`ID` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR(60),
`user_pass` VARCHAR(64),
PRIMARY KEY (`ID`)
);
mysql> INSERT INTO users VALUES(null,'liujianhong','liujianhong'),
(null,'liu','liu123'),
(null,'ling','ling123');
創(chuàng)建存儲(chǔ)過程 test_cursor,并創(chuàng)建游標(biāo) cur_test,查詢 users 數(shù)據(jù)表中的第 3 條記錄,SQL 語句和執(zhí)行過程如下:
mysql> DELIMITER //
mysql> CREATE PROCEDURE test_cursor (in param INT(10),out result VARCHAR(90))
BEGIN
DECLARE name VARCHAR(20);
DECLARE pass VARCHAR(20);
DECLARE done INT;
DECLARE cur_test CURSOR FOR SELECT user_name,user_pass FROM users;
DECLARE continue handler FOR SQLSTATE '02000' SET done = 1;
IF param THEN INTO result FROM users WHERE id = param;
ELSE
OPEN cur_test;
repeat
FETCH cur_test into name,pass;
SELECT concat_ws(',',result,name,pass) INTO result;
until done
END repeat;
CLOSE cur_test;
END IF;
END //
mysql> call test_cursor(3,@test)//
mysql> select @test//
+-----------+
| @test |
+-----------+
| ling,ling123 |
+-----------+
創(chuàng)建 pro_users() 存儲(chǔ)過程,定義 cur_1 游標(biāo),將表 users 中的 user_name 字段全部修改為 MySQL,SQL 語句和執(zhí)行過程如下。
mysql> CREATE PROCEDURE pro_users()
BEGIN
DECLARE result VARCHAR(100);
DECLARE no INT;
DECLARE cur_1 CURSOR FOR SELECT user_name FROM users;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no=1;
SET no=0;
OPEN cur_1;
WHILE no=0 do
FETCH cur_1 into result;
UPDATE users SET user_name='MySQL'
WHERE user_name=result;
END WHILE;
CLOSE cur_1;
END //
mysql> call pro_users() //
mysql> SELECT * FROM users //
+----+-----------+-----------+
| ID | user_name | user_pass |
+----+-----------+-----------+
| 1 | MySQL | liujianhon|
| 2 | MySQL | liu123 |
| 3 | MySQL | ying |
+----+-----------+-----------+
3 rows in set (0.00 sec)
結(jié)果顯示,users 表中的 user_name 字段已經(jīng)全部修改為 MySQL。