MySQL可更新檢視
阿新 • • 發佈:2019-02-06
可更新檢視是指通過檢視,來更新、插入、刪除基本表中的資料。檢視是一個虛擬表,即對檢視的更新,實質上是更新基表。但是檢視的構造很多時候是由多個表連線查詢,以及結合聚合函式,分組過濾等等定義的。對於這類的檢視,想要去更新,恐怕就顯得力不從心了。因為涉及到多張表。本文簡要描述可更新檢視的特點並給出演示。
一、不帶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進作用於當前