Python Day48 mysql補充
一、視圖
視圖是一個虛擬表(非真實存在),其本質是【根據SQL語句獲取動態的數據集,並為其命名】,用戶使用時只需使用【名稱】即可獲取結果集,可以將該結果集當做表來使用。使用視圖我們可以把查詢過程中的臨時表摘出來,用視圖去實現,這樣以後再想操作該臨時表的數據時就無需重寫復雜的sql了,直接去視圖中查找即可,但視圖有明顯地效率問題,並且視圖是存放在數據庫中的,如果我們程序中使用的sql過分依賴數據庫中的視圖,即強耦合,那就意味著擴展sql極為不便,因此並不推薦使用。
1、創建視圖
create view 視圖名 as sql語句
註意,上述為創建視圖的語句,但是語句中的sql語句中不能包含子查詢。實例如下:
可以通過創建視圖的方式,將上述sql查詢語句的結果保存成視圖形式的虛擬表,下次再次使用時,就可以避免上述重復的sql語句:
2、視圖的修改
正如視圖概念中所述,視圖為sql語句查詢結果的虛擬表,它的真實數據是來源sql語句中涉及的真正的表中,當sql語句中只關聯一個表,更改視圖中的數據,所被關聯的表中的數據也會跟著更改,顯然這是不合理的,當sql語句中關聯多個表,則壓根不可以實現對視圖中的數據的更改。總之不可以通過update或者insert等語句對視圖中的內容進行更改。如果想真正的實現對視圖的更改,其實就是更改原有視圖中的sql語句,具體的更改語法如下:
alter view 原視圖名 as 新sql語句
3、刪除視圖
drop view 視圖名 #例:drop view course_teacher
總結:使用視圖以後就無需每次都重寫子查詢的sql,但是這麽效率並不高,還不如我們寫子查詢的效率高;其次視圖是存放到數據庫裏的,如果我們程序中的sql過分依賴於數據庫中存放的視圖,那麽意味著,一旦sql需要修改且涉及到視圖的部分,則必須去數據庫中進行修改。
二、觸發器
使用觸發器可以定制用戶對表進行【增、刪、改】操作時前後的行為,註意:沒有查詢
1、創建觸發器語法
# 插入前 CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW BEGIN ... END # 插入後 CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW BEGIN ... END # 刪除前 CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW BEGIN ... END # 刪除後 CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW BEGIN ... END # 更新前 CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW BEGIN ... END # 更新後 CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW BEGIN ... END
2、觸發器實例
#準備表 CREATE TABLE cmd ( id INT PRIMARY KEY auto_increment, USER CHAR (32), priv CHAR (10), cmd CHAR (64), sub_time datetime, #提交時間 success enum (‘yes‘, ‘no‘) #0代表執行失敗 ); CREATE TABLE errlog ( id INT PRIMARY KEY auto_increment, err_cmd CHAR (64), err_time datetime ); #創建觸發器 delimiter // CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW BEGIN IF NEW.success = ‘no‘ THEN #等值判斷只有一個等號 INSERT INTO errlog(err_cmd, err_time) VALUES(NEW.cmd, NEW.sub_time) ; #必須加分號 END IF ; #必須加分號 END// delimiter ; #往表cmd中插入記錄,觸發觸發器,根據IF的條件決定是否插入錯誤日誌 INSERT INTO cmd ( USER, priv, cmd, sub_time, success ) VALUES (‘egon‘,‘0755‘,‘ls -l /etc‘,NOW(),‘yes‘), (‘egon‘,‘0755‘,‘cat /etc/passwd‘,NOW(),‘no‘), (‘egon‘,‘0755‘,‘useradd xxx‘,NOW(),‘no‘), (‘egon‘,‘0755‘,‘ps aux‘,NOW(),‘yes‘); #查詢錯誤日誌,發現有兩條 mysql> select * from errlog; +----+-----------------+---------------------+ | id | err_cmd | err_time | +----+-----------------+---------------------+ | 1 | cat /etc/passwd | 2017-09-14 22:18:48 | | 2 | useradd xxx | 2017-09-14 22:18:48 | +----+-----------------+---------------------+ rows in set (0.00 sec)
特別的:NEW表示即將插入的數據行,OLD表示即將刪除的數據行。
3、觸發器的刪除
觸發器無法由用戶直接調用,而是由於對表的【增/刪/改】操作被動引發的。刪除觸發器的語法如下:
drop trigger 觸發器名; #例:drop trigger tri_after_insert_cmd;
三、事務
事務用於將某些操作的多個SQL作為原子性操作,一旦有某一個出現錯誤,即可回滾到原來的狀態,從而保證數據庫數據完整性。
create table user( id int primary key auto_increment, name char(32), balance int ); insert into user(name,balance) values (‘wsb‘,1000), (‘egon‘,1000), (‘ysb‘,1000); #原子操作,執行中無異常 start transaction; update user set balance=900 where name=‘wsb‘; update user set balance=1010 where name=‘egon‘; update user set balance=1090 where name=‘ysb‘; commit; #出現異常,回滾到初始狀態 start transaction; update user set balance=800 where name=‘wsb‘; update user set balance=1020 where name=‘egon‘; uppdate user set balance=1180 where name=‘ysb‘; rollback;
commit;
四、存儲過程
存儲過程包含了一系列可執行的sql語句,存儲過程存放於MySQL中,通過調用它的名字可以執行其內部的一堆sql。使用存儲過程的優點:(1)用於替代程序寫的SQL語句,實現程序與sql解耦;(2)基於網絡傳輸,傳別名的數據量小,而直接傳sql數據量大。缺點是程序員擴展功能不方便。
1、數據庫與程序使用方式
#方式一: MySQL:存儲過程 程序:調用存儲過程 #方式二: MySQL: 程序:純SQL語句 #方式三: MySQL: 程序:類和對象,即ORM(本質還是純SQL語句)
2、創建無參數存儲過程
#創建無參存儲過程 delimiter $$ #符號不局限於此,但前後需一致 create procedure p1() begin declare i int default 1; while (i<10) do select * from course; set i=i+1; end while; end $$ delimiter ; #調用存儲過程 call p1();
3、創建有參數存儲過程
有參數的情況時,在定義存儲過程中必須定義參數的類型,包含三種,解釋如下:
#in 僅用於傳入參數用 #out 僅用於返回值用 #inout 既可以傳入又可以當作返回值
應用實例:
#創建有參存儲過程 delimiter $$ create procedure p2( in x char(5), out y int ) begin select cid from course where cname=x; set y=1; end $$ delimiter ; #mysql中調用: set @x=‘生物‘; set @y=0; call p2(@x,@y); #查看返回值 select @y; #pymysql中的調用: import pymysql conn=pymysql.connect( host=‘localhost‘, port=3306, user=‘root‘, password=‘‘, database=‘day48‘, charset=‘utf8‘ ) cur=conn.cursor() #拿到存儲過程sql語句的執行結果 cur.callproc(‘p2‘,(‘生物‘,0)) print(cur.fetchall())
#拿到存儲過程返回值 ‘‘‘pymysql默認會把參數變為如下形式名字,分別為生物和0的名字:@_p2_0 ,@_p2_1;‘‘‘ cur.execute(‘select @_p2_1;‘) print(cur.fetchone()) cur.close() conn.close()
帶事務存儲過程實例:
#介紹 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 -- ERROR set p_return_code = 1; rollback; END; DECLARE exit handler for sqlwarning BEGIN -- WARNING set p_return_code = 2; rollback; END; START TRANSACTION; DELETE from tb1; #執行失敗 insert into blog(name,sub_time) values(‘yyy‘,now()); COMMIT; -- SUCCESS set p_return_code = 0; #0代表執行成功 END // delimiter ; #在mysql中調用存儲過程 set @res=123; call p5(@res); select @res; #在python中基於pymysql調用存儲過程 cursor.callproc(‘p5‘,(123,)) print(cursor.fetchall()) #查詢select的查詢結果 cursor.execute(‘select @_p5_0;‘) print(cursor.fetchall())
4、刪除存儲過程
drop procedure proc_name;
Python Day48 mysql補充