13.1.12 CREATE EVENT 语句

CREATE
    [DEFINER = user]
    EVENT
    [IF NOT EXISTS]
    event_name
    ON SCHEDULE schedule
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE | DISABLE ON 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}

该语句创建并安排新事件。除非启用了事件计划程序,否则事件将不会运行。有关检查事件计划程序状态并在必要时启用它的信息,请参阅第 23.4.2 节“事件调度程序配置”

CREATE EVENT要求具有在其中创建事件的架构的EVENT特权。如果存在DEFINER子句,则所需的特权取决于* user *值,如第 23.6 节“存储的对象访问控制”中所述。

有效的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的事件。通过运行一条将myschema.mytabletable 的mycol列的值增加 1 的 SQL 语句,此事件在创建后一小时内执行一次。

  • event_name *必须是有效的 MySQL 标识符,最大长度为 64 个字符。事件名称不区分大小写,因此在同一架构中不能有两个名为myeventMyEvent的事件。通常,控制事件名称的规则与存储例程名称的规则相同。参见第 9.2 节“架构对象名称”

事件与模式关联。如果没有模式指示为* event_name *的一部分,则假定为默认(当前)模式。要在特定架构中创建事件,请使用schema_name.event_name语法用架构限定事件名称。

DEFINER子句指定在事件执行时检查访问权限时要使用的 MySQL 帐户。如果存在DEFINER子句,则* user 值应为指定为'user_name'@'host_name'CURRENT_USERCURRENT_USER()的 MySQL 帐户。允许的 user *值取决于您所拥有的特权,如第 23.6 节“存储的对象访问控制”中所述。另请参阅该部分以获取有关事件安全性的其他信息。

如果省略DEFINER子句,则默认定义器是执行CREATE EVENT语句的用户。这与显式指定DEFINER = CURRENT_USER相同。

在事件主体内,CURRENT_USER函数返回用于在事件执行时检查特权的帐户,该帐户是DEFINER用户。有关事件内用户审核的信息,请参见第 6.2.18 节“基于 SQL 的帐户活动审核”

IF NOT EXISTSCREATE EVENT的含义与CREATE TABLE的含义相同:如果在同一模式中已经存在名为* event_name *的事件,则不会执行任何操作,也不会导致错误。 (但是,在这种情况下会生成警告.)

ON SCHEDULE子句确定为事件定义的* event_body *重复的时间,频率和持续时间。此子句采用以下两种形式之一:

  • AT timestamp用于一次性事件。它指定事件仅在* timestamp *给定的日期和时间执行一次,该时间必须同时包括日期和时间,或者必须是可解析为 datetime 值的 table 达式。为此,您可以使用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指定当前日期和时间。在这种情况下,事件在创建后立即起作用。

要创建相对于当前日期和时间在将来某个时间发生的事件(例如用短语“从现在开始三周”table 示的事件),可以使用可选的子句+ INTERVAL interval。 * interval *部分由数量和时间单位两部分组成,并遵循Temporal Intervals中描述的语法规则,除了在定义事件时不能使用任何涉及微秒的单位关键字。对于某些间隔类型,可以使用复杂的时间单位。例如,“两分钟十秒”可以 table 示为+ INTERVAL '2:10' MINUTE_SECOND

您也可以合并间隔。例如,AT CURRENT_TIMESTAMP + INTERVAL 3 WEEK + INTERVAL 2 DAY等效于“从现在起三周零两天”。该子句的每个部分都必须以+ INTERVAL开头。

  • 要定期重复执行操作,请使用EVERY子句。 EVERY关键字后跟* interval *,如先前对AT关键字的讨论中所述。 (+ INTERVAL不能与EVERY一起使用.)例如,EVERY 6 WEEKtable 示“每六个星期”。

尽管EVERY子句中不允许使用+ INTERVAL子句,但是您可以使用+ INTERVAL中允许的相同复杂时间单位。

EVERY子句可以包含可选的STARTS子句。 STARTS后跟一个* timestamp *值,该值指示何时应开始重复该操作,并且还可以使用+ INTERVAL interval指定“从现在开始”的时间。例如,EVERY 3 MONTH STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEKtable 示“每三个月,从现在开始的一个星期开始”。同样,您可以将EVERY 2 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL '6:15' HOUR_MINUTEtable 示为“每两周,从现在开始六小时十五分钟”。未指定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等价于“每 12 个小时,从现在开始 30 分钟,到现在 4 周结束”。不使用ENDS意味着事件将无限期 continue 执行。

