文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  CREATE EVENT 語法

15.1.13 CREATE EVENT 語法

CREATE
    [DEFINER = user]
    EVENT
    [IF NOT EXISTS]
    event_name
    ON SCHEDULE schedule
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE | DISABLE ON {REPLICA | SLAVE}]
    [COMMENT 'string']
    DO event_body;

schedule: {
    AT timestamp [+ INTERVAL interval] ...
  | EVERY interval
    [STARTS timestamp [+ INTERVAL interval] ...]
    [ENDS timestamp [+ INTERVAL interval] ...]
}

interval:
    quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
              WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
              DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

此語句會建立並排程一個新的事件。除非啟用事件排程器,否則事件不會執行。如需關於檢查事件排程器狀態以及在必要時啟用它的資訊,請參閱第 27.5.2 節「事件排程器組態」

CREATE EVENT 需要在要建立事件的結構描述中具有 EVENT 權限。如果存在 DEFINER 子句,則所需的權限取決於 user 值,如第 27.7 節「已儲存物件存取控制」中所述。

有效的 CREATE EVENT 語句的最低要求如下

  • 關鍵字 CREATE EVENT 加上事件名稱,該名稱唯一識別資料庫結構描述中的事件。

  • 一個 ON SCHEDULE 子句,決定事件執行的時間和頻率。

  • 一個 DO 子句,其中包含事件要執行的 SQL 語句。

這是一個最小的 CREATE EVENT 語句範例

CREATE EVENT myevent
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
    DO
      UPDATE myschema.mytable SET mycol = mycol + 1;

先前的語句建立一個名為 myevent 的事件。此事件會執行一次,在建立後一小時執行,方法是執行一個 SQL 語句,將 myschema.mytable 資料表的 mycol 欄位的值遞增 1。

event_name 必須是有效的 MySQL 識別符號,最大長度為 64 個字元。事件名稱不區分大小寫,因此您無法在同一個結構描述中擁有兩個名為 myeventMyEvent 的事件。一般來說,管理事件名稱的規則與管理預存常式的名稱的規則相同。請參閱第 11.2 節「結構描述物件名稱」

事件與結構描述相關聯。如果未指示結構描述作為 event_name 的一部分,則會假設預設 (目前) 結構描述。若要在特定結構描述中建立事件,請使用 schema_name.event_name 語法以結構描述限定事件名稱。

DEFINER 子句指定在事件執行時檢查存取權限時要使用的 MySQL 帳戶。如果存在 DEFINER 子句,則 user 值應為指定為 'user_name'@'host_name'CURRENT_USERCURRENT_USER() 的 MySQL 帳戶。允許的 user 值取決於您擁有的權限,如第 27.7 節「已儲存物件存取控制」中所述。另請參閱該節以取得關於事件安全性的其他資訊。

如果省略 DEFINER 子句,則預設的定義者是執行 CREATE EVENT 語句的使用者。這與明確指定 DEFINER = CURRENT_USER 相同。

在事件主體中,CURRENT_USER 函數會傳回在事件執行時用來檢查權限的帳戶,也就是 DEFINER 使用者。如需關於事件內的使用者稽核的資訊,請參閱第 8.2.23 節「以 SQL 為基礎的帳戶活動稽核」

IF NOT EXISTS 對於 CREATE EVENT 的意義與對於 CREATE TABLE 的意義相同:如果名為 event_name 的事件已存在於相同的結構描述中,則不會採取任何動作,且不會產生錯誤。(但是,在這種情況下會產生警告。)

