11.5 表达式
本节列举了 MySQL 中表达式必须遵循的语法规则,并提供了关于表达式中可能出现的术语类型的额外信息。
以下语法规则定义了 MySQL 中的表达式语法。这里显示的语法基于 MySQL 源代码分布中的sql/sql_yacc.yy
文件。关于某些表达式术语的额外信息,请参见表达式术语笔记。
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
关于操作符优先级,见第14.4.1节,“操作符优先级”。某些操作符的优先级和含义取决于 SQL 模式:
-
默认情况下,
||
是逻辑OR
运算符。启用PIPES_AS_CONCAT
,||
是字符串连接,优先级在^
和单目运算符之间。 -
默认情况下,
!
的优先级高于NOT
。启用HIGH_NOT_PRECEDENCE
,!
和NOT
优先级相同。
请参见第11.1节,“字面值”。
请参见第11.2节,“模式对象名称”。
变量可以是用户变量、系统变量或存储程序局部变量或参数:
-
用户变量:第11.4节,“自定义变量”
-
系统变量:第7.1.9节,“使用系统变量”
-
存储程序局部变量:第15.6.4.1节,“局部变量DECLARE语句”
param_marker
是在预准备语句中的占位符,例如?。见第15.5.1节,“PREPARE语句”。
(
表示返回单个值的子查询,即标量子查询。见第15.2.15.1节,“标量子查询作为操作数”。subquery
)
{
是 ODBC 逃逸语法,用于ODBC 兼容性。值为 identifier
expr
}expr
。语法中的{
和 }
大括号应该写作文字;它们在其他语法描述中不作为语法元语法使用。
match_expr
表示MATCH
表达式。见第14.9节,“全文搜索函数”。
case_expr
表示一个CASE
表达式。见第14.5节,“控制流函数”。
interval_expr
表示一个时间间隔。见时间间隔。
interval_expr
在表达式中表示一个时间间隔。间隔具有以下语法:
INTERVAL expr unit
expr
表示数量。unit
表示解释数量的单位;它是一个指定符号,如 HOUR
、DAY
或 WEEK
。关键字 INTERVAL
和 unit
指定符号不区分大小写。
以下表格显示了每个 unit
值的 expr
参数的预期形式。
表11.2 时间间隔表达式和单位参数
unit Value |
Expected expr Format |
---|---|
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
格式中使用任何标点符号,表格中显示的都是建议的分隔符。
时间间隔用于某些函数,如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
一同进行时间计算的表达式,可以使用+
或者 -
运算符:
date + INTERVAL expr unit
date - INTERVAL expr unit
INTERVAL
可以出现在expr
unit
+
运算符的两侧,如果另一边的表达式是日期或datetime值。对于 -
运算符,INTERVAL
只能出现在右侧,因为从间隔值减去日期或datetime值没有意义。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假设天和小时部分缺失,值表示分钟和秒。换言之,'1:10' DAY_SECOND
被解释为等同于'1:10' MINUTE_SECOND
。这与MySQL解释TIME
值的方式相似,表示已过时间,而不是一天中的时间。
expr
被视为字符串,因此如果使用 INTERVAL
指定非字符串值,需要小心。例如,以间隔指定符号 HOUR_MINUTE
,'6/4' 将被视为 6 小时,四分钟,而 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