9.5 Expressions
本节列出了 MySQL 中 table 达式必须遵循的语法规则,并提供了有关 table 达式中可能出现的术语类型的其他信息。
Expression Syntax
以下语法规则定义了 MySQL 中的 table 达式语法。此处显示的语法基于 MySQL 源代码分发的sql/sql_yacc.yy
文件中给出的语法。有关某些 table 达方式的更多信息,请参见table 达术语 Comments。
expr:
expr OR expr
| expr || expr
| expr XOR expr
| expr AND expr
| expr && expr
| NOT expr
| ! expr
| boolean_primary IS [NOT] {TRUE | FALSE | UNKNOWN}
| boolean_primary
boolean_primary:
boolean_primary IS [NOT] NULL
| boolean_primary <=> predicate
| boolean_primary comparison_operator predicate
| boolean_primary comparison_operator {ALL | ANY} (subquery)
| predicate
comparison_operator: = | >= | > | <= | < | <> | !=
predicate:
bit_expr [NOT] IN (subquery)
| bit_expr [NOT] IN (expr [, expr] ...)
| bit_expr [NOT] BETWEEN bit_expr AND predicate
| bit_expr SOUNDS LIKE bit_expr
| bit_expr [NOT] LIKE simple_expr [ESCAPE simple_expr]
| bit_expr [NOT] REGEXP bit_expr
| bit_expr
bit_expr:
bit_expr | bit_expr
| bit_expr & bit_expr
| bit_expr << bit_expr
| bit_expr >> bit_expr
| bit_expr + bit_expr
| bit_expr - bit_expr
| bit_expr * bit_expr
| bit_expr / bit_expr
| bit_expr DIV bit_expr
| bit_expr MOD bit_expr
| bit_expr % bit_expr
| bit_expr ^ bit_expr
| bit_expr + interval_expr
| bit_expr - interval_expr
| simple_expr
simple_expr:
literal
| identifier
| function_call
| simple_expr COLLATE collation_name
| param_marker
| variable
| simple_expr || simple_expr
| + simple_expr
| - simple_expr
| ~ simple_expr
| ! simple_expr
| BINARY simple_expr
| (expr [, expr] ...)
| ROW (expr, expr [, expr] ...)
| (subquery)
| EXISTS (subquery)
| {identifier expr}
| match_expr
| case_expr
| interval_expr
有关运算符的优先级,请参见第 12.3.1 节“运算符优先级”。一些运算符的优先级和含义取决于 SQL 模式:
-
默认情况下,||是逻辑OR运算符。启用PIPES_AS_CONCAT时,||是字符串连接,优先级在^和一元运算符之间。
-
默认情况下,!的优先级高于
NOT
。启用HIGH_NOT_PRECEDENCE时,!和NOT
具有相同的优先级。
table 达术语 Comments
有关 Literals 值的语法,请参见第 9.1 节“文学价值”。
有关标识符语法,请参见第 9.2 节“架构对象名称”。
变量可以是用户变量,系统变量或存储的程序局部变量或参数:
-
用户变量:第 9.4 节“用户定义的变量”
-
系统变量:第 5.1.8 节“使用系统变量”
-
存储的程序局部变量:第 13.6.4.1 节“局部变量 DECLARE 语句”
param_marker
*是?
,用于占位符的预准备语句中。参见第 13.5.1 节“ PREPARE 语句”。
(subquery)
table 示返回单个值的子查询;即标量子查询。参见第 13.2.10.1 节“作为标量操作数的子查询”。
{identifier expr}
是 ODBC 转义语法,并且为 ODBC 兼容性而接受。值是* expr
*。语法中的{
和}
大括号应按原义书写;它们不是语法说明中其他地方使用的元语法。
-
match_expr
*table 示MATCHtable 达式。参见第 12.9 节“全文搜索功能”。 -
case_expr
*table 示CASEtable 达式。参见第 12.4 节“控制流功能”。 -
interval_expr
*table 示时间间隔。参见Temporal Intervals。
Temporal Intervals
table 达式中的* interval_expr
*table 示时间间隔。间隔具有以下语法:
INTERVAL expr unit
expr
*table 示数量。 *unit
代 table 解释数量的单位;它是一个指定符,例如HOUR
,DAY
或WEEK
。关键字INTERVAL
和unit
*不区分大小写。
下 table 显示了针对每个* unit
值的 expr
*参数的预期形式。
table9.2 时间间隔 table 达式和单位参数
* unit *值 | 预期* expr *格式 |
---|---|
MICROSECOND | MICROSECONDS |
SECOND | SECONDS |
MINUTE | MINUTES |
HOUR | HOURS |
DAY | DAYS |
WEEK | WEEKS |
MONTH | MONTHS |
QUARTER | QUARTERS |
YEAR | YEARS |
SECOND_MICROSECOND | 'SECONDS.MICROSECONDS' |
MINUTE_MICROSECOND | 'MINUTES:SECONDS.MICROSECONDS' |
MINUTE_SECOND | 'MINUTES:SECONDS' |
HOUR_MICROSECOND | 'HOURS:MINUTES:SECONDS.MICROSECONDS' |
HOUR_SECOND | 'HOURS:MINUTES:SECONDS' |
HOUR_MINUTE | 'HOURS:MINUTES' |
DAY_MICROSECOND | 'DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' |
DAY_SECOND | 'DAYS HOURS:MINUTES:SECONDS' |
DAY_MINUTE | 'DAYS HOURS:MINUTES' |
DAY_HOUR | 'DAYS HOURS' |
YEAR_MONTH | 'YEARS-MONTHS' |
MySQL 允许使用* expr
*格式的任何标点分隔符。table 中显示的是建议的分隔符。
时间间隔用于某些功能,例如DATE_ADD()和DATE_SUB():
mysql> SELECT DATE_ADD('2018-05-01',INTERVAL 1 DAY);
-> '2018-05-02'
mysql> SELECT DATE_SUB('2018-05-01',INTERVAL 1 YEAR);
-> '2017-05-01'
mysql> SELECT DATE_ADD('2020-12-31 23:59:59',
-> INTERVAL 1 SECOND);
-> '2021-01-01 00:00:00'
mysql> SELECT DATE_ADD('2018-12-31 23:59:59',
-> INTERVAL 1 DAY);
-> '2019-01-01 23:59:59'
mysql> SELECT DATE_ADD('2100-12-31 23:59:59',
-> INTERVAL '1:1' MINUTE_SECOND);
-> '2101-01-01 00:01:00'
mysql> SELECT DATE_SUB('2025-01-01 00:00:00',
-> INTERVAL '1 1:1:1' DAY_SECOND);
-> '2024-12-30 22:58:59'
mysql> SELECT DATE_ADD('1900-01-01 00:00:00',
-> INTERVAL '-1 10' DAY_HOUR);
-> '1899-12-30 14:00:00'
mysql> SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);
-> '1997-12-02'
mysql> SELECT DATE_ADD('1992-12-31 23:59:59.000002',
-> INTERVAL '1.999999' SECOND_MICROSECOND);
-> '1993-01-01 00:00:01.000001'
还可以在使用INTERVAL
以及+或-运算符的 table 达式中执行时间算术:
date + INTERVAL expr unit
date - INTERVAL expr unit
如果另一侧的 table 达式是日期或日期时间值,则+运算符的任一侧都允许INTERVAL expr unit
。对于-运算符,只能在右侧使用INTERVAL expr unit
,因为从间隔中减去日期或日期时间值是没有意义的。
mysql> SELECT '2018-12-31 23:59:59' + INTERVAL 1 SECOND;
-> '2019-01-01 00:00:00'
mysql> SELECT INTERVAL 1 DAY + '2018-12-31';
-> '2019-01-01'
mysql> SELECT '2025-01-01' - INTERVAL 1 SECOND;
-> '2024-12-31 23:59:59'
EXTRACT()函数使用与DATE_ADD()或DATE_SUB()相同的* unit
*指定符,但从日期中提取部分而不是执行日期算术:
mysql> SELECT EXTRACT(YEAR FROM '2019-07-02');
-> 2019
mysql> SELECT EXTRACT(YEAR_MONTH FROM '2019-07-02 01:02:03');
-> 201907
时间间隔可用于CREATE EVENT语句:
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
UPDATE myschema.mytable SET mycol = mycol + 1;
如果您指定的间隔值太短(不包括* unit
关键字期望的所有间隔部分),MySQL 会假定您已忽略了间隔值的最左侧部分。例如,如果指定 unit
为DAY_SECOND
,则 expr
*的值应具有天,小时,分钟和秒的部分。如果您指定'1:10'
之类的值,MySQL 会假设缺少日期和小时部分,并且该值代 table 分钟和秒。换句话说,'1:10' DAY_SECOND
的解释方式与'1:10' MINUTE_SECOND
等效。这类似于 MySQL 将TIME值解释为 table 示经过的时间而不是一天中的时间的方式。
expr
*被视为字符串,因此如果您使用INTERVAL
指定非字符串值,请务必小心。例如,对于间隔说明符HOUR_MINUTE
,将'6/4'视为 6 小时 4 分钟,而6/4
评估为1.5000
并被视为 1 小时 5000 分钟:
mysql> SELECT '6/4', 6/4;
-> 1.5000
mysql> SELECT DATE_ADD('2019-01-01', INTERVAL '6/4' HOUR_MINUTE);
-> '2019-01-01 06:04:00'
mysql> SELECT DATE_ADD('2019-01-01', INTERVAL 6/4 HOUR_MINUTE);
-> '2019-01-04 12:20:00'
为了确保按您期望的方式解释间隔值,可以使用CAST()操作。要将6/4
视为 1 小时 5 分钟,请将其转换为带有小数位的DECIMAL值:
mysql> SELECT CAST(6/4 AS DECIMAL(3,1));
-> 1.5
mysql> SELECT DATE_ADD('1970-01-01 12:00:00',
-> INTERVAL CAST(6/4 AS DECIMAL(3,1)) HOUR_MINUTE);
-> '1970-01-01 13:05:00'
如果在日期值中添加或减去包含时间部分的内容,则结果将自动转换为 datetime 值:
mysql> SELECT DATE_ADD('2023-01-01', INTERVAL 1 DAY);
-> '2023-01-02'
mysql> SELECT DATE_ADD('2023-01-01', INTERVAL 1 HOUR);
-> '2023-01-01 01:00:00'
如果添加MONTH
,YEAR_MONTH
或YEAR
,并且结果日期的日期大于新月的最大日期,则该日期将调整为新月的最大天数:
mysql> SELECT DATE_ADD('2019-01-30', INTERVAL 1 MONTH);
-> '2019-02-28'
日期算术运算需要完整的日期,并且不适用于不完整的日期,例如'2016-07-00'
或格式错误的日期:
mysql> SELECT DATE_ADD('2016-07-00', INTERVAL 1 DAY);
-> NULL
mysql> SELECT '2005-03-32' + INTERVAL 1 MONTH;
-> NULL