小巧、快速、可靠。
選擇其中三項。
建立觸發程序 (CREATE TRIGGER)

1. 語法

create-trigger-stmt (建立觸發程序陳述式)

CREATE TEMP TEMPORARY TRIGGER IF NOT EXISTS schema-name . trigger-name BEFORE AFTER INSTEAD OF DELETE INSERT UPDATE OF column-name , ON table-name FOR EACH ROW WHEN expr BEGIN update-stmt ; END insert-stmt delete-stmt select-stmt

delete-stmt (刪除陳述式)

expr (表達式)

insert-stmt (插入陳述式)

select-stmt (選擇陳述式)

update-stmt (更新陳述式)

2. 說明

CREATE TRIGGER 陳述式用於將觸發程序新增至資料庫結構描述。觸發程序是在發生指定的資料庫事件時自動執行的資料庫操作。

每個觸發程序都必須指定它將針對下列其中一個操作觸發:DELETE (刪除)INSERT (插入)UPDATE (更新)。觸發程序會針對刪除、插入或更新的每一列觸發一次。如果使用 "UPDATE OF 欄位名稱" 語法,則觸發程序只會在 欄位名稱 出現在 UPDATE 陳述式之 SET 子句其中一個條件的左側時才會觸發。

由於歷史上的疏忽,「UPDATE OF」子句中命名的欄位實際上不必存在於正在更新的資料表中。無法辨識的欄位名稱會被靜默忽略。如果 SQLite 在「UPDATE OF」子句中的任何名稱不是資料表中的欄位時,使 CREATE TRIGGER 陳述式失敗會更有幫助。然而,由於這個問題是在 SQLite 廣泛部署多年後才發現的,因此我們一直避免修復這個問題,以免破壞舊版應用程式。

目前 SQLite 只支援 FOR EACH ROW 觸發程序,而不支援 FOR EACH STATEMENT 觸發程序。因此,明確指定 FOR EACH ROW 是可選的。FOR EACH ROW 表示觸發程序中指定的 SQL 陳述式可能會針對導致觸發程序觸發的陳述式所插入、更新或刪除的每個資料庫列執行(取決於 WHEN 子句)。

WHEN 子句和觸發程序動作都可以使用 "NEW.欄位名稱" 和 "OLD.欄位名稱" 形式的參考來存取正在插入、刪除或更新的列的元素,其中 欄位名稱 是觸發程序關聯之資料表中欄位的名稱。OLD 和 NEW 參考只能在與它們相關的事件觸發程序中使用,如下所示:

INSERT (插入) NEW 參考有效
UPDATE (更新) NEW 和 OLD 參考有效
DELETE (刪除) OLD 參考有效

如果提供了 WHEN 子句,則只有在 WHEN 子句為 true 時才會執行指定的 SQL 陳述式。如果沒有提供 WHEN 子句,則每次觸發程序觸發時都會執行 SQL 陳述式。

BEFORE 或 AFTER 關鍵字決定觸發程序動作相對於關聯列的插入、修改或移除的執行時間。如果沒有出現任何關鍵字,則預設為 BEFORE。

在觸發器主體內的 UPDATEINSERT 動作中,可以指定 ON CONFLICT 子句。但是,如果在觸發觸發器的語句中指定了 ON CONFLICT 子句,則會改用外部語句的衝突處理策略。

當觸發器關聯的表格(表格名稱 表格)被 刪除 時,觸發器會自動 刪除。但是,如果觸發器動作參考其他表格,則在 刪除修改 這些其他表格時,觸發器不會被刪除或修改。

可以使用 DROP TRIGGER 語句移除觸發器。

2.1. 觸發器內 UPDATE、DELETE 和 INSERT 語句的語法限制

觸發器內的 UPDATEDELETEINSERT 語句不支援 UPDATEDELETEINSERT 語句的完整語法。以下限制適用:

3. INSTEAD OF 觸發器

BEFORE 和 AFTER 觸發器僅適用於一般表格。INSTEAD OF 觸發器僅適用於檢視表。

如果檢視表上存在 INSTEAD OF INSERT 觸發器,則可以對該檢視表執行 INSERT 語句。不會發生實際的插入。而是會執行觸發器中包含的語句。INSTEAD OF DELETE 和 INSTEAD OF UPDATE 觸發器以相同的方式作用於針對檢視表的 DELETE 和 UPDATE 語句。