ON SCHEDULE 子句會決定為事件定義的 event_body 重複的時間、頻率和持續時間。此子句採用兩種形式之一

  • AT timestamp 用於一次性事件。它指定事件僅在 timestamp 給定的日期和時間執行一次,其中必須包含日期和時間,或是必須解析為日期時間值的運算式。您可以為此目的使用 DATETIMETIMESTAMP 類型的任一值。如果日期在過去,則會發生警告,如下所示

    mysql> SELECT NOW();
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2006-02-10 23:59:01 |
    +---------------------+
    1 row in set (0.04 sec)
    
    mysql> CREATE EVENT e_totals
        ->     ON SCHEDULE AT '2006-02-10 23:59:00'
        ->     DO INSERT INTO test.totals VALUES (NOW());
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Note
       Code: 1588
    Message: Event execution time is in the past and ON COMPLETION NOT
             PRESERVE is set. The event was dropped immediately after
             creation.

    本身無效的 CREATE EVENT 語句(無論任何原因)都會失敗並產生錯誤。

    您可以使用 CURRENT_TIMESTAMP 來指定目前的日期和時間。在這種情況下,事件會在建立後立即執行。

    若要建立在相對於目前日期和時間的未來某個時間點發生的事件 (例如,以短語 三週後 表示的事件),您可以使用選擇性子句 + INTERVAL intervalinterval 部分包含兩個部分,一個數量和一個時間單位,並遵循時間間隔中描述的語法規則,但您在定義事件時不能使用任何涉及微秒的時間單位關鍵字。使用某些間隔類型時,可能會使用複雜的時間單位。例如,兩分鐘又十秒可以表示為 + INTERVAL '2:10' MINUTE_SECOND

    您也可以結合間隔。例如,AT CURRENT_TIMESTAMP + INTERVAL 3 WEEK + INTERVAL 2 DAY 等同於三週又兩天後。此類子句的每個部分都必須以 + INTERVAL 開頭。

  • 若要以固定間隔重複動作,請使用 EVERY 子句。EVERY 關鍵字後面接著一個 interval,如先前關於 AT 關鍵字的討論中所述。(+ INTERVAL EVERY 一起使用。)例如,EVERY 6 WEEK 表示 每六週

    雖然 + INTERVAL 子句在 EVERY 子句中不允許,但您可以使用 + INTERVAL 中允許的相同複雜時間單位。

    EVERY 子句可能包含選擇性的 STARTS 子句。STARTS 後面接著一個 timestamp 值,指示動作應開始重複的時間,並且也可以使用 + INTERVAL interval 來指定 從現在開始的時間量。例如,EVERY 3 MONTH STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEK 表示 每三個月,從現在起一週後開始。同樣地,您可以將 每兩週,從現在起六小時又十五分鐘後開始表示為 EVERY 2 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL '6:15' HOUR_MINUTE。不指定 STARTS 與使用 STARTS CURRENT_TIMESTAMP 相同,也就是說,為事件指定的動作會在事件建立後立即開始重複。

    EVERY 子句可能包含選擇性的 ENDS 子句。ENDS 關鍵字後面接著一個 timestamp 值,告知 MySQL 事件應停止重複的時間。您也可以將 + INTERVAL intervalENDS 一起使用;例如,EVERY 12 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 30 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 4 WEEK 等同於 每十二小時,從現在起三十分鐘後開始,並從現在起四週後結束。不使用 ENDS 表示事件會無限期地繼續執行。

    ENDS 支援與 STARTS 相同的複雜時間單位語法。

    您可以在 EVERY 子句中使用 STARTSENDS、兩者都使用或兩者都不使用。

    如果重複事件未在其排程間隔內終止,則可能會同時執行事件的多個執行個體。如果這是不理想的,您應該建立一個機制來防止同時發生多個執行個體。例如,您可以使用 GET_LOCK() 函數,或是資料列或資料表鎖定。