ENDS支持复杂时间单位的语法与STARTS支持相同的语法。

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

如果重复事件未在其调度间隔内终止,则结果可能是事件的多个实例同时执行。如果这是不希望的,则应构建一种机制来防止同时发生实例。例如,您可以使用GET_LOCK()函数或行或 table 锁定。

ON SCHEDULE子句可以使用涉及内置 MySQL 函数和用户变量的 table 达式来获取其中包含的* timestamp interval *值中的任何一个。您不得在此类 table 达式中使用存储的函数或用户定义的函数,也不得使用任何 table 引用。但是,您可以使用SELECT FROM DUALCREATE EVENTALTER EVENT语句均是如此。在这种情况下,明确不允许引用存储的函数,用户定义的函数和 table,并且它们会因错误而失败(请参见 Bug#22830)。

ON SCHEDULE子句中的时间使用当前会话time_zone值进行解释。这成为事件时区;也就是说,用于事件调度的时区,在事件执行时有效。这些时间将转换为 UTC,并与事件时区一起存储在mysql.eventtable 中。这使得事件执行可以按定义进行,而不管服务器时区的任何后续更改或夏令时影响如何。有关事件时间 table 示的其他信息,请参见第 23.4.4 节“事件元数据”。另请参见第 13.7.5.18 节“ SHOW EVENTS 语句”第 24.8 节““ INFORMATION_SCHEMA 事件”table”

通常,一旦事件过期,它将立即被丢弃。您可以通过指定ON COMPLETION PRESERVE来覆盖此行为。使用ON COMPLETION NOT PRESERVE只会使默认的非持久行为明确。

您可以创建事件,但可以使用DISABLE关键字阻止其活动。或者,您可以使用ENABLE明确显示默认状态,该状态为活动状态。与ALTER EVENT(请参见第 13.1.2 节“ ALTER EVENT 语句”)结合使用时,此功能最为有用。

第三个值也可能代替ENABLEDISABLE出现;将DISABLE ON SLAVE设置为复制从属服务器上的事件状态,以指示该事件已在主服务器上创建并复制到从属服务器,但未在从属服务器上执行。参见第 16.4.1.16 节,“调用功能的复制”

您可以使用COMMENT子句为事件提供 Comments。 * comment *可以是您要用来描述事件的最多 64 个字符的任何字符串。Comments 文本是字符串 Literals,必须用引号引起来。

DO子句指定事件所执行的操作,并包含一个 SQL 语句。几乎可以在存储例程中使用的任何有效 MySQL 语句也可以用作计划事件的操作语句。 (请参阅第 23.8 节“对存储程序的限制”。)例如,以下事件e_hourly每小时一次从sessionstable 中删除所有行,其中该 table 是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语句似乎成功;但是,当服务器尝试执行生成的计划事件时,执行失败并显示错误。

Note

诸如SELECTSHOW之类的语句仅在事件中使用时不返回结果集;它们的输出不会发送到 MySQL Monitor,也不会存储在任何地方。但是,您可以使用诸如选择...进入插入...选择之类的语句来存储结果。 (有关后者的实例,请参阅本节中的下一个示例.)

事件所属的架构是DO子句中 table 引用的默认架构。对其他架构中的 table 的任何引用都必须使用正确的架构名称进行限定。

与存储例程一样,可以通过使用BEGINEND关键字在DO子句中使用复合语句语法,如下所示:

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命令更改语句定界符。参见第 23.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);

如果事件的定义者具有足以设置全局系统变量的特权(请参见第 5.1.8.1 节“系统变量特权”),则该事件可以读取和写入全局变量。由于授予此类特权可能会导致滥用行为,因此必须格外小心。

通常,在存储的例程中有效的任何语句都可以用于事件执行的动作语句。有关存储例程中允许的语句的更多信息,请参见第 23.2.1 节“存储的例程语法”。您可以将事件创建为存储例程的一部分,但是另一个事件不能创建一个事件。