請注意,sqlite3_changes()sqlite3_total_changes() 介面不會計算 INSTEAD OF 觸發器的觸發次數,但 count_changes pragma 會計算 INSTEAD OF 觸發器的觸發次數。

4. 一些觸發器範例

假設客戶記錄儲存在「customers」表格中,訂單記錄儲存在「orders」表格中,則以下 UPDATE 觸發器可確保在客戶更改其地址時,所有關聯的訂單都會被重新導向:

CREATE TRIGGER update_customer_address UPDATE OF address ON customers 
  BEGIN
    UPDATE orders SET address = new.address WHERE customer_name = old.name;
  END;

安裝此觸發器後,執行以下語句:

UPDATE customers SET address = '1 Main St.' WHERE name = 'Jack Jones';

會導致自動執行以下操作:

UPDATE orders SET address = '1 Main St.' WHERE customer_name = 'Jack Jones';

關於 INSTEAD OF 觸發器的範例,請參考以下綱要:

CREATE TABLE customer(
  cust_id INTEGER PRIMARY KEY,
  cust_name TEXT,
  cust_addr TEXT
);
CREATE VIEW customer_address AS
   SELECT cust_id, cust_addr FROM customer;
CREATE TRIGGER cust_addr_chng
INSTEAD OF UPDATE OF cust_addr ON customer_address
BEGIN
  UPDATE customer SET cust_addr=NEW.cust_addr
   WHERE cust_id=NEW.cust_id;
END;

使用上述綱要,以下形式的語句:

UPDATE customer_address SET cust_addr=$new_address WHERE cust_id=$cust_id;

會更新特定客戶條目的 customer.cust_addr 欄位,其中 customer.cust_id 等於 $cust_id 參數。請注意,指派給檢視的值如何在觸發器主體內的特殊「NEW」表格中作為欄位提供。

5. 使用 BEFORE 觸發器的注意事項

如果 BEFORE UPDATE 或 BEFORE DELETE 觸發器修改或刪除將要被更新或刪除的資料列,則後續更新或刪除操作的結果未定義。此外,如果 BEFORE 觸發器修改或刪除資料列,則未定義原本會在這些資料列上執行的 AFTER 觸發器是否實際執行。

在未明確將 rowid 設定為整數的 BEFORE INSERT 觸發器中,NEW.rowid 的值未定義。

由於上述行為,建議程式設計師優先使用 AFTER 觸發器,而非 BEFORE 觸發器。

6. RAISE() 函式

可以在觸發器程式中使用特殊的 SQL 函式 RAISE(),語法如下

raise-function (raise 函式)

RAISE ( ROLLBACK , error-message ) IGNORE ABORT FAIL

當在觸發器程式執行期間呼叫 RAISE(ROLLBACK,...)、RAISE(ABORT,...) 或 RAISE(FAIL,...) 其中之一時,會執行指定的 ON CONFLICT 處理,並且目前查詢會終止。錯誤碼 SQLITE_CONSTRAINT 與指定的錯誤訊息會返回應用程式。

當呼叫 RAISE(IGNORE) 時,目前觸發器程式的其餘部分、導致觸發器程式執行的陳述式以及任何後續將會執行的觸發器程式都會被放棄。不會rollback任何資料庫變更。如果導致觸發器程式執行的陳述式本身是觸發器程式的一部分,則該觸發器程式會從下一步開始繼續執行。

7. 非 TEMP 資料表上的 TEMP 觸發器

觸發器通常存在於與 CREATE TRIGGER 陳述式中「ON」關鍵字後命名的資料表相同的資料庫中。但可以在另一個資料庫的資料表上建立 TEMP 觸發器。這樣的觸發器只會在定義觸發器的應用程式變更目標資料表時觸發。修改資料庫的其他應用程式將無法看到 TEMP 觸發器,因此無法執行觸發器。

在非 TEMP 資料表上定義 TEMP 觸發器時,務必指定包含非 TEMP 資料表的資料庫。例如,在以下陳述式中,務必使用「main.tab1」而不是僅使用「tab1」

CREATE TEMP TRIGGER ex1 AFTER INSERT ON main.tab1 BEGIN ...

如果未在目標資料表上指定結構描述名稱,則每當發生任何結構描述變更時,TEMP 觸發器可能會重新附加到另一個資料庫中同名的資料表。

本頁面最後修改時間:2024-08-03 15:33:40 UTC