1.1 什麼是視圖mysql
通俗來說,視圖就是一條 select 語句執行後返回的結果集。全部咱們在建立視圖的時候,主要的工做就落在建立這條SQL查詢語句上。算法
1.2 視圖的特性sql
視圖是對若干張基本表的引用,一張虛表,查詢語句的執行結果,不存儲具體的數據(基本表數據發生了改變,視圖也會跟着改變)數據庫
1.3 視圖的做用編程
方便操做,特別是查詢操做,減小複雜的SQL語句,加強可讀性;更加安全,數據庫受權命令不能限定到特定的行和特定的列,但經過合理建立視圖,能夠把權限限定到行列級別;安全
1.4 使用場合oracle
權限控制的時候,不但願用戶訪問表中某些敏感信息的列,好比 salary… 關鍵信息來源於多個複雜關聯表,能夠建立視圖提取咱們須要的信息,簡化操做;ide
1.5 視圖的使用函數
視圖實例1-建立視圖及查詢數據操做fetch
現有三張表:用戶(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)視圖與表是一對多關係狀況:若是隻修改一張表的數據,且沒有其它約束(如視圖中沒有的字段,在基本表中是必填字段狀況),是能夠進行改數據操做;
除了以上兩條外都是沒法進行增刪改,可是強烈不建議直接對視圖進行增刪改操做,可能不經意就修改了真實表中的多條數據
查看庫中的視圖:
show table status where comment = 'view';
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_body trigger_time: { BEFORE | AFTER } trigger_event: { INSERT | UPDATE | DELETE } trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
trigger_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 執行語句;
例1:建立了一個名爲trig1的觸發器,一旦在work表中有插入動做,就會自動往time表裏插入當前時間
mysql> 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;
mysql> DELIMITER || mysql> CREATE TRIGGER trig2 BEFORE DELETE -> ON work FOR EACH ROW -> BEGIN -> INSERT INTO time VALUES(NOW()); -> INSERT INTO time VALUES(NOW()); -> END|| mysql> 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」)。
mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2)); mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00); mysql> delimiter $$ mysql> 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$$ mysql> delimiter ; mysql> update account set amount=-10 where acct_num=137; mysql> select * from account; +----------+---------+ | acct_num | amount | +----------+---------+ | 137 | 0.00 | | 141 | 1937.50 | | 97 | -100.00 | +----------+---------+ mysql> update account set amount=200 where acct_num=137; mysql> select * from account; +----------+---------+ | acct_num | amount | +----------+---------+ | 137 | 100.00 | | 141 | 1937.50 | | 97 | -100.00 | +----------+---------+
2.6 查看觸發器
mysql> SHOW TRIGGERS\G; …… 結果,顯示全部觸發器的基本信息;沒法查詢指定的觸發器。 在information_schema.triggers表中查看觸發器信息 mysql> SELECT * FROM information_schema.triggers\G …… 結果,顯示全部觸發器的詳細信息;同時,該方法能夠查詢制定觸發器的詳細信息。 mysql> select * from information_schema.triggers -> where trigger_name='upd_check'\G;
刪除觸發器
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
刪除觸發器以後最好使用上面的方法查看一遍;同時,也可使用database.trig來指定某個數據庫中的觸發器。
注意:
若是不須要某個觸發器時必定要將這個觸發器刪除,以避免形成意外操做,這很關鍵。
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 ;
調用函數:
MariaDB [db1]> select hello(); +-------------------------+ | hello() | +-------------------------+ | Hello world, i am mysql | +-------------------------+
(2)含有參數的自定義函數
delimiter $$ CREATE FUNCTION f1( t1 int, t2 int) RETURNS INT BEGIN DECLARE num int; set num = t1 + t2; RETURN(num); END $$ delimiter ;
調用函數:
MariaDB [db1]> select f1(1, 100); +------------+ | f1(1, 100) | +------------+ | 101 | +------------+
3.4 查看庫中的函數
-- 查看函數 show FUNCTION status; -- 查看函數的建立過程: show create function func_name;
4.1 什麼是存儲過程
一組可編程的函數,是爲了完成特定功能的SQL語句集,經編譯建立並保存在數據庫中,用戶可經過指定存儲過程的名字並給定參數(須要時)來調用執行。
優勢:
(1)將重複性很高的一些操做,封裝到一個存儲過程當中,簡化了對這些SQL的調用;
(2)批量處理:SQL+循環,減小流量,也就是「跑批」;
(3)統一接口,確保數據的安全
相對於oracle數據庫來講,MySQL的存儲過程相對功能較弱,使用較少。
4.2 存儲過程的建立和調用
存儲過程就是具備名字的一段代碼,用來完成一個特定的功能,建立的存儲過程保存在數據庫的數據字典中。
建立存儲過程
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]
現有兩張表(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() BEGIN select * from teacher; insert into userinfo(username, password) VALUES ('xiaoA', '123'); END $$ delimiter ;
執行存儲過程:
MariaDB [db1]> 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輸入輸出參數:既表示調用者向過程傳入值,又表示過程向調用者傳出值(值只能是變量)
IN輸入參數的使用
delimiter $$ CREATE PROCEDURE p2(in t1 int) BEGIN SELECT t1; set t1 = 2; SELECT t1; END $$ delimiter ;
調用存儲過程:
MariaDB [db1]> set @t1 = 1; Query OK, 0 rows affected (0.00 sec) MariaDB [db1]> call p2(@t1); +------+ | t1 | +------+ | 1 | +------+ +------+ | t1 | +------+ | 2 | +------+ MariaDB [db1]> select @t1; +------+ | @t1 | +------+ | 1 | +------+
以上能夠看出,t1 在存儲過程當中被修改,但並不影響@t1 的值,由於前者爲局部變量、後者爲全局變量。
OUT 輸出參數
delimiter $$ CREATE PROCEDURE p3(out t_out int) BEGIN SELECT t_out; set t_out = 2; SELECT t_out; END $$ delimiter ;
調用存儲過程:
MariaDB [db1]> set @t_out =1 ; MariaDB [db1]> call p3(@t_out); +-------+ | t_out | +-------+ | NULL | +-------+ # 由於out是向調用者輸出參數,不接收輸入的參數,因此存儲過程裏的p_out爲null +-------+ | t_out | +-------+ | 2 | +-------+ MariaDB [db1]> select @t_out; +--------+ | @t_out | +--------+ | 2 | +--------+ # 調用了 p3 存儲過程,輸出參數,改變了 t_out 變量的值
inout輸入參數
delimiter $$ CREATE PROCEDURE p4(inout t_inout int) BEGIN SELECT t_inout; set t_inout = 2; SELECT t_inout; END $$ delimiter ;
調用存儲過程:
MariaDB [db1]> set @t_inout = 1; MariaDB [db1]> call p4(@t_inout); +---------+ | t_inout | +---------+ | 1 | +---------+ +---------+ | t_inout | +---------+ | 2 | +---------+ MariaDB [db1]> select @t_inout; +----------+ | @t_inout | +----------+ | 2 | +----------+
調用了 p4 存儲過程,接受了輸入的參數,也輸出參數,改變了變量
注意:
(1)若是過程沒有參數,也必須在過程名後面寫上小括號
(2)確保參數的名字不等於列的名字,不然在過程體中,參數名被當作列名來處理
建議使用:
輸入值使用 in 參數;
輸入值使用 in 參數;
inout參數就儘可能少用
4.4 存儲過程-事務
在執行一個存儲過程當中,咱們沒法肯定這個存儲過程是否執行成功,若是執行失敗,咱們是否要考慮回滾的問題。這裏就須要存儲過程對於事務的支持:
delimiter // create procedure p4( out status int ) BEGIN 1. 聲明若是出現異常則執行{ set status = 1; rollback; } 開始事務 -- 由秦兵帳戶減去100 -- 方少偉帳戶加90 -- 張根帳戶加10 commit; 結束 set status = 2; END // delimiter ;
存儲過程支持事務以下:
delimiter $$ CREATE PROCEDURE p5(out p_return_code tinyint) BEGIN DECLARE exit HANDLER for SQLEXCEPTION BEGIN -- 執行失敗,則返回 1 set p_return_code = 1; ROLLBACK; -- 若是出錯,則回滾 END; START TRANSACTION; INSERT into userinfo(username, password) VALUES ('xiaoB', '222'); COMMIT; -- 執行成功,則返回 2 set p_return_code = 2; END $$ delimiter ; 執行: MariaDB [db1]> set @p_return_code=0; MariaDB [db1]> call p5(@p_return_code); MariaDB [db1]> select @p_return_code; +----------------+ | @p_return_code | +----------------+ | 2 | +----------------+
變量 p_return_code = 2 說明存儲過程執行成功。
4.5 使用 pymysql 模塊調用存儲過程
import pymysql config = { 'host': '192.168.118.11', 'user': 'root', 'password': '123456', 'database': 'db1' } db = pymysql.connect(**config) with db.cursor(cursor=pymysql.cursors.DictCursor) as cursor: cursor.callproc('p3', (0,)) # 使用 callproc 調用存儲過程 cursor.execute('select @_p3_0') # 查詢 out 參數的返回值 r2 = cursor.fetchall() # 獲取返回值 print(r2) 執行結果: [{'@_p3_0': 2}]
4.6 查看存儲過程
-- 查看存儲過程: show procedure status; -- 查看存儲過程建立的過程: show create procedure proc_name;