1. 程式人生 > >MySQL可更新檢視

MySQL可更新檢視

可更新檢視是指通過檢視,來更新、插入、刪除基本表中的資料。檢視是一個虛擬表,即對檢視的更新,實質上是更新基表。但是檢視的構造很多時候是由多個表連線查詢,以及結合聚合函式,分組過濾等等定義的。對於這類的檢視,想要去更新,恐怕就顯得力不從心了。因為涉及到多張表。本文簡要描述可更新檢視的特點並給出演示。

一、不帶check option更新

-- 當前環境
mysql> show variables like 'version';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| version | 5.7.17 | +---------------+--------+ -- 可更新檢視演示 DROP TABLE IF EXISTS items; CREATE TABLE items ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, price DECIMAL(11, 2) NOT NULL ); -- 為items表填充資料 INSERT INTO items(name, price) VALUES ('Laptop', 700.56), ('Desktop', 699.99), ('iPad'
, 700.50); CREATE OR REPLACE VIEW vw_items AS SELECT * FROM items WHERE price > 700; -- 查詢檢視 SELECT * FROM vw_items; -- 以下語句插入成功,基表和檢視同時可見 INSERT INTO vw_items VALUES (NULL, 'iPhone', 800.50); -- 以下語句插入成功,基表可見,因為檢視包含了where子句對其過濾 INSERT INTO vw_items VALUES (NULL, 'iPhone4', 500.50); -- Query OK, 1 row affected (0.00 sec) SELECT * FROM vw_items;

二、基於check option更新

-- 先清空一下資料

TRUNCATE TABLE items;

CREATE OR REPLACE VIEW vw_items_check
AS
   SELECT *
   FROM items
   WHERE price > 700
   WITH CHECK OPTION;

-- 下面基於vw_items_check建立另外一個檢視vw_items_check2
CREATE OR REPLACE VIEW vw_items_check2
AS
   SELECT *
   FROM vw_items_check
   WHERE price < 1000
   WITH LOCAL CHECK OPTION;

-- 下面基於vw_items_check建立另外一個檢視vw_items_check3
CREATE OR REPLACE VIEW vw_items_check3
AS
   SELECT *
   FROM vw_items_check
   WHERE price < 1000
   WITH CASCADED CHECK OPTION;

-- 基於檢視vw_items_check插入資料,以下語句插入失敗,不符合檢視過濾條件
INSERT INTO vw_items_check
VALUES (NULL, 'Laptop', 600.56);

-- ERROR 1369 (HY000): CHECK OPTION failed 'sakila.vw_items_check'

-- 基於檢視vw_items_check插入資料,以下語句執行成功
-- 滿足where子句過濾條件,插入後基表和檢視資料可見
INSERT INTO vw_items_check
VALUES (NULL, 'Laptop', 700.56);

-- 基於檢視vw_items_check2插入資料成功,值符合過濾條件
INSERT INTO vw_items_check2
VALUES (NULL, 'iPhone', 800.50);

-- 基於檢視vw_items_check3插入資料成功,值符合過濾條件
INSERT INTO vw_items_check3
VALUES (NULL, 'iPhone3', 800.50);

-- 下面使用一個不符合預期的值進行插入
-- 基於檢視vw_items_check2插入資料失敗,值不符合底層過濾條件
INSERT INTO vw_items_check2
VALUES (NULL, 'iPhone_chk2', 700);

-- ERROR 1369 (HY000): CHECK OPTION failed 'sakila.vw_items_check2'

-- 基於檢視vw_items_check3插入資料失敗,值不符合底層過濾條件
INSERT INTO vw_items_check3
VALUES (NULL, 'iPhone_chk2', 700);

-- ERROR 1369 (HY000): CHECK OPTION failed 'sakila.vw_items_check3'

-- 通過上面的測試發現,使用CASCADED與LOCAL建立的檢視都會檢查底層依賴
-- 在此並無特別
-- 說明5.7.6版本以前,檢視vw_items_check2不符合底層預期時,也可以成功執行

三、進一步測試對比CASCADED與LOCAL

-- 再次建立如下檢視,此時的檢視底層基於非check檢視

CREATE OR REPLACE VIEW vw_items_check4
AS
   SELECT *
   FROM vw_items
   WHERE price < 1000
   WITH LOCAL CHECK OPTION;