ON SCHEDULE 子句可以使用涉及內建 MySQL 函數和使用者變數的運算式,以取得其包含的任何 timestampinterval 值。您不得在此類運算式中使用預存函數或可載入函數,也不得使用任何資料表參照;但是,您可以使用 SELECT FROM DUAL。對於 CREATE EVENTALTER EVENT 語句來說,都是如此。在此類情況下,明確不允許參照預存函數、可載入函數和資料表,且會失敗並產生錯誤 (請參閱錯誤 #22830)。

ON SCHEDULE 子句中指定的時間會使用目前連線的 time_zone 值來解釋。這會成為事件時區;也就是說,用於事件排程並在事件執行時生效的時區。這些時間會被轉換為 UTC 並與事件時區一同儲存在內部。這使得事件執行可以按照定義進行,而無論後續對伺服器時區或日光節約時間的影響做出任何變更。關於事件時間表示的更多資訊,請參閱 第 27.5.4 節,「事件元數據」。另請參閱 第 15.7.7.19 節,「SHOW EVENTS 陳述式」,以及 第 28.3.14 節,「INFORMATION_SCHEMA EVENTS 表格」

通常,一旦事件過期,它會立即被刪除。您可以透過指定 ON COMPLETION PRESERVE 來覆蓋此行為。使用 ON COMPLETION NOT PRESERVE 僅僅是明確指出預設的非持久性行為。

您可以使用 DISABLE 關鍵字建立一個事件,但阻止其處於活動狀態。或者,您可以使用 ENABLE 來明確指出預設的狀態,即活動狀態。這在與 ALTER EVENT 結合使用時最為有用(請參閱 第 15.1.3 節,「ALTER EVENT 陳述式」)。

第三個值也可以出現在 ENABLEDISABLE 的位置;DISABLE ON REPLICA 設定為副本上事件的狀態,表示該事件是在複製來源伺服器上建立並複製到副本,但不會在副本上執行。請參閱 第 19.5.1.16 節,「已調用功能的複製」

DISABLE ON REPLICA 取代了已棄用的 DISABLE ON SLAVE,因此在未來版本的 MySQL 中可能會被移除。

您可以使用 COMMENT 子句為事件提供註解。comment 可以是任何最多 64 個字元的字串,您可以用於描述事件。註解文字是字串常值,必須用引號括起來。

DO 子句指定由事件執行的動作,並包含一個 SQL 陳述式。幾乎任何可以在儲存程序中使用的有效 MySQL 陳述式也可以用作排程事件的動作陳述式。(請參閱 第 27.9 節,「儲存程序的限制」。)例如,以下事件 e_hourly 每小時會從 sessions 表格中刪除所有列,而此表格是 site_activity 綱要的一部分。

CREATE EVENT e_hourly
    ON SCHEDULE
      EVERY 1 HOUR
    COMMENT 'Clears out sessions table each hour.'
    DO
      DELETE FROM site_activity.sessions;

MySQL 會儲存建立或變更事件時生效的 sql_mode 系統變數設定,並始終以這個設定強制執行事件,無論事件開始執行時目前的伺服器 SQL 模式為何

DO 子句中包含 ALTER EVENT 陳述式的 CREATE EVENT 陳述式似乎會成功;但是,當伺服器嘗試執行產生的排程事件時,執行會失敗並產生錯誤。

注意

當在事件中使用時,諸如 SELECTSHOW 之類僅傳回結果集的陳述式無效;這些陳述式的輸出不會傳送到 MySQL 監視器,也不會儲存在任何地方。但是,您可以使用諸如 SELECT ... INTOINSERT INTO ... SELECT 之類的陳述式來儲存結果。(有關後者的範例,請參閱本節中的下一個範例。)

事件所屬的綱要是 DO 子句中表格參考的預設綱要。任何對其他綱要中表格的參考都必須使用正確的綱要名稱來限定。

與儲存程序一樣,您可以在 DO 子句中使用複合陳述式語法,方法是使用 BEGINEND 關鍵字,如下所示

delimiter |

CREATE EVENT e_daily
    ON SCHEDULE
      EVERY 1 DAY
    COMMENT 'Saves total number of sessions then clears the table each day'
    DO
      BEGIN
        INSERT INTO site_activity.totals (time, total)
          SELECT CURRENT_TIMESTAMP, COUNT(*)
            FROM site_activity.sessions;
        DELETE FROM site_activity.sessions;
      END |

delimiter ;

這個範例使用 delimiter 命令來變更陳述式分隔符號。請參閱 第 27.1 節,「定義儲存程序」

在事件中可以使用更複雜的複合陳述式,例如在儲存程序中使用的那些。此範例使用區域變數、錯誤處理常式和流程控制結構

delimiter |

CREATE EVENT e
    ON SCHEDULE
      EVERY 5 SECOND
    DO
      BEGIN
        DECLARE v INTEGER;
        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;

        SET v = 0;

        WHILE v < 5 DO
          INSERT INTO t1 VALUES (0);
          UPDATE t2 SET s1 = s1 + 1;
          SET v = v + 1;
        END WHILE;
    END |

delimiter ;

沒有辦法直接將參數傳遞到事件或從事件傳遞參數;但是,可以在事件中調用帶有參數的儲存程序

CREATE EVENT e_call_myproc
    ON SCHEDULE
      AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
    DO CALL myproc(5, 27);

在 MySQL 9.0 中,可以準備 CREATE EVENT 陳述式,但陳述式文字不得包含任何預留位置 (?)。解決此限制的一種方法是組合陳述式的文字,準備它,並在儲存程序中執行它;CREATE EVENT 陳述式的可變部分可以作為參數傳遞到儲存程序中。我們在以下範例中示範了這一點,此範例假設在資料庫 d 中已經存在一個表格 t,其建立方式如下所示

USE d;

CREATE TABLE t (
  c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  c2 VARCHAR(20),
  c3 INT
);

我們希望建立一個事件,該事件以在建立時確定的間隔將列插入此表格,類似於此處顯示的陳述式所定義的事件

CREATE EVENT e 
  ON SCHEDULE EVERY interval SECOND
  STARTS CURRENT_TIMESTAMP + INTERVAL 10 SECOND
  ENDS CURRENT_TIMESTAMP + INTERVAL 2 MINUTE
  ON COMPLETION PRESERVE
  DO
    INSERT INTO d.t1 VALUES ROW(NULL, NOW(), FLOOR(RAND()*100));

我們不能使用 ? 作為 interval 的預留位置,但我們可以將參數值傳遞給像這樣的一個儲存程序

delimiter |

CREATE PROCEDURE sp(n INT)
BEGIN
  SET @s1 = "CREATE EVENT e ON SCHEDULE EVERY ";
  SET @s2 = " SECOND
       STARTS CURRENT_TIMESTAMP + INTERVAL 10 SECOND
       ENDS CURRENT_TIMESTAMP + INTERVAL 2 MINUTE
       ON COMPLETION PRESERVE
       DO
       INSERT INTO d.t VALUES ROW(NULL, NOW(), FLOOR(RAND()*100))";
  
  SET @s = CONCAT(@s1, n, @s2);
  PREPARE ps FROM @s;
  EXECUTE ps;
  DEALLOCATE PREPARE ps;
END |

delimiter ;
mysql> TABLE t;
Empty set (0.00 sec)

mysql> CALL sp(5);
Query OK, 0 rows affected (0.01 sec)

# Wait 2 minutes...

mysql> TABLE t;
+----+---------------------+------+
| c1 | c2                  | c3   |
+----+---------------------+------+
|  1 | 2024-06-12 15:53:36 |   41 |
|  2 | 2024-06-12 15:53:41 |   84 |
|  3 | 2024-06-12 15:53:46 |   71 |
|  4 | 2024-06-12 15:53:51 |   78 |
|  5 | 2024-06-12 15:53:56 |   53 |
|  6 | 2024-06-12 15:54:01 |    6 |
|  7 | 2024-06-12 15:54:06 |   48 |
|  8 | 2024-06-12 15:54:11 |   98 |
|  9 | 2024-06-12 15:54:16 |   22 |
| 10 | 2024-06-12 15:54:21 |   88 |
| 11 | 2024-06-12 15:54:26 |   53 |
| 12 | 2024-06-12 15:54:31 |   75 |
| 13 | 2024-06-12 15:54:36 |   93 |
| 14 | 2024-06-12 15:54:41 |   13 |
| 15 | 2024-06-12 15:54:46 |   62 |
| 16 | 2024-06-12 15:54:51 |   47 |
| 17 | 2024-06-12 15:54:56 |   22 |
| 18 | 2024-06-12 15:55:01 |   47 |
| 19 | 2024-06-12 15:55:06 |   43 |
| 20 | 2024-06-12 15:55:11 |   50 |
| 21 | 2024-06-12 15:55:16 |   98 |
| 22 | 2024-06-12 15:55:21 |   15 |
| 23 | 2024-06-12 15:55:26 |   56 |
+----+---------------------+------+
23 rows in set (0.00 sec)

在使用引數值 5 調用 sp 後(如所示),並等待 2 分鐘直到事件 e 完成執行,我們可以發現表格 t 每 5 秒更新一次。由於 e 是以 ON COMPLETION PRESERVE 建立的,我們可以在資訊綱要的 EVENTS 表格中看到它,並驗證它是按照預期建立的

mysql> SELECT EVENT_NAME, EVENT_SCHEMA, EVENT_DEFINITION, EVENT_TYPE 
     > FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='e'\G
*************************** 1. row ***************************
      EVENT_NAME: e
    EVENT_SCHEMA: d
EVENT_DEFINITION: INSERT INTO d.t VALUES ROW(NULL, NOW(), FLOOR(RAND()*100))
      EVENT_TYPE: RECURRING
1 row in set (0.00 sec)

如果事件的定義者具有足夠的權限來設定全域系統變數(請參閱 第 7.1.9.1 節,「系統變數權限」),則事件可以讀取和寫入全域變數。由於授予此類權限會導致潛在的濫用,因此在執行此操作時必須格外小心。

通常,任何在儲存程序中有效的陳述式都可以用於事件執行的動作陳述式。有關儲存程序中允許的陳述式的更多資訊,請參閱 第 27.2.1 節,「儲存程序語法」。無法將事件建立為儲存程序的一部分,或透過另一個事件建立事件。