MYSQL 基础篇(补)
一、視圖、觸發器、函數、存儲過程、事件
1、視圖
1.1 什么是視圖
通俗來講,視圖就是一條 select 語句執行后返回的結果集。所有我們在創建視圖的時候,主要的工作就落在創建這條SQL查詢語句上。
1.2 視圖的特性
視圖是對若干張基本表的引用,一張虛表,查詢語句的執行結果,不存儲具體的數據(基本表數據發生了改變,視圖也會跟著改變)
1.3 視圖的作用
方便操作,特別是查詢操作,減少復雜的SQL語句,增強可讀性;更加安全,數據庫授權命令不能限定到特定的行和特定的列,但通過合理創建視圖,可以把權限限定到行列級別;
1.4 使用場合
權限控制的時候,不希望用戶訪問表中某些敏感信息的列,比如 salary… 關鍵信息來源于多個復雜關聯表,可以創建視圖提取我們需要的信息,簡化操作;
1.5 視圖的使用
- 語法
with check option
首先視圖只操作它可以查詢出來的數據,對于它查詢不出的數據,即使基表有,也不可以通過視圖來操作。
現有三張表:用戶(user)、課程(course)、用戶課程中間表(user_course),表結構及數據如下:
SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for course -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` (`sid` int(11) NOT NULL AUTO_INCREMENT,`sname` varchar(32) NOT NULL,PRIMARY KEY (`sid`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of course -- ---------------------------- INSERT INTO `course` VALUES ('1', '語文'); INSERT INTO `course` VALUES ('2', '數學'); INSERT INTO `course` VALUES ('3', '英語'); INSERT INTO `course` VALUES ('4', '物理'); INSERT INTO `course` VALUES ('5', '');-- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) NOT NULL,`course_id` int(11) NOT NULL,PRIMARY KEY (`id`),KEY `fk_student_course` (`course_id`),CONSTRAINT `fk_student_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`sid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES ('1', '小飛', '1'); INSERT INTO `student` VALUES ('2', 'hukey', '2'); INSERT INTO `student` VALUES ('3', '小王', '3'); INSERT INTO `student` VALUES ('4', '阿狗', '4');這時,當我們想要查詢小飛上的所以課程相關信息的時候,需要這樣寫一條長長的SQL語句,如下:
SELECT sid, sname, student.name from course LEFT JOIN student on course.sid = student.course_id where student.name = '小飛';但是我們可以通過視圖簡化操作,例如我們創建視圖 view_student_course 如下:
create ALGORITHM = UNDEFINED DEFINER = 'root'@'%' SQL SECURITY DEFINER VIEW view_student_course AS (SELECT sid, sname, student.name from course LEFT JOIN student on course.sid = student.course_id );幾點說明(MySQL中的視圖在標準SQL的基礎之上做了擴展):
ALGORITHM=UNDEFINED:指定視圖的處理算法; DEFINER=`root`@`localhost`:指定視圖創建者; SQL SECURITY DEFINER:指定視圖查詢數據時的安全驗證方式;創建好視圖之后,我們可以直接用以下SQL語句在視圖上查詢小飛上的所以課程相關信息,同樣可以得到所需結果:
SELECT * from view_student_course where name = '小飛';可以嘗試對視圖進行增刪改操作,這里總結如下:
(1)視圖與表是一對一關系情況:如果沒有其它約束(如視圖中沒有的字段,在基本表中是必填字段情況),是可以進行增刪改數據操作;
(2)視圖與表是一對多關系情況:如果只修改一張表的數據,且沒有其它約束(如視圖中沒有的字段,在基本表中是必填字段情況),是可以進行改數據操作;
除了以上兩條外都是無法進行增刪改,但是強烈不建議直接對視圖進行增刪改操作,可能不經意就修改了真實表中的多條數據。
- 查看庫中的視圖:
- 修改視圖
使用create or replace view命令修改視圖
create or replace view view_student_course as select ... with check option; # with check option 可以不加使用alter view命令修改視圖
alter view view_student_course as select ... with check option;- 刪除視圖
2、觸發器
2.1 什么是觸發器
觸發器是與表有關的數據庫對象,在滿足定義條件時觸發,并執行觸發器中定義的語句集合。
觸發器的特性:
1. 在 begin end體, begin … end; 之間的語句可以寫的簡單或者復雜
2. 什么條件觸發:insert、update、delete
3. 什么時候觸發:在增刪改前或者后
4. 觸發頻率: 針對每一行執行
5. 觸發器定義在表上,附著在表上
也就是由事件來觸發某個操作,事件包括INSERT語句,UPDATE語句和DELETE語句;可以協助應用在數據庫端確保數據的完整性。
盡量少使用觸發器、不建議使用
假設觸發器觸發每次執行1s,insert table 500條數據,那么就需要觸發500次觸發器,光是觸發器執行的時間就花費了500s,而insert 500條數據一共是1s,那么這個insert的效率就非常低了。因此我們特別需要注意的一點是觸發器的begin end;之間的語句的執行效率一定要高,資源消耗要小。
2.2 觸發器的創建
CREATE[DEFINER = { user | CURRENT_USER }] TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW [trigger_order] trigger_bodytrigger_time: { BEFORE | AFTER }trigger_event: { INSERT | UPDATE | DELETE }trigger_order: { FOLLOWS | PRECEDES } other_trigger_nametrigger_time: { BEFORE | AFTER }
BEFORE 和 AFTER 參數指定了觸發的時間,在事件之前或之后
FOR EACH ROW
表示任何一條記錄上的操作滿足觸發事件都會觸發該觸發器,也就是說觸發器的觸發頻率是針對每一行數據觸發一次。
trigger_event: { INSERT | UPDATE | DELETE }
(1)INSERT型觸發器:插入某一行時激活觸發器,可能通過INSERT、LOAD DATA、REPLACE 語句觸發(LOAD DAT語句用于將一個文件裝入到一個數據表中,相當與一系列的INSERT操作);
(2)UPDATE型觸發器:更改某一行時激活觸發器,可能通過UPDATE語句觸發;
(3)DELETE型觸發器:刪除某一行時激活觸發器,可能通過DELETE、REPLACE語句觸發。
2.3 創建只有一個執行語句的觸發器
CREATE TRIGGER 觸發器名 BEFORE|AFTER 觸發事件 ON 表名 FOR EACH ROW 執行語句;如:創建了一個名為 tri_work_ins 的觸發器,一旦在work表中有插入動作,就會自動往time表里插入當前時間
CREATE TRIGGER trig1 AFTER INSERT ON work FOR EACH ROW INSERT INTO time VALUES(NOW());2.4 創建有多個執行語句的觸發器
CREATE TRIGGER 觸發器名 BEFORE|AFTER 觸發事件 ON 表名 FOR EACH ROW BEGIN執行語句列表 END; DELIMITER || # 修改結束標志 默認是 ; 修改為 || 這樣可以一次執行多句 CREATE TRIGGER trig2 BEFORE DELETE ON work FOR EACH ROW BEGIN INSERT INTO time VALUES(NOW()); INSERT INTO time VALUES(NOW()); END|| DELIMITER ; # 重新修改結束標志位 ;2.5 NEW 和 OLD 詳解
MySQL 中定義了 NEW 和 OLD,用來表示觸發器的所在表中,觸發了觸發器的那一行數據,來引用觸發器中發生變化的記錄內容,具體地:
(1)在INSERT型觸發器中,NEW用來表示將要(BEFORE)或已經(AFTER)插入的新數據;
(2)在UPDATE型觸發器中,OLD用來表示將要或已經被修改的原數據,NEW用來表示將要或已經修改為的新數據;
(3)在DELETE型觸發器中,OLD用來表示將要或已經被刪除的原數據;
使用方法:NEW.columnName (columnName為相應數據表某一列名)
另外,OLD是只讀的,而NEW則可以在觸發器中使用 SET 賦值,這樣不會再次觸發觸發器,造成循環調用(如每插入一個學生前,都在其學號前加“2013”)。
CREATE TABLE account (acct_num INT, amount DECIMAL(10,2)); # 創建表 INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00); # 插入數據# 創建觸發器 delimiter $$ CREATE TRIGGER upd_check BEFORE UPDATE ON account FOR EACH ROW BEGIN IF NEW.amount < 0 THENSET NEW.amount = 0; ELSEIF NEW.amount > 100 THENSET NEW.amount = 100; END IF; END$$ delimiter ;update account set amount=-10 where acct_num=137; # 測試觸發器,amount小于0select * from account; # 查詢表中所有數據 +----------+---------+ | acct_num | amount | +----------+---------+ | 137 | 0.00 | | 141 | 1937.50 | | 97 | -100.00 | +----------+---------+update account set amount=200 where acct_num=137; # 測試觸發器,amount大于100 select * from account; # 查詢表中所有數據 +----------+---------+ | acct_num | amount | +----------+---------+ | 137 | 100.00 | | 141 | 1937.50 | | 97 | -100.00 | +----------+---------+2.6 查看觸發器
# 結果,顯示所有觸發器的基本信息;無法查詢指定的觸發器。 SHOW TRIGGERS;# 結果,顯示所有觸發器的詳細信息;同時,該方法可以查詢制定觸發器的詳細信息。 SELECT * FROM information_schema.triggers; # 查詢指定的觸發器詳情 select * from information_schema.triggers where trigger_name='upd_check';2.7 刪除觸發器
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name刪除觸發器之后最好使用上面的方法查看一遍;同時,也可以使用database.trig來指定某個數據庫中的觸發器。
注意:如果不需要某個觸發器時一定要將這個觸發器刪除,以免造成意外操作,這很關鍵。
3、函數
3.1 什么是函數
函數存儲著一系列sql語句,調用函數就是一次性執行這些語句。所以函數可以降低語句重復。但要注意的是函數注重返回值,不注重執行過程,所以一些語句無法執行。所以函數并不是單純的sql語句集合。mysql有內置函數,也能夠自定義函數。
補充:函數與存儲過程的區別:函數只會返回一個值,不允許返回一個結果集。函數強調返回值,所以函數不允許返回多個值的情況,即使是查詢語句。
3.2 函數的創建
Create function function_name(參數列表) # 參數列表 如: (參數名 參數類型,參數名 參數類型) returns 返回值類型 BEGIN 函數體內容 END相關說明:
函數名:應該合法的標識符,并且不應該與已有的關鍵字沖突。一個函數應該屬于某數據庫,可以使用db_name.funciton_name 的形式執行當前函數所屬數據庫,否則默認為當前數據庫。
參數列表:可以有一個或多個函數參數,甚至是沒有參數也是可以的。對于每個參數,由參數名和參數類型組成。
返回值: 指明返回值類型
函數體:自定義函數的函數體由多條可用的MySQL語句,流程控制,變量申明等語句構成。需要指明的是函數體中一定要含有return 返回語句。
3.3 函數使用示例
(1)無參數函數定義
# 創建函數 delimiter $$CREATE FUNCTION hello() RETURNS VARCHAR(255) BEGIN RETURN 'Hello world, i am mysql'; END $$delimiter ;# 調用函數 select hello(); +-------------------------+ | hello() | +-------------------------+ | Hello world, i am mysql | +-------------------------+(2)含有參數的自定義函數
# 定義函數 delimiter $$ # 求和 CREATE FUNCTION f1(t1 int,t2 int) RETURNS INT BEGINDECLARE num int; # 定義臨時變量set num = t1 + t2; # 給臨時變量賦值RETURN(num); END $$delimiter ;# 調用函數 select f1(1, 100); +------------+ | f1(1, 100) | +------------+ | 101 | +------------+3.4 查看庫中的函數
-- 查看函數 show FUNCTION status;-- 查看函數的創建過程 show create function func_name;4、存儲過程
4.1 什么是存儲過程
一組可編程的函數,是為了完成特定功能的SQL語句集,經編譯創建并保存在數據庫中,用戶可通過指定存儲過程的名字并給定參數(需要時)來調用執行。
優點:
(1)將重復性很高的一些操作,封裝到一個存儲過程中,簡化了對這些SQL的調用;
(2)批量處理:SQL+循環,減少流量,也就是“跑批”;
(3)統一接口,確保數據的安全
相對于oracle數據庫來說,MySQL的存儲過程相對功能較弱,使用較少。
4.2 存儲過程的創建和調用
存儲過程就是具有名字的一段代碼,用來完成一個特定的功能,創建的存儲過程保存在數據庫的數據字典中。
-- 創建存儲過程 CREATE[DEFINER = { user | CURRENT_USER }] PROCEDURE sp_name ([proc_parameter[,...]])[characteristic ...] routine_bodyproc_parameter:[ IN | OUT | INOUT ] param_name typecharacteristic: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]現有兩張表(userinfo)和(teacher)表,表結構及數據:
SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for teacher -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` (`tid` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) NOT NULL,PRIMARY KEY (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of teacher -- ---------------------------- INSERT INTO `teacher` VALUES ('1', '周杰倫'); INSERT INTO `teacher` VALUES ('2', '那英'); INSERT INTO `teacher` VALUES ('3', '汪峰'); INSERT INTO `teacher` VALUES ('4', '哈林');-- ---------------------------- -- Table structure for userinfo -- ---------------------------- DROP TABLE IF EXISTS `userinfo`; CREATE TABLE `userinfo` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(10) NOT NULL,`password` varchar(32) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of userinfo -- ---------------------------- INSERT INTO `userinfo` VALUES ('1', 'admin', 'admin'); INSERT INTO `userinfo` VALUES ('2', 'superman', '123456'); INSERT INTO `userinfo` VALUES ('3', 'batman', '666');創建一個存儲過程:
delimiter $$CREATE PROCEDURE p1() BEGINselect * from teacher;insert into userinfo(username, password) VALUES ('xiaoA', '123'); END $$delimiter ;執行存儲過程:
call p1; +-----+-----------+ | tid | name | +-----+-----------+ | 1 | 周杰倫 | | 2 | 那英 | | 3 | 汪峰 | | 4 | 哈林 | +-----+-----------+ 4 rows in set (0.00 sec)Query OK, 1 row affected (0.00 sec)解析:這個存儲過程做了兩件事,一個是查詢所有的teacher,另一個就是向student表中插入一條數據
4.3 存儲過程的參數
存儲過程可以有 0 個或多個參數,用于存儲過程的定義。
3 種參數類型:
1)IN 輸入參數:表示調用者向過程傳入值(傳入值可以是字面量或變量);
2)OUT輸出參數:表示過程向調用者傳出值(可以返回多個值)(傳出值只能是變量);
3)INOUT輸入輸出參數:既表示調用者向過程傳入值,又表示過程向調用者傳出值(值只能是變量);
4.3.1 IN輸入參數的使用
delimiter $$CREATE PROCEDURE p2(in t1 int) BEGINSELECT t1;set t1 = 2;SELECT t1; END $$delimiter ;調用存儲過程:
set @t1 = 1; Query OK, 0 rows affected (0.00 sec)call p2(@t1); +------+ | t1 | +------+ | 1 | +------++------+ | t1 | +------+ | 2 | +------+select @t1; +------+ | @t1 | +------+ | 1 | +------+以上可以看出,t1 在存儲過程中被修改,但并不影響@t1 的值,因為前者為局部變量、后者為全局變量。
4.3.2 OUT 輸出參數
delimiter $$CREATE PROCEDURE p3(out t_out int) BEGINSELECT t_out;set t_out = 2;SELECT t_out; END $$delimiter ;調用存儲過程:
set @t_out =1 ;call p3(@t_out); +-------+ | t_out | +-------+ | NULL | +-------+ # 因為out是向調用者輸出參數,不接收輸入的參數,所以存儲過程里的p_out為null+-------+ | t_out | +-------+ | 2 | +-------+select @t_out; +--------+ | @t_out | +--------+ | 2 | +--------+ # 調用了 p3 存儲過程,輸出參數,改變了 t_out 變量的值4.3.3 inout輸入參數
delimiter $$CREATE PROCEDURE p4(inout t_inout int) BEGINSELECT t_inout;set t_inout = 2;SELECT t_inout; END $$delimiter ;調用存儲過程:
set @t_inout = 1;call p4(@t_inout); +---------+ | t_inout | +---------+ | 1 | +---------++---------+ | t_inout | +---------+ | 2 | +---------+select @t_inout; +----------+ | @t_inout | +----------+ | 2 | +----------+ # 調用了 p4 存儲過程,接受了輸入的參數,也輸出參數,改變了變量注意:
(1)如果過程沒有參數,也必須在過程名后面寫上小括號
(2)確保參數的名字不等于列的名字,否則在過程體中,參數名被當做列名來處理
建議使用:輸入值使用 in 參數;inout參數就盡量少用
4.3.4 存儲過程-事務
在執行一個存儲過程中,我們無法確定這個存儲過程是否執行成功,如果執行失敗,我們是否要考慮回滾的問題。這里就需要存儲過程對于事務的支持:
delimiter //create procedure p4(out status int ) BEGIN1. 聲明如果出現異常則執行{set status = 1;rollback;}開始事務-- 由秦兵賬戶減去100-- 方少偉賬戶加90-- 張根賬戶加10commit;結束set status = 2;END //delimiter ;存儲過程支持事務如下:
delimiter $$CREATE PROCEDURE p5(out p_return_code tinyint) BEGINDECLARE exit HANDLER for SQLEXCEPTIONBEGIN-- 執行失敗,則返回 1set p_return_code = 1;ROLLBACK; -- 如果出錯,則回滾END;START TRANSACTION;INSERT into userinfo(username, password) VALUES ('xiaoB', '222');COMMIT;-- 執行成功,則返回 2set p_return_code = 2; END $$delimiter ;執行: set @p_return_code=0;call p5(@p_return_code);select @p_return_code; +----------------+ | @p_return_code | +----------------+ | 2 | +----------------+ # 變量 p_return_code = 2 說明存儲過程執行成功。4.4 查看存儲過程
-- 查看存儲過程: show procedure status; -- 查看存儲過程創建的過程: show create procedure proc_name;5、事件
5.1 什么是事件
是什么?事件是一組SQL集合,簡單說就是mysql中的定時器,時間到了就執行。
5.2 查詢事件變量
注:如果查詢不到變量,說明數據庫版本過低,不支持事件。
SHOW VARIABLES LIKE 'event_scheduler'; #開啟事件,如果想要每次重啟數據庫服務后,事件仍然生效需要在mysql.ini文件中加入event_scheduler = ON; 的語句 SET GLOBAL event_scheduler = ON; #查詢數據庫所有創建的事件 SELECT * FROM mysql.event; #啟用事件任務 ALTER EVENT event1 ENABLE; #禁用事件任務 ALTER EVENT event1 DISABLE; #查看事件的定義 SHOW CREATE EVENT event1;5.3 創建事件語法
CREATE[DEFINER = { USER | CURRENT_USER }] EVENT [IF NOT EXISTS]event_name ON SCHEDULE `schedule` [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] DO event_body;`schedule`: AT TIMESTAMP [+ INTERVAL INTERVAL] ... | EVERY INTERVAL [STARTS TIMESTAMP [+ INTERVAL INTERVAL] ...] [ENDS TIMESTAMP [+ INTERVAL INTERVAL] ...] INTERVAL: quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND} -- 說明#DEFINER:定義事件執行的時候檢查權限的用戶。#event_name:表示事件名稱#SCHEDULE:表示觸發點,AT timestamp一般用于只執行一次。EVERY interval一般用于周期性執行,可以設定開始時間和結束時間。#ON COMPLETION PRESERVE:表示任務執行之后仍保留#ON COMPLETION NOT PRESERVE:表示任務執行完成后不保留#ENABLE|DISABLE:表示設置啟用或者禁止這個事件。#COMMENT:添加注釋5.4 測試
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `name` VARCHAR(200) NOT NULL COMMENT '收貨人', `address` VARCHAR(100) NOT NULL COMMENT '收貨地址', `addtime` DATETIME NOT NULL COMMENT '添加時間', PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8;#清空表 TRUNCATE TABLE `user`;測試存儲過程
DELIMITER $$ DROP PROCEDURE IF EXISTS `ADD_USER`$$ CREATE PROCEDURE `ADD_USER`() BEGIN INSERT INTO `user`(NAME, address,ADDTIME) VALUES('AT','AT',NOW()); END$$ DELIMITER ;事件案列
# 1.每隔3秒 DROP EVENT IF EXISTS `event1`; DELIMITER ;;CREATE EVENT `event1` ON SCHEDULE EVERY 3 SECOND ON COMPLETION PRESERVE DISABLE COMMENT '' DO BEGIN INSERT INTO `user`(NAME, address,ADDTIME) VALUES('test1','test1',NOW()); END;;DELIMITER ; #2.每天幾點幾分 DROP EVENT IF EXISTS `event2`; DELIMITER ;;CREATE EVENT `event2` ON SCHEDULE EVERY 1 DAY STARTS DATE_ADD(DATE_ADD(CURDATE(),INTERVAL 3 HOUR),INTERVAL 30 MINUTE) ON COMPLETION PRESERVE ENABLE COMMENT '' DO BEGIN CALL ADD_USER(); END ;;DELIMITER ; #9號凌晨1點 SELECT DATE_ADD(DATE_SUB(CURDATE(),INTERVAL DAY(CURDATE())-9 DAY),INTERVAL 1 HOUR); #1分鐘后 SELECT NOW()+INTERVAL 1 MINUTE; #凌晨3點 SELECT DATE_ADD(CURDATE(),INTERVAL 3 HOUR); #凌晨3點30分 SELECT DATE_ADD(DATE_ADD(CURDATE(),INTERVAL 3 HOUR),INTERVAL 30 MINUTE);文章內容博主忘記來之那篇博客了,如有侵權,請聯系我修改,萬分抱歉。
總結
以上是生活随笔為你收集整理的MYSQL 基础篇(补)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 变速变调软件有哪些?这个不错的变速变调软
- 下一篇: 在不同位置(客户端的终端设备,服务端,项