CREATE OR REPLACE VIEW vw_items_check5
AS
   SELECT *
   FROM vw_items
   WHERE price < 1000
   WITH CASCADED CHECK OPTION;

-- 基於檢視vw_items_check4插入資料成功,值不符合底層過濾條件
-- 但是此時可以成功插入,說明local生效,不依賴底層過濾條件    
INSERT INTO vw_items_check4
VALUES (NULL, 'iPhone_chk4', 700);    

Query OK, 1 row affected (0.00 sec)

-- 下面驗證插入結果,查詢vw_items_check4被過濾
SELECT * FROM vw_items_check4;
+----+---------+--------+
| id | name | price |
+----+---------+--------+
| 1 | Laptop | 700.56 |
| 2 | iPhone | 800.50 |
| 3 | iPhone3 | 800.50 |
+----+---------+--------+

-- 查詢基表資料存在
SELECT * FROM items;
+----+-------------+--------+
| id | name | price |
+----+-------------+--------+
| 1 | Laptop | 700.56 |
| 2 | iPhone | 800.50 |
| 3 | iPhone3 | 800.50 |
| 4 | iPhone_chk4 | 700.00 |
+----+-------------+--------+

-- 基於檢視vw_items_check5插入資料失敗,cascade級聯校驗生效
INSERT INTO vw_items_check5
VALUES (NULL, 'iPhone_chk5', 700);

-- ERROR 1369 (HY000): CHECK OPTION failed 'sakila.vw_items_check5'

四、基於檢視刪除

-- 基於檢視vw_items_check4刪除資料
-- 如下,提示刪除成功,但基表資料未刪除,因為不滿足過濾條件
DELETE FROM vw_items_check4
WHERE id = 4;

-- Query OK, 0 rows affected (0.00 sec)

-- Author : Leshami
-- Blog : http://blog.csdn.net/leshami

-- 基於檢視vw_items_check5刪除資料
-- 如下,提示刪除成功,但基表資料未刪除,因為不滿足過濾條件
DELETE FROM vw_items_check5
WHERE id = 4;

-- Query OK, 0 rows affected (0.00 sec)

-- 滿足過濾條件 id為3的記錄能夠被刪除
DELETE FROM vw_items_check5
WHERE id = 3;

-- Query OK, 1 row affected (0.00 sec)

-- 刪除後的結果
SELECT * FROM items;
+----+-------------+--------+
| id | name | price |
+----+-------------+--------+
| 1 | Laptop | 700.56 |
| 2 | iPhone | 800.50 |
| 4 | iPhone_chk4 | 700.00 |
+----+-------------+--------+

五、更新檢視

-- 由於不符合過濾條件,2個檢視均無法更新
UPDATE vw_items_check5
SET price = 701
WHERE id = 4;    

Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0

UPDATE vw_items_check4
SET price = 701
WHERE id = 4;   

Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0

-- 基於檢視vw_items5更新資料,此時選擇滿足條件的記錄來更新
-- 更新為比過濾條件低的價格,無法成功更新
UPDATE vw_items_check5
SET price = 700
WHERE id = 2; 

ERROR 1369 (HY000): CHECK OPTION failed 'sakila.vw_items_check5'

-- 更新為符合條件時,被成功更新
UPDATE vw_items_check5
SET price = 900
WHERE id = 2;

Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

六、cascade 與local的差異(官方描述)

-- 未指定local與cascade時,預設為cascade
-- 官方給出的關於LOCAL與CASCADED對比
/*

• With LOCAL, the view WHERE clause is checked, then checking recurses to underlying views and
applies the same rules.

• With CASCADED, the view WHERE clause is checked, then checking recurses to underlying views,
adds WITH CASCADED CHECK OPTION to them (for purposes of the check; their definitions remain
unchanged), and applies the same rules.

• With no check option, the view WHERE clause is not checked, then checking recurses to underlying
views, and applies the same rules.
*/

七、結論:

1、不使用check子句情形,可以對檢視進行DML操作,影響基表資料
2、使用check子句情形,所有的DML必須滿足過濾條件,否則報錯,update語句更新後的值不符合過濾條件則無法更新
3、LOCAL與CASCADED選項受底層檢視影響,如果底層檢視帶check,則兩者作用相同,否則LOCAL進作用於當前