TiDB 中函数和操作符使用方法与 MySQL 基本一致,详情参见: Functions and Operators。
在 SQL 语句中,表达式可用于诸如 SELECT
语句的 ORDER BY
或 HAVING
子句,SELECT
/DELETE
/UPDATE
语句的 WHERE
子句,或 SET
语句之类的地方。
可使用字面值,列名,NULL,内置函数,操作符等来书写表达式。其中有些表达式下推到 TiKV 上执行,详见下推到 TiKV 的表达式列表。
TiDB 中表达式求值的类型转换与 MySQL 基本一致,详情参见 MySQL 表达式求值的类型转换。
操作符 | 功能描述 |
---|---|
AND, && | 逻辑与 |
= | 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) |
:= | 赋值 |
BETWEEN … AND … | 判断值满足范围 |
BINARY | 将一个字符串转换为一个二进制字符串 |
& | 位与 |
~ | 位非 |
\| |
位或 |
^ | 按位异或 |
CASE | case 操作符 |
DIV | 整数除 |
/ | 除法 |
= | 相等比较 |
<=> | 空值安全型相等比较 |
> | 大于 |
>= | 大于或等于 |
IS | 判断一个值是否等于一个布尔值 |
IS NOT | 判断一个值是否不等于一个布尔值 |
IS NOT NULL | 非空判断 |
IS NULL | 空值判断 |
<< | 左移 |
< | 小于 |
<= | 小于或等于 |
LIKE | 简单模式匹配 |
- | 减 |
%, MOD | 求余 |
NOT, ! | 取反 |
NOT BETWEEN … AND … | 判断值是否不在范围内 |
!=, <> | 不等于 |
NOT LIKE | 不符合简单模式匹配 |
NOT REGEXP | 不符合正则表达式模式匹配 |
||, OR | 逻辑或 |
+ | 加 |
REGEXP | 使用正则表达式进行模式匹配 |
>> | 右移 |
RLIKE REGEXP | 同义词 |
* | 乘 |
- | 取反符号 |
XOR | 逻辑亦或 |
操作符优先级显示在以下列表中,从最高优先级到最低优先级。同一行显示的操作符具有相同的优先级。
INTERVAL
BINARY
!
- (unary minus), ~ (unary bit inversion)
^
*, /, DIV, %, MOD
-, +
<<, >>
&
|
= (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
BETWEEN, CASE, WHEN, THEN, ELSE
NOT
AND, &&
XOR
OR, ||
= (assignment), :=
详情参见 这里.
操作符名 | 功能描述 |
---|---|
BETWEEN … AND … | 判断值是否在范围内 |
COALESCE() | 返回第一个非空值 |
= | 相等比较 |
<=> | 空值安全型相等比较 |
> | 大于 |
>= | 大于或等于 |
GREATEST() | 返回最大值 |
IN() | 判断值是否在一个值的集合内 |
INTERVAL() | 返回一个小于第一个参数的参数的下标 |
IS | 判断是否等于一个布尔值 |
IS NOT | 判断是否不等于一个布尔值 |
IS NOT NULL | 非空判断 |
IS NULL | 空值判断 |
ISNULL() | 判断参数是否为空 |
LEAST() | 返回最小值 |
< | 小于 |
<= | 小于或等于 |
LIKE | 简单模式匹配 |
NOT BETWEEN … AND … | 判断值是否不在范围内 |
!=, <> | 不等于 |
NOT IN() | 判断值是否不在一个值的集合内 |
NOT LIKE | 不满足简单模式匹配 |
STRCMP() | 比较两个字符串 |
详情参见 这里.
操作符名 | 功能描述 |
---|---|
AND, && | 逻辑与 |
NOT, ! | 逻辑非 |
\|\| , OR |
逻辑或 |
XOR | 逻辑亦或 |
详情参见 这里.
操作符名 | 功能描述 |
---|---|
= | 赋值(可用于SET语句中,或用于UPDATE语句的SET中) |
:= | 赋值 |
详情参见 这里.
TiDB 支持使用 MySQL 5.7 中提供的所有控制流程函数。
函数名 | 功能描述 |
---|---|
CASS | Case操作符 |
IF() | 构建if/else |
IFNULL() | 构建NUll if/else |
NULLIF() | 如果expr1 = expr2,返回NULL |
TiDB 支持使用 MySQL 5.7 中提供的大部分字符串函数。
函数名 | 功能描述 |
---|---|
ASCII() | 返回最左字符的数值 |
BIN() | 返回一个数的二进制值的字符串表示 |
BIT_LENGTH() | 返回字符串的位长度 |
CHAR() | 返回由整数的代码值所给出的字符组成的字符串 |
CHAR_LENGTH() | 返回字符串的字符长度 |
CHARACTER_LENGTH() | 与 CHAR_LENGTH() 功能相同 |
CONCAT() | 返回连接的字符串 |
CONCAT_WS() | 返回由分隔符连接的字符串 |
ELT() | 返回指定位置的字符串 |
EXPORT_SET() | 返回一个字符串,其中值位中设置的每个位,可以得到一个 on 字符串,而每个未设置的位,可以得到一个 off 字符串 |
FIELD() | 返回参数在后续参数中出现的第一个位置 |
FIND_IN_SET() | 返回第一个参数在第二个参数中出现的位置 |
FORMAT() | 返回指定小数位数格式的数字 |
FROM_BASE64() | 解码 base-64 表示的字符串,并返回结果 |
HEX() | 返回一个十进制数或字符串值的 16 进制表示 |
INSERT() | 在指定位置插入一个子字符串,最多不超过指定字符数 |
INSTR() | 返回第一次出现的子字符串的索引 |
LCASE() | 与 LOWER() 功能相同 |
LEFT() | 返回最左侧指定长度的字符 |
LENGTH() | 返回字符串长度,单位为字节 |
LIKE | 进行简单模式匹配 |
LOCATE() | 返回第一次出现的子字符串的位置 |
LOWER() | 返回全小写的参数 |
LPAD() | 返回字符串参数,左侧添加指定字符串 |
LTRIM() | 去掉前缀空格 |
MAKE_SET() | 返回一组用逗号分隔的字符串,这些字符串的位数与给定的 bits 参数对应 |
MID() | 返回一个以指定位置开始的子字符串 |
NOT LIKE | 否定简单模式匹配 |
NOT REGEXP | REGEXP 的否定形式 |
OCT() | 返回一个数值的八进制表示,形式为字符串 |
OCTET_LENGTH() | 与 LENGTH() 功能相同 |
ORD() | 返回该参数最左侧字符的字符编码 |
POSITION() | 与 LOCATE() 功能相同 |
QUOTE() | 使参数逃逸,为了在 SQL 语句中使用 |
REGEXP | 使用正则表达式匹配模式 |
REPEAT() | 以指定次数重复一个字符串 |
REPLACE() | 替换所有出现的指定字符串 |
REVERSE() | 反转字符串里的所有字符 |
RIGHT() | 返回指定数量的最右侧的字符 |
RLIKE | 与 REGEXP 功能相同 |
RPAD() | 以指定次数添加字符串 |
RTRIM() | 去掉后缀空格 |
SPACE() | 返回指定数量的空格,形式为字符串 |
STRCMP() | 比较两个字符串 |
SUBSTR() | 返回指定的子字符串 |
SUBSTRING() | 返回指定的子字符串 |
SUBSTRING_INDEX() | 从一个字符串中返回指定出现次数的定界符之前的子字符串 |
TO_BASE64() | 返回转化为 base-64 表示的字符串参数 |
TRIM() | 去掉前缀和后缀空格 |
UCASE() | 与 UPPER() 功能相同 |
UNHEX() | 返回一个数的十六进制表示,形式为字符串 |
UPPER() | 参数转换为大写形式 |
TiDB 支持使用 MySQL 5.7 中提供的所有数值函数与操作符。
操作符名 | 功能描述 |
---|---|
+ | 加号 |
- | 减号 |
* | 乘号 |
/ | 除号 |
DIV | 整数除法 |
%, MOD | 模运算,取余 |
- | 更改参数符号 |
函数名 | 功能描述 |
---|---|
POW() | 返回参数的指定乘方的结果值 |
POWER() | 返回参数的指定乘方的结果值 |
EXP() | 返回 e(自然对数的底)的指定乘方后的值 |
SQRT() | 返回非负数的二次方根 |
LN() | 返回参数的自然对数 |
LOG() | 返回第一个参数的自然对数 |
LOG2() | 返回参数以 2 为底的对数 |
LOG10() | 返回参数以 10 为底的对数 |
PI() | 返回 pi 的值 |
TAN() | 返回参数的正切值 |
COT() | 返回参数的余切值 |
SIN() | 返回参数的正弦值 |
COS() | 返回参数的余弦值 |
ATAN() | 返回参数的反正切值 |
ATAN2(), ATAN() | 返回两个参数的反正切值 |
ASIN() | 返回参数的反正弦值 |
ACOS() | 返回参数的反余弦值 |
RADIANS() | 返回由度转化为弧度的参数 |
DEGREES() | 返回由弧度转化为度的参数 |
MOD() | 返回余数 |
ABS() | 返回参数的绝对值 |
CEIL() | 返回不小于参数的最小整数值 |
CEILING() | 返回不小于参数的最小整数值 |
FLOOR() | 返回不大于参数的最大整数值 |
ROUND() | 返回参数最近似的整数或指定小数位数的数值 |
RAND() | 返回一个随机浮点值 |
SIGN() | 返回参数的符号 |
CONV() | 不同数基间转换数字,返回数字的字符串表示 |
TRUNCATE() | 返回被舍位至指定小数位数的数字 |
CRC32() | 计算循环冗余码校验值并返回一个 32 位无符号值 |
函数名 | 功能描述 |
---|---|
ADDDATE() |
将时间间隔添加到日期上 |
ADDTIME() |
时间数值相加 |
CONVERT_TZ() |
转换时区 |
CURDATE() |
返回当前日期 |
CURRENT_DATE() , CURRENT_DATE |
与 CURDATE() 同义 |
CURRENT_TIME() , CURRENT_TIME |
与 CURTIME() 同义 |
CURRENT_TIMESTAMP() , CURRENT_TIMESTAMP |
与 NOW() 同义 |
CURTIME() |
返回当前时间 |
DATE() |
从日期或日期/时间表达式中提取日期部分 |
DATE_ADD() |
将时间间隔添加到日期上 |
DATE_FORMAT() |
返回满足指定格式的日期/时间 |
DATE_SUB() |
从日期减去指定的时间间隔 |
DATEDIFF() |
返回两个日期间隔的天数 |
DAY() |
与 DAYOFMONTH() 同义 |
DAYNAME() |
返回星期名称 |
DAYOFMONTH() |
返回参数对应的天数部分(1-31) |
DAYOFWEEK() |
返回参数对应的星期下标 |
DAYOFYEAR() |
返回参数代表一年的哪一天 (1-366) |
EXTRACT() |
提取日期/时间中的单独部分 |
FROM_DAYS() |
将天数转化为日期 |
FROM_UNIXTIME() |
将 Unix 时间戳格式化为日期 |
GET_FORMAT() |
返回满足日期格式的字符串 |
HOUR() |
提取日期/时间表达式中的小时部分 |
LAST_DAY |
返回参数中月份的最后一天 |
LOCALTIME() , LOCALTIME |
与 NOW() 同义 |
LOCALTIMESTAMP , LOCALTIMESTAMP() |
与 NOW() 同义 |
MAKEDATE() |
根据给定的年份和一年中的天数生成一个日期 |
MAKETIME() |
根据给定的时、分、秒生成一个时间 |
MICROSECOND() |
返回参数的微秒部分 |
MINUTE() |
返回参数的分钟部分 |
MONTH() |
返回参数的月份部分 |
MONTHNAME() |
返回参数的月份名称 |
NOW() |
返回当前日期和时间 |
PERIOD_ADD() |
在年-月表达式上添加一段时间(数个月) |
PERIOD_DIFF() |
返回间隔的月数 |
QUARTER() |
返回参数对应的季度(1-4) |
SEC_TO_TIME() |
将秒数转化为 ‘HH:MM:SS’ 的格式 |
SECOND() |
返回秒数(0-59) |
STR_TO_DATE() |
将字符串转化为日期 |
SUBDATE() |
当传入三个参数时作为 DATE_SUB() 的同义 |
SUBTIME() |
从一个时间中减去一段时间 |
SYSDATE() |
返回该方法执行时的时间 |
TIME() |
返回参数的时间表达式部分 |
TIME_FORMAT() |
格式化时间 |
TIME_TO_SEC() |
返回参数对应的秒数 |
TIMEDIFF() |
返回时间间隔 |
TIMESTAMP() |
传入一个参数时候,该方法返回日期或日期/时间表达式, 传入两个参数时候, 返回参数的和 |
TIMESTAMPADD() |
在日期/时间表达式上增加一段时间间隔 |
TIMESTAMPDIFF() |
从日期/时间表达式中减去一段时间间隔 |
TO_DAYS() |
将参数转化对应的天数(从第 0 年开始) |
TO_SECONDS() |
将日期或日期/时间参数转化为秒数(从第 0 年开始) |
UNIX_TIMESTAMP() |
返回一个 Unix 时间戳 |
UTC_DATE() |
返回当前的 UTC 日期 |
UTC_TIME() |
返回当前的 UTC 时间 |
UTC_TIMESTAMP() |
返回当前的 UTC 日期和时间 |
WEEK() |
返回参数所在的一年中的星期数 |
WEEKDAY() |
返回星期下标 |
WEEKOFYEAR() |
返回参数在日历中对应的一年中的星期数 |
YEAR() |
返回参数对应的年数 |
YEARWEEK() |
返回年数和星期数 |
TiDB 支持使用 MySQL 5.7 中提供的所有位函数和操作符。
函数和操作符名 | 功能描述 |
---|---|
BIT_COUNT() | 返回参数二进制表示中为 1 的个数 |
& | 位与 |
~ | 按位取反 |
| | 位或 |
0 | 位亦或 |
<< | 左移 |
>> | 右移 |
Cast 函数和操作符用于将某种数据类型的值转换为另一种数据类型。TiDB 支持使用 MySQL 5.7 中提供的所有 Cast 函数和操作符。
函数和操作符名 | 功能描述 |
---|---|
BINARY |
将一个字符串转换成一个二进制字符串 |
CAST() |
将一个值转换成一个确定类型 |
CONVERT() |
将一个值转换成一个确定类型 |
TiDB 支持使用 MySQL 5.7 中提供的大部分加密和压缩函数。
函数名 | 功能描述 |
---|---|
MD5() |
计算字符串的 MD5 校验和 |
PASSWORD() |
计算并返回密码字符串 |
RANDOM_BYTES() |
返回随机字节向量 |
SHA1() , SHA() |
计算 SHA-1 160 位校验和 |
SHA2() |
计算 SHA-2 校验和 |
AES_DECRYPT() |
使用 AES 解密 |
AES_ENCRYPT() |
使用 AES 加密 |
COMPRESS() |
返回经过压缩的二进制字符串 |
UNCOMPRESS() |
解压缩字符串 |
UNCOMPRESSED_LENGTH() |
返回字符串解压后的长度 |
CREATE_ASYMMETRIC_PRIV_KEY() |
创建私钥 |
CREATE_ASYMMETRIC_PUB_KEY() |
创建公钥 |
CREATE_DH_PARAMETERS() |
创建 DH 共享密钥 |
CREATE_DIGEST() |
从字符串创建摘要 |
ASYMMETRIC_DECRYPT() |
使用公钥或私钥解密密文 |
ASYMMETRIC_DERIVE() |
从非对称密钥导出对称密钥 |
ASYMMETRIC_ENCRYPT() |
使用公钥或私钥加密明文 |
ASYMMETRIC_SIGN() |
从摘要创建签名 |
ASYMMETRIC_VERIFY() |
验证签名字符串是否匹配摘要字符串 |
DES_DECRYPT()
、DES_ENCRYPT()
、OLD_PASSWORD()
和 ENCRYPT()
:这些函数在 MySQLVALIDATE_PASSWORD_STRENGTH()
函数。TiDB 支持使用 MySQL 5.7 中提供的大部分信息函数。
函数名 | 功能描述 |
---|---|
BENCHMARK() |
循环执行一个表达式 |
CONNECTION_ID() |
返回当前连接的连接 ID (线程 ID) |
CURRENT_USER() , CURRENT_USER |
返回当前用户的用户名和主机名 |
DATABASE() |
返回默认(当前)的数据库名 |
FOUND_ROWS() |
该函数返回对于一个包含 LIMIT 的 SELECT 查询语句,在不包含 LIMIT 的情况下回返回的记录数 |
LAST_INSERT_ID() |
返回最后一条 INSERT 语句中自增列的值 |
ROW_COUNT() |
影响的行数 |
SCHEMA() |
与 DATABASE() 同义 |
SESSION_USER() |
与 USER() 同义 |
SYSTEM_USER() |
与 USER() 同义 |
USER() |
返回客户端提供的用户名和主机名 |
VERSION() |
返回当前 MySQL 服务器的版本信息 |
TIDB_VERSION() |
返回当前 TiDB 服务器的版本信息 |
TiDB 支持 MySQL 5.7 GA 版本发布的大多数 JSON 函数。MySQL 5.7 发布后,又增加了更多 JSON 函数,TiDB 并未支持所有这些函数(参见未支持的函数)。
函数及语法糖 | 功能描述 |
---|---|
JSON_ARRAY([val[, val] …]) | 根据一系列元素创建一个 JSON 文档 |
JSON_OBJECT(key, val[, key, val] …) | 根据一系列 K/V 对创建一个 JSON 文档 |
JSON_QUOTE(string) | 返回一个字符串,该字符串为带引号的 JSON 值 |
函数及语法糖 | 功能描述 |
---|---|
JSON_CONTAINS(target, candidate[, path]) | 通过返回 1 或 0 来表示目标 JSON 文档中是否包含给定的 candidate JSON 文档 |
JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] …) | 通过返回 0 或 1 来表示一个 JSON 文档在给定路径是否包含数据 |
JSON_EXTRACT(json_doc, path[, path] …) | 从 JSON 文档中解出某一路径对应的子文档 |
-> | 返回执行路径后面的 JSON 列的值;JSON_EXTRACT(doc, path_literal) 的语法糖 |
->> | 返回执行路径后面的 JSON 列的值和转义后的结果; JSON_UNQUOTE(JSON_EXTRACT(doc, path_literal)) 的语法糖 |
JSON_KEYS(json_doc[, path]) | 返回从 JSON 对象的顶级值作为 JSON array 的键,如果给定了路径参数,则从选定路径中获取顶级键 |
函数及语法糖 | 功能描述 |
---|---|
JSON_INSERT(json_doc, path, val[, path, val] …) | 在 JSON 文档中在某一路径下插入子文档 |
JSON_MERGE(json_doc, json_doc[, json_doc] …) | 已废弃的 JSON_MERGE_PRESERVE 别名 |
JSON_MERGE_PRESERVE(json_doc, json_doc[, json_doc] …) | 将两个或多个 JSON 文档合并成一个文档,并返回合并结果 |
JSON_REMOVE(json_doc, path[, path] …) | 移除 JSON 文档中某一路径下的子文档 |
JSON_REPLACE(json_doc, path, val[, path, val] …) | 替换 JSON 文档中的某一路径下的子文档 |
JSON_SET(json_doc, path, val[, path, val] …) | 在 JSON 文档中为某一路径设置子文档 |
JSON_UNQUOTE(json_val) | 去掉 JSON 值外面的引号,返回结果为字符串 |
函数及语法糖 | 功能描述 |
---|---|
JSON_DEPTH(json_doc) | 返回 JSON 文档的最大深度 |
JSON_LENGTH(json_doc[, path]) | 返回 JSON 文档的长度;如果路径参数已定,则返回该路径下值的长度 |
JSON_TYPE(json_val) | 检查某 JSON 文档内部内容的类型 |
TiDB 暂未支持以下 JSON 函数。相关进展参见 TiDB #7546:
JSON_APPEND
及其别名 JSON_ARRAY_APPENDJSON_ARRAY_INSERT
JSON_DEPTH
JSON_MERGE_PATCH
JSON_PRETTY
JSON_SEARCH
JSON_STORAGE_SIZE
JSON_VALID
JSON_ARRAYAGG
JSON_OBJECTAGG
TiDB 支持的 MySQL GROUP BY 聚合函数如下所示:
函数名 | 功能描述 |
---|---|
COUNT() |
返回检索到的行的数目 |
COUNT(DISTINCT) |
返回不同值的数目 |
SUM() |
返回和 |
AVG() |
返回平均值 |
MAX() |
返回最大值 |
MIN() |
返回最小值 |
GROUP_CONCAT() |
返回连接的字符串 |
注意:
TiDB 目前不支持 GROUP BY
修饰符,例如 WITH ROLLUP
,将来会提供支持。详情参阅 #4250。
TiDB 支持 SQL 模式 ONLY_FULL_GROUP_BY
,当启用该模式时,TiDB 拒绝不明确的非聚合列的查询。例如,以下查询在启用 ONLY_FULL_GROUP_BY
时是不合规的,因为 SELECT
列表中的非聚合列 “b” 在 GROUP BY
语句中不显示:
drop table if exists t;
create table t(a bigint, b bigint, c bigint);
insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3);
select a, b, sum(c) from t group by a;
+------+------+--------+
| a | b | sum(c) |
+------+------+--------+
| 1 | 2 | 3 |
| 2 | 2 | 3 |
| 3 | 2 | 3 |
+------+------+--------+
3 rows in set (0.01 sec)
set sql_mode = 'ONLY_FULL_GROUP_BY';
Query OK, 0 rows affected (0.00 sec)
select a, b, sum(c) from t group by a;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'b' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
目前,TiDB 默认开启 SQL 模式 ONLY_FULL_GROUP_BY。
TiDB 目前实现的 ONLY_FULL_GROUP_BY
没有 MySQL 5.7 严格。例如,假设我们执行以下查询,希望结果按 “c” 排序:
drop table if exists t;
create table t(a bigint, b bigint, c bigint);
insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2);
select distinct a, b from t order by c;
要对结果进行排序,必须先清除重复。但选择保留哪一行会影响 c 的保留值,也会影响排序,并使其具有任意性。
在 MySQL 中,ORDER BY
表达式需至少满足以下条件之一,否则 DISTINCT
和 ORDER BY
查询将因不合规而被拒绝:
但是在 TiDB 中,上述查询是合规的,详情参阅 #4254。
TiDB 中另一个标准 SQL 的扩展允许 HAVING
子句中的引用使用 SELECT
列表中的别名表达式。例如:以下查询返回在 orders
中只出现一次的 name
值:
select name, count(name) from orders
group by name
having count(name) = 1;
这个 TiDB 扩展允许在聚合列的 HAVING
子句中使用别名:
select name, count(name) as c from orders
group by name
having c = 1;
标准 SQL 只支持 GROUP BY
子句中的列表达式,以下语句不合规,因为 FLOOR(value/100)
是一个非列表达式:
select id, floor(value/100)
from tbl_name
group by id, floor(value/100);
TiDB 对标准 SQL 的扩展支持 GROUP BY
子句中非列表达式,认为上述语句合规。
标准 SQL 也不支持 GROUP BY
子句中使用别名。TiDB 对标准 SQL 的扩展支持使用别名,查询的另一种写法如下:
select id, floor(value/100) as val
from tbl_name
group by id, val;
TiDB 目前不支持的聚合函数如下所示,相关进展参阅 TiDB #7623。
STD
, STDDEV
, STDDEV_POP
STDDEV_SAMP
VARIANCE
, VAR_POP
VAR_SAMP
JSON_ARRAYAGG
JSON_OBJECTAGG
TiDB 中窗口函数的使用方法与 MySQL 8.0 基本一致,详情可参见 MySQL 窗口函数。由于窗口函数会使用一些保留关键字,可能导致原先可以正常执行的 SQL 语句在升级 TiDB 后无法被解析语法,此时可以将 tidb_enable_window_function 设置为 0,该参数的默认值为 1。
TiDB 支持的窗口函数如下所示:
函数名 | 功能描述 |
---|---|
CUME_DIST() |
返回一组值中的累积分布 |
DENSE_RANK() |
返回分区中当前行的排名,并且排名是连续的 |
FIRST_VALUE() |
当前窗口中第一行的表达式值 |
LAG() |
分区中当前行前面第 N 行的表达式值 |
LAST_VALUE() |
当前窗口中最后一行的表达式值 |
LEAD() |
分区中当前行后面第 N 行的表达式值 |
NTH_VALUE() |
当前窗口中第 N 行的表达式值 |
NTILE() |
将分区划分为 N 桶,为分区中的每一行分配桶号 |
PERCENT_RANK() |
返回分区中小于当前行的百分比 |
RANK() |
返回分区中当前行的排名,排名可能不连续 |
ROW_NUMBER() |
返回分区中当前行的编号 |
TiDB 支持使用 MySQL 5.7 中提供的大部分其他函数。
函数名 | 功能描述 |
---|---|
ANY_VALUE() |
在 ONLY_FULL_GROUP_BY 模式下,防止带有 GROUP BY 的语句报错 |
DEFAULT() |
返回表的某一列的默认值 |
INET_ATON() |
将 IP 地址转换为数值 |
INET_NTOA() |
将数值转换为 IP 地址 |
INET6_ATON() |
将 IPv6 地址转换为数值 |
INET6_NTOA() |
将数值转换为 IPv6 地址 |
IS_IPV4() |
判断参数是否为 IPv4 地址 |
IS_IPV4_COMPAT() |
判断参数是否为兼容 IPv4 的地址 |
IS_IPV4_MAPPED() |
判断参数是否为 IPv4 映射的地址 |
IS_IPV6() |
判断参数是否为 IPv6 地址 |
NAME_CONST() |
可以用于重命名列名 |
SLEEP() |
让语句暂停执行几秒时间 |
UUID() |
返回一个通用唯一识别码 (UUID) |
VALUES() |
定义 INSERT 语句使用的值 |
| GET_LOCK()
| 获取命名锁,详见 TiDB #10929 | | RELEASE_LOCK()
| 释放命名锁,详见 TiDB #10929 | | UUID_SHORT()
| 基于特定假设提供唯一的 UUID,目前这些假设在 TiDB 中不存在,详见 TiDB #4620 | | MASTER_WAIT_POS()
| 与 MySQL 同步相关 |
TiDB 中精度数学计算与 MySQL 中基本一致, 详情请参见: Precision Math.
精确数值运算的范围包括精确值数据类型(整型和 DECIMAL 类型), 以及精确值数字字面量. 近似值数据类型和近似值数字字面量被作为浮点数来处理.
精确值数字字面量包含整数部分或小数部分, 或二者都包含. 精确值数字字面量可以包含符号位. 例如: 1, .2, 3.4, -5, -6.78, +9.10.
近似值数字字面量以一个包含尾数和指数的科学计数法表示(基数为 10). 其中尾数和指数可以分别或同时带有符号位. 例如: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.
两个看起来相似的数字可能会被以不同的方式进行处理. 例如, 2.34 是精确值(定点数), 而 2.3E0 是近似值(浮点数).
DECIMAL 数据类型是定点数类型, 其运算是精确计算. FLOAT 和 DOUBLE 数据类型是浮点类型, 其运算是近似计算.
本节讨论 DECIMAL 数据类型的特性, 主要涉及以下几点:
DECIMAL 列的声明语法为 DECIMAL(M, D). 其中参数值意义及其范围如下:
M 的最大值 65 表示 DECIMAL 值的计算精确到 65 位数字. 该精度同样适用于其精确值字面量.
DECIMAL 列的值采用二进制进行存储, 其将每 9 位十进制数字包装成 4 个字节. 其中整数和小数部分分别确定所需的存储空间. 如果数字位数为 9 的倍数, 则每 9 位十进制数字各采用 4 个字节进行存储, 对于剩余不足 9 位的数字, 所需的存储空间如下表所示.
剩余数字位数 | 存储所需字节数 |
---|---|
0 | 0 |
1–2 | 1 |
3–4 | 2 |
5–6 | 3 |
7–9 | 4 |
例如, 定义类型为 DECIMAL(18, 9) 的列, 其小数点两侧均各包含 9 位十进制数字, 因此, 分别需要 4 个字节的存储空间. 定义类型为 DECIMAL(20, 6) 的列, 其小数部分包含 6 位十进制数字, 整数部分包含 14 位十进制数字. 整数部分中 9 位数字需要 4 个字节进行存储, 其余 5 位数字需要 3 个字节进行存储. 小数部分 6 位数字需要 3 个字节进行存储.
DECIMAL 列不存储前导的字符 + 或字符 - 或数字 0. 如果将 +0003.1 插入到 DECIMAL(5, 1) 列中, 则将其存储为3.1. 对于负数, 不存储字符 - 的字面值.
DECIMAL 列不允许插入大于列定义的隐含范围的值. 例如, DECIMAL(3, 0) 列范围为 -999 到 999. DECIMAL(M, D) 列小数点左边部分最多支持 M-D 位数字.
有关 DECIMAL 值的内部格式完整说明, 请参阅 TiDB 源码文件 types/mydecimal.go.
在涉及精度数学计算的表达式中,TiDB 会尽可能不做任何修改的使用每个输入的数值。比如:在计算比较函数时,参与运算的数字将不做任何改变。在严格 SQL 模式下,向一个数据列插入一个值时,如果该值处于这一列的值域范围内,这个值将直接不做任何修改的直接插入进去,提取这个值的时候,取得的值和插入的值将会是同一个值。当处于非严格 SQL 模式时,TiDB 会允许数据插入过程中发生的数据截断。
处理数值类型表达式取决于这个表达式参数的具体值:
如果数值类型表达式中包含字符串参数,这些字符串参数将被转换成双精度浮点数,这个表达式的计算结果将是个近似值。
向一个数值类型列插入数据的具体行为会受到 SQL 模式的影响。接下来的讨论将围绕严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式展开,如果要打开所有的限制,可以简单的使用 TRADITIONAL 模式,这个模式将同时使用严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式:
SET sql_mode = 'TRADITIONAL';
向一个具有精确值类型(DECIMAL 或者整数类型)的列插入数据时,如果插入的数据位于该列的值域范围内将使用该数据的精确值。如果该数据的小数部分太长,将会发生数值修约,这时会有 warning 产生,具体内容可以看”数值修约”。
如果该数据整数部分太长:
如果向一个数值类型列插入字符串,如果该字符串中包含非数值部分,TiDB 将这样做类型转换:
默认情况下,如果计算的过程中发生了除数是 0 的现象将会得到一个 NULL 结果,并且不会有 warning 产生。通过设置适当的 SQL 模式,除以 0 的操作可以被限制:当设置 ERROR_FOR_DIVISION_BY_ZERO SQL 模式时,TiDB 的行为是:
假设我们有如下的 SQL 语句:
INSERT INTO t SET i = 1/0;
不同的 SQL 模式将会导致不同的结果如下:
sql_mode 的值 |
结果 |
---|---|
“ | 没有 warning,没有 error,i 被设为 NULL |
strict | 没有 warning,没有 error,i 被设为 NULL |
ERROR_FOR_DIVISION_BY_ZERO |
有 warning,没有 error,i 被设为 NULL |
strict, ERROR_FOR_DIVISION_BY_ZERO |
有 error,插入失败 |
round() 函数的结果取决于他的参数是否是精确值:
SELECT ROUND(2.5), ROUND(25E-1);
+------------+--------------+
| ROUND(2.5) | ROUND(25E-1) |
+------------+--------------+
| 3 | 3 |
+------------+--------------+
1 row in set (0.00 sec)
向一个 DECIMAL 或者整数类型列插入数据时,round 的规则将采用 round half away from zero 的方式:
CREATE TABLE t (d DECIMAL(10,0));
Query OK, 0 rows affected (0.01 sec)
INSERT INTO t VALUES(2.5),(2.5E0);
Query OK, 2 rows affected, 2 warnings (0.00 sec)
SELECT d FROM t;
+------+
| d |
+------+
| 3 |
| 3 |
+------+
2 rows in set (0.00 sec)
当 TiDB 从 TiKV 中读取数据的时候,TiDB 会尽量下推一些表达式运算到 TiKV 中,从而减少数据传输量以及 TiDB 单一节点的计算压力。本文将介绍 TiDB 已支持下推的表达式,以及如何禁止下推特定表达式。
表达式分类 | 具体操作 |
---|---|
逻辑运算 | AND (&&), OR (||), NOT (!) |
比较运算 | <, <=, =, != (<>), >, >=, <=> , IN() , IS NULL, LIKE, IS TRUE, IS FALSE, COALESCE() |
数值运算 | +, -, *, /, ABS() , CEIL() , CEILING() , FLOOR() |
控制流运算 | CASE , IF() , IFNULL() |
JSON运算 | JSON_TYPE(json_val), JSON_EXTRACT(json_doc, path[, path] …), JSON_UNQUOTE(json_val), JSON_OBJECT(key, val[, key, val] …), JSON_ARRAY([val[, val] …]), JSON_MERGE(json_doc, json_doc[, json_doc] …), JSON_SET(json_doc, path, val[, path, val] …), JSON_INSERT(json_doc, path, val[, path, val] …), JSON_REPLACE(json_doc, path, val[, path, val] …), JSON_REMOVE(json_doc, path[, path] …) |
日期运算 | DATE_FORMAT() |
当函数的计算过程由于下推而出现异常时,可通过黑名单功能禁止其下推来快速恢复业务。具体而言,你可以将上述支持的函数或运算符名加入黑名单 mysql.expr_pushdown_blacklist 中,以禁止特定表达式下推。
执行以下步骤,可将一个或多个函数或运算符加入黑名单:
执行以下步骤,可将一个或多个函数及运算符移出黑名单:
以下示例首先将运算符 < 及 > 加入黑名单,然后将运算符 > 从黑名单中移出。
黑名单是否生效可以从 explain 结果中进行观察。
tidb> create table t(a int);
Query OK, 0 rows affected (0.01 sec)
tidb> explain select * from t where a < 2 and a > 2;
+---------------------+----------+------+------------------------------------------------------------+
| id | count | task | operator info |
+---------------------+----------+------+------------------------------------------------------------+
| TableReader_7 | 0.00 | root | data:Selection_6 |
| └─Selection_6 | 0.00 | cop | gt(test.t.a, 2), lt(test.t.a, 2) |
| └─TableScan_5 | 10000.00 | cop | table:t, range:[-inf,+inf], keep order:false, stats:pseudo |
+---------------------+----------+------+------------------------------------------------------------+
3 rows in set (0.00 sec)
tidb> insert into mysql.expr_pushdown_blacklist values('<'), ('>');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
tidb> admin reload expr_pushdown_blacklist;
Query OK, 0 rows affected (0.00 sec)
tidb> explain select * from t where a < 2 and a > 2;
+---------------------+----------+------+------------------------------------------------------------+
| id | count | task | operator info |
+---------------------+----------+------+------------------------------------------------------------+
| Selection_5 | 8000.00 | root | gt(test.t.a, 2), lt(test.t.a, 2) |
| └─TableReader_7 | 10000.00 | root | data:TableScan_6 |
| └─TableScan_6 | 10000.00 | cop | table:t, range:[-inf,+inf], keep order:false, stats:pseudo |
+---------------------+----------+------+------------------------------------------------------------+
3 rows in set (0.00 sec)
tidb> delete from mysql.expr_pushdown_blacklist where name = '>';
Query OK, 1 row affected (0.00 sec)
tidb> admin reload expr_pushdown_blacklist;
Query OK, 0 rows affected (0.00 sec)
tidb> explain select * from t where a < 2 and a > 2;
+-----------------------+----------+------+------------------------------------------------------------+
| id | count | task | operator info |
+-----------------------+----------+------+------------------------------------------------------------+
| Selection_5 | 2666.67 | root | lt(test.t.a, 2) |
| └─TableReader_8 | 3333.33 | root | data:Selection_7 |
| └─Selection_7 | 3333.33 | cop | gt(test.t.a, 2) |
| └─TableScan_6 | 10000.00 | cop | table:t, range:[-inf,+inf], keep order:false, stats:pseudo |
+-----------------------+----------+------+------------------------------------------------------------+
4 rows in set (0.00 sec)
注意:
运算符原始名称 | 运算符别名 |
---|---|
< | LT |
> | GT |
<= | LE |
>= | GT |
= | EQ |
!= | NE |
<> | NE |
<=> | NullEQ |
| | bitor |
&& | bitand |
|| | or |
! | not |
in | IN |
+ | PLUS |
- | MINUS |
* | MUL |
/ | DIV |
DIV | INTDIV |
IS NULL | ISNULL |
IS TRUE | ISTRUE |
IS FALSE | ISFALSE |