第12章函数和操作符

目录

12.1功能和操作员参考
12.2表达式评估中的类型转换
12.3运营商
12.3.1运营商优先顺序
12.3.2比较函数和运算符
12.3.3逻辑运算符
12.3.4赋值运算符
12.4控制流功能
12.5字符串函数
12.5.1字符串比较函数
12.5.2正则表达式
12.5.3函数结果的字符集和校对
12.6数字函数和运算符
12.6.1算术运算符
12.6.2数学函数
12。7日期和时间函数
12.8 MySQL使用什么日历?
12.9全文搜索功能
12.9.1自然语言全文检索
12.9.2布尔全文搜索
12.9.3使用查询扩展的全文搜索
12.9.4全文停用词
12.9.5全文限制
12.9.6微调MySQL全文搜索
12.9.7为全文索引添加排序规则
12.9.8 ngram全文分析器
12.9.9 MeCab全文分析器插件
12.10演员函数和运算符
12.11 XML函数
12.12位功能和操作符
12.13加密和压缩功能
12.14锁定功能
12.15信息功能
12.16空间分析功能
12.16.1空间函数参考
12.16.2空间函数的参数处理
12.16.3从WKT值创建几何值的函数
12.16.4从WKB值创建几何值的函数
12.16.5创建几何值的特定于MySQL的函数
12.16.6几何格式转换函数
12.16.7几何属性函数
12.16.8空间算子函数
12.16.9测试几何对象之间空间关系的函数
12.16.10空间Geohash函数
12.16.11空间GeoJSON函数
12.16.12空间便利函数
12.17 JSON函数
12.17.1 JSON函数参考
12.17.2创建JSON值的函数
12.17.3搜索JSON值的函数
12.17.4修改JSON值的函数
12.17.5返回JSON值属性的函数
12.17.6 JSON表函数
12.17.7 JSON模式验证函数
12.17.8 JSON实用程序函数
12.18与全局事务标识符(GTID)一起使用的函数
12.19 MySQL企业加密功能
12.19.1 MySQL Enterprise加密安装
12.19.2 MySQL Enterprise加密用法和示例
12.19.3 MySQL企业加密功能参考
12.19.4 MySQL企业加密功能描述
12.20聚合(GROUP BY)函数
12.20.1聚合(GROUP BY)功能描述
12.20.2 GROUP BY修饰符
12.20.3 GROUP BY的MySQL处理
12.20.4功能依赖性的检测
12.21窗口函数
12.21.1窗口功能描述
12.21.2窗口函数概念和语法
12.21.3窗口功能框架规范
12.21.4命名为Windows
12.21.5窗口函数限制
12.22性能模式函数
12.23内部功能
12.24其他功能
12.25精度数学
12.25.1数值的类型
12.25.2 DECIMAL数据类型特征
12.25.3表达处理
12.25.4舍入行为
12.25.5精确数学例子

表达式可以在几个点中使用 SQL 语句,比如在 ORDER BY HAVING 子句 SELECT 语句时,在 WHERE 一个条款 SELECT DELETE UPDATE 陈述,或 SET 陈述。 表达式可以使用文字值,列值, NULL 内置函数,存储函数,用户定义函数和运算符 来编写 本章描述了在MySQL中编写表达式所允许的函数和运算符。 第24.2节“使用存储的例程” 第29.4节“向MySQL添加新函数” 中给出了编写存储函数和用户定义函数的说明。 有关 描述服务器如何解释对不同类型函数的引用的规则 请参见 第9.2.4节“函数名称解析和解析”

除非在特定函数或运算符的文档中另有说明,否则 包含的表达式 NULL 始终会生成一个 NULL 值。

注意

默认情况下,函数名称和后面的括号之间不能有空格。 这有助于MySQL解析器区分函数调用和对恰好与函数同名的表或列的引用。 但是,允许使用函数参数周围的空格。

您可以通过使用该 --sql-mode=IGNORE_SPACE 选项 启动它来告诉MySQL服务器在函数名后面接受空格 (请参见 第5.1.11节“服务器SQL模式” 。)单个客户端程序可以使用 CLIENT_IGNORE_SPACE 选项for 来请求此行为 mysql_real_connect() 在任何一种情况下,所有函数名称都成为保留字。

为简洁起见,本章中的大多数示例都 以缩写形式 显示 mysql 程序 的输出 而不是以这种格式显示示例:

MySQL的> SELECT MOD(29,9);
+ ----------- +
| mod(29,9)|
+ ----------- +
| 2 |
+ ----------- +
1行(0.00秒)

使用此格式:

MySQL的> SELECT MOD(29,9);
        - > 2

12.1功能和操作员参考

表12.1函数和操作符

名称 描述
ABS() 返回绝对值
ACOS() 返回反余弦
ADDDATE() 将时间值(间隔)添加到日期值
ADDTIME() 添加时间
AES_DECRYPT() 使用AES解密
AES_ENCRYPT() 使用AES加密
AND && 逻辑和
ANY_VALUE() 抑制ONLY_FULL_GROUP_BY值拒绝
ASCII() 返回最左侧字符的数值
ASIN() 返回圆弧正弦
= 分配值(作为 SET 语句的 一部分 ,或作为 语句中 SET 子句的 一部分 UPDATE
:= 分配值
ASYMMETRIC_DECRYPT() 使用私钥或公钥解密密文
ASYMMETRIC_DERIVE() 从非对称密钥导出对称密钥
ASYMMETRIC_ENCRYPT() 使用私钥或公钥加密明文
ASYMMETRIC_SIGN() 从摘要生成签名
ASYMMETRIC_VERIFY() 验证签名是否与摘要匹配
ATAN() 返回反正切
ATAN2() ATAN() 返回两个参数的反正切
AVG() 返回参数的平均值
BENCHMARK() 反复执行表达式
BETWEEN ... AND ... 检查值是否在值范围内
BIN() 返回包含数字的二进制表示的字符串
BIN_TO_UUID() 将二进制UUID转换为字符串
BINARY 将字符串转换为二进制字符串
BIT_AND() 按位返回AND
BIT_COUNT() 返回设置的位数
BIT_LENGTH() 以位为单位返回参数长度
BIT_OR() 按位返回OR
BIT_XOR() 按位返回异或
& 按位AND
~ 按位反转
| 按位OR
^ 按位异或
CAN_ACCESS_COLUMN() 限内部使用
CAN_ACCESS_DATABASE() 限内部使用
CAN_ACCESS_TABLE() 限内部使用
CAN_ACCESS_VIEW() 限内部使用
CASE 案例运营商
CAST() 将值转换为特定类型
CEIL() 返回不小于参数的最小整数值
CEILING() 返回不小于参数的最小整数值
CHAR() 返回传递的每个整数的字符
CHAR_LENGTH() 返回参数中的字符数
CHARACTER_LENGTH() CHAR_LENGTH()的同义词
CHARSET() 返回参数的字符集
COALESCE() 返回第一个非NULL参数
COERCIBILITY() 返回字符串参数的归类强制性值
COLLATION() 返回字符串参数的排序规则
COMPRESS() 将结果作为二进制字符串返回
CONCAT() 返回连接字符串
CONCAT_WS() 返回与分隔符连接
CONNECTION_ID() 返回连接的连接ID(线程ID)
CONV() 转换不同数字基数之间的数字
CONVERT() 将值转换为特定类型
CONVERT_TZ() 从一个时区转换为另一个时区
COS() 返回余弦
COT() 归还余切
COUNT() 返回返回的行数
COUNT(DISTINCT) 返回许多不同值的计数
CRC32() 计算循环冗余校验值
CREATE_ASYMMETRIC_PRIV_KEY() 创建私钥
CREATE_ASYMMETRIC_PUB_KEY() 创建公钥
CREATE_DH_PARAMETERS() 生成共享DH密钥
CREATE_DIGEST() 从字符串生成摘要
CUME_DIST() 累积分配值
CURDATE() 返回当前日期
CURRENT_DATE() CURRENT_DATE CURDATE()的同义词
CURRENT_ROLE() 返回当前活动角色
CURRENT_TIME() CURRENT_TIME CURTIME()的同义词
CURRENT_TIMESTAMP() CURRENT_TIMESTAMP 同义词NOW()
CURRENT_USER() CURRENT_USER 经过身份验证的用户名和主机名
CURTIME() 返回当前时间
DATABASE() 返回默认(当前)数据库名称
DATE() 提取日期或日期时间表达式的日期部分
DATE_ADD() 将时间值(间隔)添加到日期值
DATE_FORMAT() 格式化日期指定
DATE_SUB() 从日期中减去时间值(间隔)
DATEDIFF() 减去两个日期
DAY() DAYOFMONTH()的同义词
DAYNAME() 返回工作日的名称
DAYOFMONTH() 返回月中的某一天(0-31)
DAYOFWEEK() 返回参数的工作日索引
DAYOFYEAR() 返回一年中的某一天(1-366)
DECODE() 解码使用ENCODE()加密的字符串
DEFAULT() 返回表列的默认值
DEGREES() 将弧度转换为度数
DENSE_RANK() 其分区内当前行的排名,没有间隙
DES_DECRYPT() 解密一个字符串
DES_ENCRYPT() 加密字符串
DIV 整数除法
/ 分部运营商
ELT() 返回索引号处的字符串
ENCODE() 编码一个字符串
ENCRYPT() 加密字符串
= 平等的运营商
<=> NULL-safe等于运算符
EXP() 提升到的力量
EXPORT_SET() 返回一个字符串,使得对于值位中设置的每个位,您获得一个on字符串,并且对于每个未设置的位,您将获得一个关闭字符串
EXTRACT() 提取部分日期
ExtractValue() 使用XPath表示法从XML字符串中提取值
FIELD() 后续参数中第一个参数的索引(位置)
FIND_IN_SET() 第二个参数中第一个参数的索引(位置)
FIRST_VALUE() 窗口框架第一行的参数值
FLOOR() 返回不大于参数的最大整数值
FORMAT() 返回格式化为指定小数位数的数字
FORMAT_BYTES() 将字节数转换为带单位的值
FORMAT_PICO_TIME() 将时间(皮秒)转换为单位值
FOUND_ROWS() 对于带有LIMIT子句的SELECT,返回的行数没有LIMIT子句
FROM_BASE64() 解码base64编码的字符串并返回结果
FROM_DAYS() 将日期号码转换为日期
FROM_UNIXTIME() 将Unix时间戳格式化为日期
GeomCollection() 从几何构造几何集合
GeometryCollection() 从几何构造几何集合
GET_DD_COLUMN_PRIVILEGES() 限内部使用
GET_DD_CREATE_OPTIONS() 限内部使用
GET_DD_INDEX_SUB_PART_LENGTH() 限内部使用
GET_FORMAT() 返回日期格式字符串
GET_LOCK() 获取命名锁
> 大于运营商
>= 大于或等于运营商
GREATEST() 返回最大的参数
GROUP_CONCAT() 返回连接的字符串
GROUPING() 区分超级聚合ROLLUP行与常规行
GTID_SUBSET() 如果子集中的所有GTID也已设置,则返回true;否则返回true。 否则是假的。
GTID_SUBTRACT() 返回集合中不在子集中的所有GTID。
HEX() 十进制或字符串值的十六进制表示
HOUR() 提取小时
ICU_VERSION() ICU库版本
IF() 如果/ else构造
IFNULL() Null if / else构造
IN() 检查值是否在一组值内
INET_ATON() 返回IP地址的数值
INET_NTOA() 从数值返回IP地址
INET6_ATON() 返回IPv6地址的数值
INET6_NTOA() 从数值返回IPv6地址
INSERT() 在指定位置插入子字符串,直到指定的字符数
INSTR() 返回第一次出现的子串的索引
INTERNAL_AUTO_INCREMENT() 限内部使用
INTERNAL_AVG_ROW_LENGTH() 限内部使用
INTERNAL_CHECK_TIME() 限内部使用
INTERNAL_CHECKSUM() 限内部使用
INTERNAL_DATA_FREE() 限内部使用
INTERNAL_DATA_LENGTH() 限内部使用
INTERNAL_DD_CHAR_LENGTH() 限内部使用
INTERNAL_GET_COMMENT_OR_ERROR() 限内部使用
INTERNAL_GET_VIEW_WARNING_OR_ERROR() 限内部使用
INTERNAL_INDEX_COLUMN_CARDINALITY() 限内部使用
INTERNAL_INDEX_LENGTH() 限内部使用
INTERNAL_KEYS_DISABLED() 限内部使用
INTERNAL_MAX_DATA_LENGTH() 限内部使用
INTERNAL_TABLE_ROWS() 限内部使用
INTERNAL_UPDATE_TIME() 限内部使用
INTERVAL() 返回小于第一个参数的参数的索引
IS 针对布尔值测试值
IS_FREE_LOCK() 命名锁是否免费
IS_IPV4() 参数是否为IPv4地址
IS_IPV4_COMPAT() 参数是否是IPv4兼容的地址
IS_IPV4_MAPPED() 参数是否是IPv4映射地址
IS_IPV6() 参数是否是IPv6地址
IS NOT 针对布尔值测试值
IS NOT NULL NOT NULL值测试
IS NULL NULL值测试
IS_USED_LOCK() 命名锁是否正在使用; 返回连接标识符,如果为true
IS_UUID() 参数是否是有效的UUID
ISNULL() 测试参数是否为NULL
JSON_ARRAY() 创建JSON数组
JSON_ARRAY_APPEND() 将数据附加到JSON文档
JSON_ARRAY_INSERT() 插入JSON数组
JSON_ARRAYAGG() 将结果集作为单个JSON数组返回
-> 评估路径后从JSON列返回值; 相当于JSON_EXTRACT()。
JSON_CONTAINS() JSON文档是否包含路径中的特定对象
JSON_CONTAINS_PATH() JSON文档是否包含路径中的任何数据
JSON_DEPTH() JSON文档的最大深度
JSON_EXTRACT() 从JSON文档返回数据
->> 在评估路径并取消引用结果后,从JSON列返回值; 相当于JSON_UNQUOTE(JSON_EXTRACT())。
JSON_INSERT() 将数据插入JSON文档
JSON_KEYS() 来自JSON文档的键数组
JSON_LENGTH() JSON文档中的元素数量
JSON_MERGE() (已弃用8.0.3) 合并JSON文档,保留重复键。 JSON_MERGE_PRESERVE()的弃用词不再使用
JSON_MERGE_PATCH() 合并JSON文档,替换重复键的值
JSON_MERGE_PRESERVE() 合并JSON文档,保留重复键
JSON_OBJECT() 创建JSON对象
JSON_OBJECTAGG() 将结果集作为单个JSON对象返回
JSON_OVERLAPS() 比较两个JSON文档,如果它们具有任何共同的键值对或数组元素,则返回TRUE(1),否则返回FALSE(0)
JSON_PRETTY() 以人类可读的格式打印JSON文档
JSON_QUOTE() 引用JSON文档
JSON_REMOVE() 从JSON文档中删除数据
JSON_REPLACE() 替换JSON文档中的值
JSON_SCHEMA_VALID() 根据JSON模式验证JSON文档; 如果文档针对模式进行验证,则返回TRUE / 1;否则返回FALSE / 0
JSON_SCHEMA_VALIDATION_REPORT() 根据JSON模式验证JSON文档; 以JSON格式返回有关验证结果的报告,包括成功或失败以及失败原因
JSON_SEARCH() JSON文档中的值路径
JSON_SET() 将数据插入JSON文档
JSON_STORAGE_FREE() 在部分更新之后释放JSON列值的二进制表示内的空间
JSON_STORAGE_SIZE() 用于存储JSON文档的二进制表示的空间
JSON_TABLE() 将JSON表达式中的数据作为关系表返回
JSON_TYPE() JSON值的类型
JSON_UNQUOTE() 取消引用JSON值
JSON_VALID() JSON值是否有效
LAG() 行中滞后当前行的参数值
LAST_DAY 返回参数的月份的最后一天
LAST_INSERT_ID() 最后一次INSERT的AUTOINCREMENT列的值
LAST_VALUE() 窗口框架最后一行的参数值
LCASE() LOWER()的同义词
LEAD() 分区中行前导行的参数值
LEAST() 返回最小的参数
LEFT() 返回指定的最左边的字符数
<< 左移
LENGTH() 以字节为单位返回字符串的长度
< 不到运营商
<= 小于或等于运营商
LIKE 简单的模式匹配
LineString() 从Point值构造LineString
LN() 返回参数的自然对数
LOAD_FILE() 加载指定的文件
LOCALTIME() LOCALTIME NOW()的同义词
LOCALTIMESTAMP LOCALTIMESTAMP() NOW()的同义词
LOCATE() 返回第一次出现的子串的位置
LOG() 返回第一个参数的自然对数
LOG10() 返回参数的以10为底的对数
LOG2() 返回参数的base-2对数
LOWER() 以小写形式返回参数
LPAD() 返回字符串参数,使用指定的字符串进行左填充
LTRIM() 删除前导空格
MAKE_SET() 返回一组以逗号分隔的字符串,这些字符串具有相应的位设置位
MAKEDATE() 创建年份和年中的日期
MAKETIME() 从小时,分钟,秒创建时间
MASTER_POS_WAIT() 阻止,直到从站已读取并应用所有更新到指定位置
MATCH 执行全文搜索
MAX() 返回最大值
MBRContains() 一个几何的MBR是否包含另一个几何的MBR
MBRCoveredBy() 一个MBR是否被另一个MBR覆盖
MBRCovers() 一个MBR是否涵盖另一个MBR
MBRDisjoint() 两个几何形状的MBR是否不相交
MBREquals() 两个几何的MBR是否相等
MBRIntersects() 两个几何的MBR是否相交
MBROverlaps() 两个几何的MBR是否重叠
MBRTouches() 两种几何形状的MBR是否接触
MBRWithin() 一个几何的MBR是否在另一个几何的MBR内
MD5() 计算MD5校验和
MEMBER OF() 如果第一个操作数匹配作为第二个操作数传递的JSON数组的任何元素,则返回true(1),否则返回false(0)
MICROSECOND() 从参数返回微秒
MID() 返回从指定位置开始的子字符串
MIN() 返回最小值
- 减号运算符
MINUTE() 从论证中返回分钟
MOD() 归还剩下的
% MOD 模数运算符
MONTH() 从过去的日期返回月份
MONTHNAME() 返回月份名称
MultiLineString() 从LineString值构造MultiLineString
MultiPoint() 从Point值构造MultiPoint
MultiPolygon() 从Polygon值构造MultiPolygon
NAME_CONST() 导致列具有给定名称
NOT ! 否定价值
NOT BETWEEN ... AND ... 检查值是否不在值范围内
!= <> 不等于运营商
NOT IN() 检查值是否不在一组值内
NOT LIKE 简单模式匹配的否定
NOT REGEXP REGEXP的否定
NOW() 返回当前日期和时间
NTH_VALUE() 第N行窗口框架的参数值
NTILE() 其分区中当前行的存储桶编号。
NULLIF() 如果expr1 = expr2,则返回NULL
OCT() 返回包含数字的八进制表示的字符串
OCTET_LENGTH() LENGTH()的同义词
OR || 逻辑或
ORD() 返回参数最左侧字符的字符代码
PASSWORD() 计算并返回密码字符串
PERCENT_RANK() 百分比等级值
PERIOD_ADD() 将期间添加到年 - 月
PERIOD_DIFF() 返回句点之间的月数
PI() 返回pi的值
+ 加法运算符
Point() 从坐标构造点
Polygon() 从LineString参数构造多边形
POSITION() LOCATE()的同义词
POW() 将引发的参数返回到指定的幂
POWER() 将引发的参数返回到指定的幂
PS_CURRENT_THREAD_ID() 当前线程的性能架构线程ID
PS_THREAD_ID() 给定线程的性能架构线程ID
QUARTER() 从日期参数返回季度
QUOTE() 转义参数以在SQL语句中使用
RADIANS() 返回参数转换为弧度
RAND() 返回随机浮点值
RANDOM_BYTES() 返回一个随机字节向量
RANK() 其分区内当前行的排名,有差距
REGEXP string是否匹配正则表达式
REGEXP_INSTR() 匹配正则表达式的子串的起始索引
REGEXP_LIKE() string是否匹配正则表达式
REGEXP_REPLACE() 替换匹配正则表达式的子字符串
REGEXP_SUBSTR() 返回子串匹配正则表达式
RELEASE_ALL_LOCKS() 释放所有当前命名的锁
RELEASE_LOCK() 释放命名锁
REPEAT() 重复指定次数的字符串
REPLACE() 替换指定字符串的出现次数
REVERSE() 反转字符串中的字符
RIGHT() 返回指定的最右边的字符数
>> 右转
RLIKE string是否匹配正则表达式
ROLES_GRAPHML() 返回表示内存角色子图的GraphML文档
ROUND() 围绕论点
ROW_COUNT() 行数已更新
ROW_NUMBER() 其分区中当前行的数量
RPAD() 追加指定次数的字符串
RTRIM() 删除尾随空格
SCHEMA() DATABASE()的同义词
SEC_TO_TIME() 将秒转换为'hh:mm:ss'格式
SECOND() 返回秒(0-59)
SESSION_USER() USER()的同义词
SHA1() SHA() 计算SHA-1 160位校验和
SHA2() 计算SHA-2校验和
SIGN() 返回参数的符号
SIN() 返回参数的正弦值
SLEEP() 睡几秒钟
SOUNDEX() 返回soundex字符串
SOUNDS LIKE 比较声音
SPACE() 返回指定数量的空格的字符串
SQRT() 返回参数的平方根
ST_Area() 返回Polygon或MultiPolygon区域
ST_AsBinary() ST_AsWKB() 从内部几何格式转换为WKB
ST_AsGeoJSON() 从几何体生成GeoJSON对象
ST_AsText() ST_AsWKT() 从内部几何格式转换为WKT
ST_Buffer() 返回距离几何体的给定距离内的点的几何
ST_Buffer_Strategy() 为ST_Buffer()生成策略选项
ST_Centroid() 返回质心作为一个点
ST_Contains() 一个几何是否包含另一个
ST_ConvexHull() 返回几何体的凸包
ST_Crosses() 一个几何是否与另一个几何相交
ST_Difference() 两个几何的返回点集差异
ST_Dimension() 几何尺寸
ST_Disjoint() 一个几何是否与另一个几何脱节
ST_Distance() 一个几何与另一个几何的距离
ST_Distance_Sphere() 两个几何形状之间的最小地球距离
ST_EndPoint() LineString的终点
ST_Envelope() 返回几何的MBR
ST_Equals() 一个几何是否与另一个几何相等
ST_ExteriorRing() 返回Polygon的外环
ST_GeoHash() 产生geohash值
ST_GeomCollFromText() ST_GeometryCollectionFromText() ST_GeomCollFromTxt() 从WKT返回几何集合
ST_GeomCollFromWKB() ST_GeometryCollectionFromWKB() 从WKB返回几何集合
ST_GeometryN() 从几何集合中返回第N个几何
ST_GeometryType() 返回几何类型的名称
ST_GeomFromGeoJSON() 从GeoJSON对象生成几何
ST_GeomFromText() ST_GeometryFromText() 从WKT返回几何
ST_GeomFromWKB() ST_GeometryFromWKB() 从WKB返回几何
ST_InteriorRingN() 返回Polygon的第N个内环
ST_Intersection() 返回点设置两个几何的交集
ST_Intersects() 一个几何是否与另一个相交
ST_IsClosed() 几何是否封闭且简单
ST_IsEmpty() 占位符功能
ST_IsSimple() 几何是否简单
ST_IsValid() 几何是否有效
ST_LatFromGeoHash() 从geohash值返回纬度
ST_Latitude() 返回Point的纬度
ST_Length() 返回LineString的长度
ST_LineFromText() ST_LineStringFromText() 从WKT构造LineString
ST_LineFromWKB() ST_LineStringFromWKB() 从WKB构造LineString
ST_LongFromGeoHash() 从geohash值返回经度
ST_Longitude() 返回Point的经度
ST_MakeEnvelope() 两点左右的矩形
ST_MLineFromText() ST_MultiLineStringFromText() 从WKT构造MultiLineString
ST_MLineFromWKB() ST_MultiLineStringFromWKB() 从WKB构造MultiLineString
ST_MPointFromText() ST_MultiPointFromText() 从WKT构造MultiPoint
ST_MPointFromWKB() ST_MultiPointFromWKB() 从WKB构造MultiPoint
ST_MPolyFromText() ST_MultiPolygonFromText() 从WKT构造MultiPolygon
ST_MPolyFromWKB() ST_MultiPolygonFromWKB() 从WKB构造MultiPolygon
ST_NumGeometries() 返回几何集合中的几何数量
ST_NumInteriorRing() ST_NumInteriorRings() 返回多边形内圈的数量
ST_NumPoints() 返回LineString中的点数
ST_Overlaps() 一个几何是否与另一个重叠
ST_PointFromGeoHash() 将geohash值转换为POINT值
ST_PointFromText() 从WKT构建点
ST_PointFromWKB() 从WKB构造点
ST_PointN() 从LineString返回第N个点
ST_PolyFromText() ST_PolygonFromText() 从WKT构造多边形
ST_PolyFromWKB() ST_PolygonFromWKB() 从WKB构造多边形
ST_Simplify() 返回简化几何
ST_SRID() 返回几何的空间参考系统ID
ST_StartPoint() LineString的起始点
ST_SwapXY() 交换X / Y坐标的返回参数
ST_SymDifference() 返回点设置两个几何的对称差异
ST_Touches() 一个几何是否接触另一个
ST_Transform() 变换几何的坐标
ST_Union() 返回点集两个几何的并集
ST_Validate() 返回验证的几何体
ST_Within() 一个几何是否在另一个之内
ST_X() 返回Point的X坐标
ST_Y() 返回Point的Y坐标
STATEMENT_DIGEST() 计算语句摘要哈希值
STATEMENT_DIGEST_TEXT() 计算规范化语句摘要
STD() 返回人口标准差
STDDEV() 返回人口标准差
STDDEV_POP() 返回人口标准差
STDDEV_SAMP() 返回样本标准差
STR_TO_DATE() 将字符串转换为日期
STRCMP() 比较两个字符串
SUBDATE() 使用三个参数调用时DATE_SUB()的同义词
SUBSTR() 返回指定的子字符串
SUBSTRING() 返回指定的子字符串
SUBSTRING_INDEX() 在指定的分隔符出现次数之前从字符串返回子字符串
SUBTIME() 减去时间
SUM() 归还总和
SYSDATE() 返回函数执行的时间
SYSTEM_USER() USER()的同义词
TAN() 返回参数的正切值
TIME() 提取传递的表达式的时间部分
TIME_FORMAT() 格式化为时间
TIME_TO_SEC() 返回转换为秒的参数
TIMEDIFF() 减去时间
* 乘法运算符
TIMESTAMP() 使用单个参数,此函数返回日期或日期时间表达式; 有两个参数,参数的总和
TIMESTAMPADD() 在datetime表达式中添加间隔
TIMESTAMPDIFF() 从日期时间表达式中减去间隔
TO_BASE64() 返回转换为base-64字符串的参数
TO_DAYS() 返回转换为days的日期参数
TO_SECONDS() 返回自0年以来转换为秒的日期或日期时间参数
TRIM() 删除前导和尾随空格
TRUNCATE() 截断到指定的小数位数
UCASE() UPPER()的同义词
- 更改参数的符号
UNCOMPRESS() 解压缩压缩的字符串
UNCOMPRESSED_LENGTH() 压缩前返回字符串的长度
UNHEX() 返回包含数字的十六进制表示的字符串
UNIX_TIMESTAMP() 返回Unix时间戳
UpdateXML() 返回替换的XML片段
UPPER() 转换为大写
USER() 客户端提供的用户名和主机名
UTC_DATE() 返回当前的UTC日期
UTC_TIME() 返回当前的UTC时间
UTC_TIMESTAMP() 返回当前的UTC日期和时间
UUID() 返回通用唯一标识符(UUID)
UUID_SHORT() 返回整数值通用标识符
UUID_TO_BIN() 将字符串UUID转换为二进制
VALIDATE_PASSWORD_STRENGTH() 确定密码的强度
VALUES() 定义INSERT期间要使用的值
VAR_POP() 返回人口标准差异
VAR_SAMP() 返回样本方差
VARIANCE() 返回人口标准差异
VERSION() 返回表示MySQL服务器版本的字符串
WAIT_FOR_EXECUTED_GTID_SET() 等到给定的GTID在slave上执行。
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 等到给定的GTID在slave上执行。
WEEK() 返回周数
WEEKDAY() 返回工作日索引
WEEKOFYEAR() 返回日期的日历周(1-53)
WEIGHT_STRING() 返回字符串的权重字符串
XOR 逻辑异或
YEAR() 回归年份
YEARWEEK() 返回年份和星期

12.2表达式评估中的类型转换

当操作符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。 某些转换是隐式发生的。 例如,MySQL会根据需要自动将字符串转换为数字,反之亦然。

MySQL的> SELECT 1+'1';
        - > 2
MySQL的> SELECT CONCAT(2,' test');
        - >'2测试'

也可以使用该 CAST() 函数 显式地将数字转换为字符串 转换与 CONCAT() 函数 隐式发生, 因为它需要字符串参数。

MySQL的> SELECT 38.8, CAST(38.8 AS CHAR);
        - > 38.8,'38 .8'
MySQL的> SELECT 38.8, CONCAT(38.8);
        - > 38.8,'38 .8'

有关隐式数字到字符串转换的字符集以及适用于 CREATE TABLE ... SELECT 语句的已 修改规则的信息,请参阅本节后面的内容

以下规则描述了比较操作的转换方式:

  • 如果是一个或两个参数 NULL ,则比较的结果是 NULL ,除了 NULL -safe <=> 等式比较运算符。 因为 NULL <=> NULL ,结果是真的。 无需转换。

  • 如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。

  • 如果两个参数都是整数,则将它们作为整数进行比较。

  • 如果不与数字进行比较,十六进制值将被视为二进制字符串。

  • 如果其中一个参数是a TIMESTAMP DATETIME 列而另一个参数是常量,则在执行比较之前将常量转换为时间戳。 这样做是为了更友好的ODBC。 这不是针对参数的 IN() 为安全起见,在进行比较时始终使用完整的日期时间,日期或时间字符串。 例如,要在使用 BETWEEN 日期或时间值 时获得最佳结果 ,请使用 CAST() 显式将值转换为所需的数据类型。

    来自一个或多个表的单行子查询不被视为常量。 例如,如果子查询返回要与 DATETIME 进行比较的整数 ,则比较将作为两个整数完成。 整数不会转换为时间值。 要将操作数作为 DATETIME 进行比较 ,请使用 CAST() 显式转换子查询值 DATETIME

  • 如果其中一个参数是十进制值,则比较取决于另一个参数。 如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较,如果另一个参数是浮点值,则将参数作为浮点值进行比较。

  • 在所有其他情况下,参数被比较为浮点(实数)。

有关将值从一种时间类型转换为另一种时间类型的信息,请参见 第11.3.6节“日期和时间类型之间的转换”

JSON值的比较发生在两个级别。 第一级比较基于比较值的JSON类型。 如果类型不同,则比较结果仅由哪种类型具有更高优先级来确定。 如果这两个值具有相同的JSON类型,则使用特定于类型的规则进行第二级比较。 为了比较JSON和非JSON值,将非JSON值转换为JSON,并将值作为JSON值进行比较。 有关详细信息,请参阅 JSON值的比较和排序

以下示例说明了将字符串转换为数字以进行比较操作:

MySQL的> SELECT 1 > '6x';
        - > 0
MySQL的> SELECT 7 > '6x';
        - > 1
MySQL的> SELECT 0 > 'x6';
        - > 0
MySQL的> SELECT 0 = 'x6';
        - > 1

为了比较字符串列和数字,MySQL不能使用列上的索引来快速查找值。 如果 str_col 是索引字符串列,则在以下语句中执行查找时,不能使用索引:

SELECT * FROM tbl_nameWHERE str_col= 1;

这样做的原因是,有许多不同的字符串可以转换为价值 1 ,例如 '1' ' 1' '1a'

使用浮点数(或转换为浮点数的值)的比较是近似的,因为这些数字是不精确的。 这可能会导致结果看起来不一致:

MySQL的> SELECT '18015376320243458' = 18015376320243458;
        - > 1
MySQL的> SELECT '18015376320243459' = 18015376320243459;
        - > 0

这样的结果可能会发生,因为值被转换为浮点数,它只有53位的精度并且可以进行舍入:

MySQL的> SELECT '18015376320243459'+0.0;
        - > 1.8015376320243e + 16

此外,从字符串到浮点以及从整数到浮点的转换不一定以相同的方式发生。 整数可以由CPU转换为浮点数,而字符串在涉及浮点乘法的运算中逐位转换。

显示的结果将因系统而异,并且可能受计算机体系结构或编译器版本或优化级别等因素的影响。 避免此类问题的一种方法是使用, CAST() 以便不将值隐式转换为浮点数:

MySQL的> SELECT CAST('18015376320243459' AS UNSIGNED) = 18015376320243459;
        - > 1

有关浮点比较的更多信息,请参见 第B.4.4.8节“浮点值的问题”

服务器包括 dtoa 一个转换库,它提供了改进字符串或 DECIMAL 值与近似值( FLOAT / DOUBLE )数字 之间转换的基础

  • 跨平台的一致转换结果,例如,消除了Unix与Windows转换差异。

  • 在结果先前未提供足够精度的情况下精确表示值,例如接近IEEE限制的值。

  • 将数字转换为字符串格式,并尽可能精确。 精度 dtoa 始终与标准C库函数 的精度 相同或更好。

由于此库生成的转换在某些情况下与非 dtoa 结果不同,因此可能存在依赖于先前结果的应用程序中的不兼容性。 例如,依赖于先前转换的特定精确结果的应用程序可能需要进行调整以适应额外的精度。

dtoa 库提供具有以下属性的转换。 D 表示具有 DECIMAL 或字符串 表示的值 ,并 F 表示本机二进制(IEEE)格式的浮点数。

  • F - > D 转换以尽可能高的精度完成,返回 D F 读回时 产生的最短字符串, 并以IEEE指定的本机二进制格式舍入为最接近的值。

  • D - > F 转换完成,这 F 是输入十进制字符串最接近的本机二进制数 D

这些性质暗示 F - > D - > F 转换是无损除非 F -inf +inf ,或 NaN 不支持后面的值,因为SQL标准将它们定义为 FLOAT or的 无效值 DOUBLE

对于 D - > F - > D 转换,用于losslessness的充分条件是, D 使用的精度15个或更少位数字,是不是反规范值, -inf +inf ,或 NaN 在某些情况下,即使 D 精度超过15位, 转换也是无损 的,但情况并非总是如此。

将数值或时间值隐式转换为字符串会生成一个值,该值具有由 系统变量 character_set_connection collation_connection 系统变量 确定的字符集和排序规则 (这些变量通常设置为 SET NAMES 。有关连接字符集的信息,请参见 第10.4节“连接字符集和排序” 。)

这意味着,这样的转换结果中的字符(非二进制的)字符串(一个 CHAR VARCHAR LONGTEXT 值),除了在该连接字符集设置到壳体 binary 在这种情况下,转换结果是一个二进制串(一个 BINARY VARBINARY LONGBLOB 值)。

对于整数表达式,约表达前述备注 评价 申请略有不同表达 分配 ; 例如,在这样的声明中:

CREATE TABLE t SELECT integer_expr;

在这种情况下,由表达式生成的列中的表具有类型 INT BIGINT 取决于整数表达式的长度。 如果表达式的最大长度不适合 INT BIGINT 则使用。 长度取自 结果集元数据 max_length SELECT (请参见 第28.7.5节“C API数据结构” )。 这意味着您可以强制使用 BIGINT 而不是 INT 使用足够长的表达式:

CREATE TABLE t SELECT 000000000000000000000;

12.3运营商

表12.2运算符

名称 描述
AND && 逻辑和
= 分配值(作为 SET 语句的 一部分 ,或作为 语句中 SET 子句的 一部分 UPDATE
:= 分配值
BETWEEN ... AND ... 检查值是否在值范围内
BINARY 将字符串转换为二进制字符串
& 按位AND
~ 按位反转
| 按位OR
^ 按位异或
CASE 案例运营商
DIV 整数除法
/ 分部运营商
= 平等的运营商
<=> NULL-safe等于运算符
> 大于运营商
>= 大于或等于运营商
IN() 检查值是否在一组值内
IS 针对布尔值测试值
IS NOT 针对布尔值测试值
IS NOT NULL NOT NULL值测试
IS NULL NULL值测试
-> 评估路径后从JSON列返回值; 相当于JSON_EXTRACT()。
->> 在评估路径并取消引用结果后,从JSON列返回值; 相当于JSON_UNQUOTE(JSON_EXTRACT())。
<< 左移
< 不到运营商
<= 小于或等于运营商
LIKE 简单的模式匹配
MEMBER OF() 如果第一个操作数匹配作为第二个操作数传递的JSON数组的任何元素,则返回true(1),否则返回false(0)
- 减号运算符
% MOD 模数运算符
NOT ! 否定价值
NOT BETWEEN ... AND ... 检查值是否不在值范围内
!= <> 不等于运营商
NOT IN() 检查值是否不在一组值内
NOT LIKE 简单模式匹配的否定
NOT REGEXP REGEXP的否定
OR || 逻辑或
+ 加法运算符
REGEXP string是否匹配正则表达式
>> 右转
RLIKE string是否匹配正则表达式
SOUNDS LIKE 比较声音
* 乘法运算符
- 更改参数的符号
XOR 逻辑异或

12.3.1运营商优先顺序

运算符优先级显示在以下列表中,从最高优先级到最低优先级。 一行显示的运算符具有相同的优先级。

间隔
BINARY,COLLATE
- (一元减号),〜(一元位反转)
^
*,/,DIV,%,MOD
- ,+
<<,>>
|
=(比较),<=>,> =,>,<=,<,<>,!=,IS,LIKE,REGEXP,IN
之间,情况,时间,然后,那么
AND,&&
XOR
或者,||
=(赋值),:=

优先级 = 取决于它是用作比较运算符( = )还是用作赋值运算符( = )。 当作为比较操作符使用,它具有相同的优先级 <=> >= > <= < <> != IS LIKE REGEXP ,和 IN 当用作赋值运算符时,它具有相同的优先级 := 第13.7.5.1节“变量赋值的SET语法” 第9.4节“用户定义的变量” 解释了MySQL如何确定 = 应该适用。

对于在表达式中以相同优先级发生的运算符,评估从左到右进行,但赋值从右到左进行求值。

一些运算符的优先级和含义取决于SQL模式:

  • 默认情况下,它 || 是一个逻辑 OR 运算符。 PIPES_AS_CONCAT 启用, || 是字符串连接,与之间的优先级 ^ 和元运算符。

  • 默认情况下, ! 优先级高于 NOT 随着 HIGH_NOT_PRECEDENCE 启用, ! 并且 NOT 具有相同的优先级。

请参见 第5.1.11节“服务器SQL模式”

运算符的优先级决定了表达式中术语的评估顺序。 要明确覆盖此订单和组术语,请使用括号。 例如:

MySQL的> SELECT 1+2*3;
        - > 7
MySQL的> SELECT (1+2)*3;
        - > 9

12.3.2比较函数和运算符

表12.3比较运算符

名称 描述
BETWEEN ... AND ... 检查值是否在值范围内
COALESCE() 返回第一个非NULL参数
= 平等的运营商
<=> NULL-safe等于运算符
> 大于运营商
>= 大于或等于运营商
GREATEST() 返回最大的参数
IN() 检查值是否在一组值内
INTERVAL() 返回小于第一个参数的参数的索引
IS 针对布尔值测试值
IS NOT 针对布尔值测试值
IS NOT NULL NOT NULL值测试
IS NULL NULL值测试
ISNULL() 测试参数是否为NULL
LEAST() 返回最小的参数
< 不到运营商
<= 小于或等于运营商
LIKE 简单的模式匹配
NOT BETWEEN ... AND ... 检查值是否不在值范围内
!= <> 不等于运营商
NOT IN() 检查值是否不在一组值内
NOT LIKE 简单模式匹配的否定
STRCMP() 比较两个字符串

比较操作导致值为 1 TRUE ), 0 FALSE )或 NULL 这些操作适用于数字和字符串。 根据需要,字符串会自动转换为数字和数字。

以下关系比较运算符不仅可用于比较标量操作数,还可用于比较行操作数:

=> <> = <= <>!=

本节后面的那些操作符的描述详细说明了它们如何与行操作数一起使用。 有关行子查询上下文中行比较的其他示例,请参见 第13.2.11.5节“行子查询”

本节中的某些函数返回除 1 TRUE ), 0 FALSE )或之外的值 NULL LEAST() 并且 GREATEST() 是这些功能的例子; 第12.2节“表达式评估中的类型转换” 描述了由这些和类似函数执行的比较操作的规则,用于确定它们的返回值。

注意

在MySQL的 早期 版本中,当评估包含 LEAST() or 的表达式时 GREATEST() ,服务器试图猜测使用该函数的上下文,并强制函数的参数作为整体表达式的数据类型。 例如,要对参数进行 LEAST("11", "45", "2") 求值并将其排序为字符串,以便返回此表达式 "11" 在MySQL 8.0.3及更早版本中,在计算表达式时 LEAST("11", "45", "2") + 0 ,服务器在对它们进行排序之前将参数转换为整数(预期向结果添加整数0),从而返回2。

从MySQL 8.0.4开始,服务器不再尝试以这种方式推断上下文。 相反,该函数使用提供的参数执行,对一个或多个参数执行数据类型转换,当且仅当它们不是全部相同类型时。 现在,在函数执行之后执行由使用返回值的表达式强制执行的任何类型强制。 这意味着,在MySQl 8.0.4及更高版本中, LEAST("11", "45", "2") + 0 计算结果为 "11" + 0 11,因此 计算结果为 11.(Bug#83895,Bug#25123839)

要将值转换为特定类型以进行比较,可以使用该 CAST() 函数。 可以使用将字符串值转换为不同的字符集 CONVERT() 请参见 第12.10节“强制转换函数和运算符”

默认情况下,字符串比较不区分大小写并使用当前字符集。 默认是 utf8mb4

  • =

    等于:

    MySQL的> SELECT 1 = 0;
            - > 0
    MySQL的> SELECT '0' = 0;
            - > 1
    MySQL的> SELECT '0.0' = 0;
            - > 1
    MySQL的> SELECT '0.01' = 0;
            - > 0
    MySQL的> SELECT '.01' = 0.01;
            - > 1
    

    对于行比较, (a, b) = (x, y) 相当于:

    (a = x)AND(b = y)
    
  • <=>

    NULL - 等于。 这个运算符像 = 运算符 一样执行相等比较 ,但返回 1 而不是 NULL 两个操作数都是 NULL 0 而不是 NULL 一个操作数 NULL

    <=> 操作相当于标准的SQL IS NOT DISTINCT FROM 操作。

    MySQL的> SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
            - > 1,1,0
    MySQL的> SELECT 1 = 1, NULL = NULL, 1 = NULL;
            - > 1,NULL,NULL
    

    对于行比较, (a, b) <=> (x, y) 相当于:

    (a <=> x)AND(b <=> y)
    
  • <> !=

    不相等:

    MySQL的> SELECT '.01' <> '0.01';
            - > 1
    MySQL的> SELECT .01 <> '0.01';
            - > 0
    MySQL的> SELECT 'zapp' <> 'zappp';
            - > 1
    

    对于行比较, (a, b) <> (x, y) (a, b) != (x, y) 等同于:

    (a <> x)OR(b <> y)
    
  • <=

    小于或等于:

    MySQL的> SELECT 0.1 <= 2;
            - > 1
    

    对于行比较, (a, b) <= (x, y) 相当于:

    (a <x)OR((a = x)AND(b <= y))
    
  • <

    少于:

    MySQL的> SELECT 2 < 2;
            - > 0
    

    对于行比较, (a, b) < (x, y) 相当于:

    (a <x)OR((a = x)AND(b <y))
    
  • >=

    大于或等于:

    MySQL的> SELECT 2 >= 2;
            - > 1
    

    对于行比较, (a, b) >= (x, y) 相当于:

    (a> x)OR((a = x)AND(b> = y))
    
  • >

    比...更棒:

    MySQL的> SELECT 2 > 2;
            - > 0
    

    对于行比较, (a, b) > (x, y) 相当于:

    (a> x)OR((a = x)AND(b> y))
    
  • IS boolean_value

    测试针对一个布尔值,其中值 boolean_value 可以是 TRUE FALSE ,或 UNKNOWN

    MySQL的> SELECT 1 IS TRUE, 0 IS FALSE, NULL IS UNKNOWN;
            - > 1,1,1
    
  • IS NOT boolean_value

    测试针对一个布尔值,其中值 boolean_value 可以是 TRUE FALSE ,或 UNKNOWN

    MySQL的> SELECT 1 IS NOT UNKNOWN, 0 IS NOT UNKNOWN, NULL IS NOT UNKNOWN;
            - > 1,1,0
    
  • IS NULL

    测试值是否为 NULL

    MySQL的> SELECT 1 IS NULL, 0 IS NULL, NULL IS NULL;
            - > 0,0,1
    

    为了与ODBC程序配合使用,MySQL在使用时支持以下额外功能 IS NULL

  • IS NOT NULL

    测试值是否不是 NULL

    MySQL的> SELECT 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;
            - > 1,1,0
    
  • expr BETWEEN min AND max

    如果 expr 大于或等于 min expr 小于或等于 max ,则 BETWEEN 返回 1 ,否则返回 0 如果所有参数都是相同类型,则 这相当于表达式 否则,类型转换将根据 第12.2节“表达式评估中的类型转换”中 所述的规则进行 ,但应用于所有三个参数。 (min <= expr AND expr <= max)

    MySQL的> SELECT 2 BETWEEN 1 AND 3, 2 BETWEEN 3 and 1;
            - > 1,0
    MySQL的> SELECT 1 BETWEEN 2 AND 3;
            - > 0
    MySQL的> SELECT 'b' BETWEEN 'a' AND 'c';
            - > 1
    MySQL的> SELECT 2 BETWEEN 2 AND '3';
            - > 1
    MySQL的> SELECT 2 BETWEEN 2 AND 'x-3';
            - > 0
    

    为了在使用 BETWEEN 日期或时间值 时获得最佳结果 ,请使用 CAST() 显式将值转换为所需的数据类型。 示例:如果将a DATETIME 与两个 DATE 进行比较 ,请将 DATE 转换 DATETIME 值。 如果使用字符串常量(例如与 '2001-1-1' a进行比较) DATE ,则将字符串强制转换为a DATE

  • expr NOT BETWEEN min AND max

    这是一样的 NOT (expr BETWEEN min AND max)

  • COALESCE(value,...)

    返回 NULL 列表 中的第一个非 值,或者 NULL 如果没有非 NULL 值。

    返回类型 COALESCE() 是参数类型的聚合类型。

    MySQL的> SELECT COALESCE(NULL,1);
            - > 1
    MySQL的> SELECT COALESCE(NULL,NULL,NULL);
            - > NULL
    
  • GREATEST(value1,value2,...)

    使用两个或多个参数,返回最大(最大值)参数。 使用与之相同的规则比较参数 LEAST()

    MySQL的> SELECT GREATEST(2,0);
            - > 2
    MySQL的> SELECT GREATEST(34.0,3.0,5.0,767.0);
            - > 767.0
    MySQL的> SELECT GREATEST('B','A','C');
            - >'C'
    

    GREATEST() NULL 如果有任何参数则 返回 NULL

  • expr IN (value,...)

    返回 1 if expr 等于 IN 列表 中的任何值 ,否则返回 0 如果所有值都是常量,则根据类型 expr 和已排序 来评估它们 然后使用二分搜索完成对项目的搜索。 IN 如果 IN 值列表完全由常量组成, 这意味着 非常快 否则,类型转换将根据 第12.2节“表达式评估中的类型转换”中 所述的规则进行 ,但应用于所有参数。

    MySQL的> SELECT 2 IN (0,3,5,7);
            - > 0
    MySQL的> SELECT 'wefwf' IN ('wee','wefwf','weg');
            - > 1
    

    IN 可用于比较行构造函数:

    MySQL的> SELECT (3,4) IN ((1,2), (3,4));
            - > 1
    MySQL的> SELECT (3,4) IN ((1,2), (3,5));
            - > 0
    

    您不应该在 IN 列表中 混合引用和不引用的值, 因为引用值(例如字符串)和不带引号的值(例如数字)的比较规则不同。 因此,混合类型可能导致不一致的结果。 例如,不要写这样的 IN 表达式:

    SELECT val1 FROM tbl1 WHERE val1 IN(1,2,'a');
    

    相反,写这样:

    SELECT val1 FROM tbl1 WHERE val1 IN('1','2','a');
    

    IN 列表中 的值数量 仅受 max_allowed_packet 限制

    为了符合SQL标准, 不仅 IN 返回 NULL 左侧的表达式 NULL ,而且还返回列表中没有匹配项且列表中的一个表达式 NULL

    IN() 语法也可用于编写某些类型的子查询。 请参见 第13.2.11.3节“带有ANY,IN或SOME的子查询”

  • expr NOT IN (value,...)

    这是一样的 NOT (expr IN (value,...))

  • ISNULL(expr)

    如果 expr NULL ,则 ISNULL() 返回 1 ,否则返回 0

    MySQL的> SELECT ISNULL(1+1);
            - > 0
    MySQL的> SELECT ISNULL(1/0);
            - > 1
    

    ISNULL() 可以用来代替 = 测试值是否 NULL (一值比较,以 NULL 使用 = 总是产率 NULL )。

    ISNULL() 函数与 IS NULL 比较运算符 共享一些特殊行为 请参阅说明 IS NULL

  • INTERVAL(N,N1,N2,N3,...)

    返回 0 如果 N < N1 1 如果 N < N2 等等或 -1 如果 N NULL 所有参数都被视为整数。 它要求 N1 < N2 < N3 < ... < Nn 此功能才能正常工作。 这是因为使用二进制搜索(非常快)。

    MySQL的> SELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);
            - > 3
    MySQL的> SELECT INTERVAL(10, 1, 10, 100, 1000);
            - > 2
    MySQL的> SELECT INTERVAL(22, 23, 30, 44, 200);
            - > 0
    
  • LEAST(value1,value2,...)

    使用两个或多个参数,返回最小(最小值)参数。 使用以下规则比较参数:

    • 如果有任何参数 NULL ,结果是 NULL 无需进行比较。

    • 如果所有参数都是整数值,则将它们作为整数进行比较。

    • 如果至少一个参数是双精度,则将它们作为双精度值进行比较。 否则,如果至少有一个参数是 DECIMAL 值,则将它们作为 DECIMAL 进行比较

    • 如果参数包含数字和字符串的混合,则将它们作为字符串进行比较。

    • 如果任何参数是非二进制(字符)字符串,则将参数作为非二进制字符串进行比较。

    • 在所有其他情况下,参数将作为二进制字符串进行比较。

    返回类型 LEAST() 是比较参数类型的聚合类型。

    MySQL的> SELECT LEAST(2,0);
            - > 0
    MySQL的> SELECT LEAST(34.0,3.0,5.0,767.0);
            - > 3.0
    MySQL的> SELECT LEAST('B','A','C');
            - >'A'
    

12.3.3逻辑运算符

表12.4逻辑运算符

名称 描述
AND && 逻辑和
NOT ! 否定价值
OR || 逻辑或
XOR 逻辑异或

在SQL中,所有逻辑运算符来评估 TRUE FALSE NULL UNKNOWN )。 在MySQL中,这些实现为1( TRUE ),0( FALSE )和 NULL 大多数情况对于不同的SQL数据库服务器是常见的,尽管某些服务器可能会返回任何非零值 TRUE

MySQL评估任何非零非 NULL TRUE 例如,以下语句都评估为 TRUE

MySQL的> SELECT 10 IS TRUE;
- > 1
MySQL的> SELECT -10 IS TRUE;
- > 1
MySQL的> SELECT 'string' IS NOT NULL;
- > 1
  • NOT !

    逻辑不。 计算 1 操作数是否为 0 0 如果操作数非零,则 NOT NULL 返回 NULL

    MySQL的> SELECT NOT 10;
            - > 0
    MySQL的> SELECT NOT 0;
            - > 1
    MySQL的> SELECT NOT NULL;
            - > NULL
    MySQL的> SELECT ! (1+1);
            - > 0
    MySQL的> SELECT ! 1+1;
            - > 1
    

    最后一个示例生成, 1 因为表达式的计算方式与 (!1)+1

    ! ,运营商是一个非标准MySQL扩展。 从MySQL 8.0.17开始,不推荐使用此运算符,并且在将来的MySQL版本中将删除对它的支持。 应调整应用程序以使用标准SQL NOT 运算符。

  • AND &&

    逻辑和。 计算 1 所有操作数是否为非零而不是 NULL 0 如果是一个或多个操作数 0 NULL 则返回。

    MySQL的> SELECT 1 AND 1;
            - > 1
    MySQL的> SELECT 1 AND 0;
            - > 0
    MySQL的> SELECT 1 AND NULL;
            - > NULL
    MySQL的> SELECT 0 AND NULL;
            - > 0
    MySQL的> SELECT NULL AND 0;
            - > 0
    

    && ,运营商是一个非标准MySQL扩展。 从MySQL 8.0.17开始,不推荐使用此运算符,并且在将来的MySQL版本中将删除对它的支持。 应调整应用程序以使用标准SQL AND 运算符。

  • OR ||

    逻辑或。 当两个操作数都是非操作数时 NULL ,结果是 1 任何操作数是非零的, 0 否则。 对于 NULL 操作数,结果是 1 如果另一个操作数非零, NULL 否则。 如果两个操作数都是 NULL ,则结果为 NULL

    MySQL的> SELECT 1 OR 1;
            - > 1
    MySQL的> SELECT 1 OR 0;
            - > 1
    MySQL的> SELECT 0 OR 0;
            - > 0
    MySQL的> SELECT 0 OR NULL;
            - > NULL
    MySQL的> SELECT 1 OR NULL;
            - > 1
    
    注意

    如果 PIPES_AS_CONCAT 启用 SQL模式,则 || 表示SQL标准字符串连接运算符(如 CONCAT() )。

    || ,运营商是一个非标准MySQL扩展。 从MySQL 8.0.17开始,不推荐使用此运算符,并且在将来的MySQL版本中将删除对它的支持。 应调整应用程序以使用标准SQL OR 运算符。 例外:如果 PIPES_AS_CONCAT 启用了 弃用,则不适用, 因为在这种情况下, || 表示字符串连接。

  • XOR

    逻辑异或。 NULL 如果任一操作数是,则 返回 NULL 对于非 NULL 操作数,评估 1 奇数个操作数是否为非零,否则 0 返回。

    MySQL的> SELECT 1 XOR 1;
            - > 0
    MySQL的> SELECT 1 XOR 0;
            - > 1
    MySQL的> SELECT 1 XOR NULL;
            - > NULL
    MySQL的> SELECT 1 XOR 1 XOR 1;
            - > 1
    

    a XOR b 在数学上等于 (a AND (NOT b)) OR ((NOT a) and b)

12.3.4赋值运算符

表12.5赋值运算符

名称 描述
= 分配值(作为 SET 语句的 一部分 ,或作为 语句中 SET 子句的 一部分 UPDATE
:= 分配值

  • :=

    分配操作员。 使操作员左侧的用户变量采用其右侧的值。 右侧的值可以是文字值,另一个存储值的变量,或产生标量值的任何合法表达式,包括查询结果(假设此值是标量值)。 您可以在同一 SET 语句中 执行多个分配 您可以在同一语句中执行多个分配。

    与此不同 = := 操作符永远不会被解释为比较运算符。 这意味着您可以 := 在任何有效的SQL语句(不仅仅是 SET 语句中)中使用它来为变量赋值。

    MySQL的> SELECT @var1, @var2;
            - > NULL,NULL
    MySQL的> SELECT @var1 := 1, @var2;
            - > 1,NULL
    MySQL的> SELECT @var1, @var2;
            - > 1,NULL
    MySQL的> SELECT @var1, @var2 := @var1;
            - > 1,1
    MySQL的> SELECT @var1, @var2;
            - > 1,1
    
    MySQL的> SELECT @var1:=COUNT(*) FROM t1;
            - > 4
    MySQL的> SELECT @var1;
            - > 4
    

    您可以使用 := 其他语句 进行值赋值 SELECT ,例如 UPDATE ,如下所示:

    MySQL的> SELECT @var1;
            - > 4
    MySQL的> SELECT * FROM t1;
            - > 1,3,5,7
    
    MySQL的> UPDATE t1 SET c1 = 2 WHERE c1 = @var1:= 1;
    查询正常,1行受影响(0.00秒)
    匹配的行数:1已更改:1警告:0
    
    MySQL的> SELECT @var1;
            - > 1
    MySQL的> SELECT * FROM t1;
            - > 2,3,5,7
    

    虽然也可以使用 := 运算符 在单个SQL语句中设置和读取同一变量的值,但 不建议这样做。 第9.4节“用户定义的变量” 解释了为什么要避免这样做。

  • =

    此运算符用于在两种情况下执行值赋值,如下两段所述。

    SET 语句中, = 被视为赋值运算符,它使运算符左侧的用户变量采用其右侧的值。 (换句话说,当在 SET 语句中 使用时 = 被视为相同 := 。)右侧的值可以是文字值,另一个存储值的变量,或产生标量值的任何合法表达式,包括结果查询(假设此值是标量值)。 您可以在同一 SET 语句中 执行多个分配

    声明 SET 条款中 UPDATE = 也充当赋值运算符; 但是,在这种情况下,只要满足任何 WHERE 条件 ,它就会使运算符左侧的列成为赋予右侧的值 UPDATE 您可以在 语句 的同一 SET 子句中 进行多项赋值 UPDATE

    在任何其他上下文中, = 被视为 比较运算符

    MySQL的> SELECT @var1, @var2;
            - > NULL,NULL
    MySQL的> SELECT @var1 := 1, @var2;
            - > 1,NULL
    MySQL的> SELECT @var1, @var2;
            - > 1,NULL
    MySQL的> SELECT @var1, @var2 := @var1;
            - > 1,1
    MySQL的> SELECT @var1, @var2;
            - > 1,1
    

    有关更多信息,请参见 第13.7.5.1节“变量赋值的SET语法” 第13.2.12节“更新语法” 第13.2.11节“子查询语法”

12.4控制流功能

表12.6流量控制运算符

名称 描述
CASE 案例运营商
IF() 如果/ else构造
IFNULL() Null if / else构造
NULLIF() 如果expr1 = expr2,则返回NULL

  • CASE value WHEN [compare_value] THEN result [WHEN [compare_value] THEN result ...] [ELSE result] END

    CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END

    第一个 CASE 语法返回 result 第一个 为true的比较。 第二种语法返回第一个条件为true的结果。 如果没有比较或条件为真, 则返回 结果 ,或者 如果没有 部分。 value=compare_value ELSE NULL ELSE

    注意

    此处描述 expr 的语法 第13.6.5.1节“CASE语法”中 描述 的SQL 语句 略有不同 ,用于在存储程序中使用。 语句不能有一个 子句,它以for 而不是 CASE CASE CASE ELSE NULL END CASE END

    CASE 表达式结果 的返回类型 是所有结果值的聚合类型:

    • 如果所有类型都是数字,则聚合类型也是数字:

      • 如果至少一个参数是双精度,则结果为双精度。

      • 否则,如果至少有一个参数 DECIMAL ,则结果为 DECIMAL

      • 否则,结果是整数类型(有一个例外):

        • 如果所有的整数类型都是有符号或无符号的所有的结果都是一样的符号和精度最高的所有指定整数类型的(也就是 TINYINT SMALLINT MEDIUMINT INT ,或 BIGINT )。

        • 如果存在有符号和无符号整数类型的组合,则结果将被签名并且精度可能更高。 例如,如果类型是有符号 INT 和无符号的 INT ,则结果将被签名 BIGINT

        • 例外是无符号 BIGINT 与任何有符号整数类型的组合。 结果是 DECIMAL 具有足够的精度和规模0。

    • 如果所有类型都是 BIT ,结果是 BIT 否则, BIT 参数被视为类似于 BIGINT

    • 如果所有类型都是 YEAR ,结果是 YEAR 否则, YEAR 参数被视为类似于 INT

    • 如果所有类型都是字符串( CHAR VARCHAR ),则结果的 VARCHAR 最大长度由操作数的最长字符长度确定。

    • 如果所有类型都是字符或二进制字符串,则结果为 VARBINARY

    • SET 并被 ENUM 视为类似于 VARCHAR ; 结果是 VARCHAR

    • 如果所有类型都是 JSON ,结果是 JSON

    • 如果所有类型都是时间的,则结果是暂时的:

    • 如果所有类型都是 GEOMETRY ,结果是 GEOMETRY

    • 如果是任何类型 BLOB ,结果是 BLOB

    • 对于所有其他类型组合,结果是 VARCHAR

    • NULL 类型聚合会忽略 文字 操作数。

    mysql> SELECT CASE 1 WHEN 1 THEN 'one'
        - >     WHEN 2 THEN 'two' ELSE 'more' END;
            - >'一个'
    MySQL的> SELECT CASE WHEN 1>0 THEN 'true' ELSE 'false' END;
            - >'true'
    mysql> SELECT CASE BINARY 'B'
        - >     WHEN 'a' THEN 1 WHEN 'b' THEN 2 END;
            - > NULL
    
  • IF(expr1,expr2,expr3)

    如果 expr1 TRUE expr1 <> 0 expr1 <> NULL ),则 IF() 返回 expr2 否则,它返回 expr3

    注意

    还有一个 声明 ,与 此处描述 功能 不同 请参见 第13.6.5.2节“IF语法” IF IF()

    如果只有一个 expr2 expr3 明确 NULL ,则 IF() 函数 的结果类型 是非 NULL 表达式 的类型

    默认返回类型 IF() (在存储到临时表时可能很重要)计算如下:

    • 如果 expr2 expr3 生成一个字符串,结果是一个字符串。

      如果 expr2 expr3 都是字符串,则如果任一字符串区分大小写,则结果区分大小写。

    • 如果 expr2 expr3 生成浮点值,则结果为浮点值。

    • 如果 expr2 expr3 生成整数,则结果为整数。

    MySQL的> SELECT IF(1>2,2,3);
            - > 3
    MySQL的> SELECT IF(1<2,'yes','no');
            - >'是'
    MySQL的> SELECT IF(STRCMP('test','test1'),'no','yes');
            - >'不'
    
  • IFNULL(expr1,expr2)

    如果 expr1 不是 NULL ,则 IFNULL() 返回 expr1 ; 否则它会返回 expr2

    MySQL的> SELECT IFNULL(1,0);
            - > 1
    MySQL的> SELECT IFNULL(NULL,10);
            - > 10
    MySQL的> SELECT IFNULL(1/0,10);
            - > 10
    MySQL的> SELECT IFNULL(1/0,'yes');
            - >'是'
    

    的默认返回值类型 是更为 一般 两个表达式的,顺序 考虑基于表达式的表的情况,或者MySQL必须在内部存储 临时表中 返回的值的情况 IFNULL(expr1,expr2) STRING REAL INTEGER IFNULL()

    
    mysql> CREATE TABLE tmp SELECT IFNULL(1,'test') AS test;
    mysql>DESCRIBE tmp;
    + ------- + -------------- + ------ + ------ + --------- + --- ---- +
    | 领域| 输入| 空| 钥匙| 默认| 额外的|
    + ------- + -------------- + ------ + ------ + --------- + --- ---- +
    | 测试| varbinary(4)| 没有| | | |
    + ------- + -------------- + ------ + ------ + --------- + --- ---- +
    

    在此示例中, test 的类型 VARBINARY(4) (字符串类型)。

  • NULLIF(expr1,expr2)

    返回 NULL if 为true,否则返回 这是一样的 expr1 = expr2 expr1 CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END

    返回值与第一个参数的类型相同。

    MySQL的> SELECT NULLIF(1,1);
            - > NULL
    MySQL的> SELECT NULLIF(1,2);
            - > 1
    
    注意

    expr1 如果参数不相等, MySQL将评估 两次。

12.5字符串函数

表12.7字符串运算符

名称 描述
ASCII() 返回最左侧字符的数值
BIN() 返回包含数字的二进制表示的字符串
BIT_LENGTH() 以位为单位返回参数长度
CHAR() 返回传递的每个整数的字符
CHAR_LENGTH() 返回参数中的字符数
CHARACTER_LENGTH() CHAR_LENGTH()的同义词
CONCAT() 返回连接字符串
CONCAT_WS() 返回与分隔符连接
ELT() 返回索引号处的字符串
EXPORT_SET() 返回一个字符串,使得对于值位中设置的每个位,您获得一个on字符串,并且对于每个未设置的位,您将获得一个关闭字符串
FIELD() 后续参数中第一个参数的索引(位置)
FIND_IN_SET() 第二个参数中第一个参数的索引(位置)
FORMAT() 返回格式化为指定小数位数的数字
FROM_BASE64() 解码base64编码的字符串并返回结果
HEX() 十进制或字符串值的十六进制表示
INSERT() 在指定位置插入子字符串,直到指定的字符数
INSTR() 返回第一次出现的子串的索引
LCASE() LOWER()的同义词
LEFT() 返回指定的最左边的字符数
LENGTH() 以字节为单位返回字符串的长度
LIKE 简单的模式匹配
LOAD_FILE() 加载指定的文件
LOCATE() 返回第一次出现的子串的位置
LOWER() 以小写形式返回参数
LPAD() 返回字符串参数,使用指定的字符串进行左填充
LTRIM() 删除前导空格
MAKE_SET() 返回一组以逗号分隔的字符串,这些字符串具有相应的位设置位
MATCH 执行全文搜索
MID() 返回从指定位置开始的子字符串
NOT LIKE 简单模式匹配的否定
NOT REGEXP REGEXP的否定
OCT() 返回包含数字的八进制表示的字符串
OCTET_LENGTH() LENGTH()的同义词
ORD() 返回参数最左侧字符的字符代码
POSITION() LOCATE()的同义词
QUOTE() 转义参数以在SQL语句中使用
REGEXP string是否匹配正则表达式
REGEXP_INSTR() 匹配正则表达式的子串的起始索引
REGEXP_LIKE() string是否匹配正则表达式
REGEXP_REPLACE() 替换匹配正则表达式的子字符串
REGEXP_SUBSTR() 返回子串匹配正则表达式
REPEAT() 重复指定次数的字符串
REPLACE() 替换指定字符串的出现次数
REVERSE() 反转字符串中的字符
RIGHT() 返回指定的最右边的字符数
RLIKE string是否匹配正则表达式
RPAD() 追加指定次数的字符串
RTRIM() 删除尾随空格
SOUNDEX() 返回soundex字符串
SOUNDS LIKE 比较声音
SPACE() 返回指定数量的空格的字符串
STRCMP() 比较两个字符串
SUBSTR() 返回指定的子字符串
SUBSTRING() 返回指定的子字符串
SUBSTRING_INDEX() 在指定的分隔符出现次数之前从字符串返回子字符串
TO_BASE64() 返回转换为base-64字符串的参数
TRIM() 删除前导和尾随空格
UCASE() UPPER()的同义词
UNHEX() 返回包含数字的十六进制表示的字符串
UPPER() 转换为大写
WEIGHT_STRING() 返回字符串的权重字符串

NULL 如果结果的长度大于 max_allowed_packet 系统变量 的值,则 返回字符串值函数 请参见 第5.1.1节“配置服务器”

对于在字符串位置上操作的函数,第一个位置编号为1。

对于采用长度参数的函数,非整数参数将四舍五入为最接近的整数。

  • ASCII(str)

    返回字符串最左侧字符的数值 str 返回 0 if str 是否为空字符串。 NULL 如果 str 是,则 返回 NULL ASCII() 适用于8位字符。

    MySQL的> SELECT ASCII('2');
            - > 50
    MySQL的> SELECT ASCII(2);
            - > 50
    MySQL的> SELECT ASCII('dx');
            - > 100
    

    另请参见该 ORD() 功能。

  • BIN(N)

    返回二进制值的字符串表示形式 N ,其中 N longlong( BIGINT )数字。 这相当于 如果 是,则 返回 CONV(N,10,2) NULL N NULL

    MySQL的> SELECT BIN(12);
            - >'1100'
    
  • BIT_LENGTH(str)

    str 以位 为单位返回字符串的长度

    MySQL的> SELECT BIT_LENGTH('text');
            - > 32
    
  • CHAR(N,... [USING charset_name])

    CHAR() 将每个参数解释 N 为一个整数,并返回一个字符串,该字符串由这些整数的代码值给出的字符组成。 NULL 值被跳过。

    MySQL的> SELECT CHAR(77,121,83,81,'76');
            - >'MySQL'
    MySQL的> SELECT CHAR(77,77.3,'77.3');
            - >'MMM'
    

    CHAR() 大于255的参数将转换为多个结果字节。 例如, CHAR(256) 等同于 CHAR(1,0) CHAR(256*256) 等同于 CHAR(1,0,0)

    MySQL的> SELECT HEX(CHAR(1,0)), HEX(CHAR(256));
    + ---------------- + ---------------- +
    | 十六进制(CHAR(1,0))| HEX(CHAR(256))|
    + ---------------- + ---------------- +
    | 0100 | 0100 |
    + ---------------- + ---------------- +
    MySQL的> SELECT HEX(CHAR(1,0,0)), HEX(CHAR(256*256));
    + ------------------ + -------------------- +
    | 十六进制(CHAR(1,0,0))| HEX(CHAR(256 * 256))|
    + ------------------ + -------------------- +
    | 010000 | 010000 |
    + ------------------ + -------------------- +
    

    默认情况下, CHAR() 返回二进制字符串。 要在给定字符集中生成字符串,请使用optional USING 子句:

    MySQL的> SELECT CHARSET(CHAR(X'65')), CHARSET(CHAR(X'65' USING utf8));
    + ---------------------- + -------------------------- ------- +
    | CHARSET(CHAR(X'65'))| CHARSET(CHAR(X'65'使用utf8))|
    + ---------------------- + -------------------------- ------- +
    | 二进制| utf8 |
    + ---------------------- + -------------------------- ------- +
    

    如果 USING 给定并且结果字符串对于给定字符集是非法的,则发出警告。 此外,如果启用了严格的SQL模式,则结果 CHAR() 将变为 NULL

  • CHAR_LENGTH(str)

    返回字符串的长度 str ,以字符为单位。 多字节字符计为单个字符。 这意味着对于包含五个2字节字符的字符串, LENGTH() 返回 10 ,而 CHAR_LENGTH() 返回 5

  • CHARACTER_LENGTH(str)

    CHARACTER_LENGTH() 是...的同义词 CHAR_LENGTH()

  • CONCAT(str1,str2,...)

    返回连接参数产生的字符串。 可能有一个或多个参数。 如果所有参数都是非二进制字符串,则结果为非二进制字符串。 如果参数包含任何二进制字符串,则结果为二进制字符串。 数字参数将转换为其等效的非二进制字符串形式。

    CONCAT() NULL 如果有任何参数则 返回 NULL

    MySQL的> SELECT CONCAT('My', 'S', 'QL');
            - >'MySQL'
    MySQL的> SELECT CONCAT('My', NULL, 'QL');
            - > NULL
    MySQL的> SELECT CONCAT(14.3);
            - > '14 .3'
    

    对于带引号的字符串,可以通过将字符串放在彼此旁边来执行连接:

    MySQL的> SELECT 'My' 'S' 'QL';
            - >'MySQL'
    
  • CONCAT_WS(separator,str1,str2,...)

    CONCAT_WS() 代表Concatenate With Separator,是一种特殊的形式 CONCAT() 第一个参数是其余参数的分隔符。 在要连接的字符串之间添加分隔符。 分隔符可以是字符串,其余参数也可以。 如果是分隔符 NULL ,结果是 NULL

    MySQL的> SELECT CONCAT_WS(',','First name','Second name','Last Name');
            - >'名字,第二个名字,姓氏'
    MySQL的> SELECT CONCAT_WS(',','First name',NULL,'Last Name');
            - >'名字,姓氏'
    

    CONCAT_WS() 不会跳过空字符串。 但是,它会 NULL 在分隔符参数后 跳过任何 值。

  • ELT(N,str1,str2,str3,...)

    ELT() 返回 N 字符串列表 第th个元素: str1 if N = 1 str2 if N = 2 ,依此类推。 返回 NULL if N 小于 1 或大于参数的数量。 ELT() 是补充 FIELD()

    MySQL的> SELECT ELT(1, 'Aa', 'Bb', 'Cc', 'Dd');
            - >'Aa'
    MySQL的> SELECT ELT(4, 'Aa', 'Bb', 'Cc', 'Dd');
            - >'Dd'
    
  • EXPORT_SET(bits,on,off[,separator[,number_of_bits]])

    返回一个字符串,使得对于值中设置的每个位 bits ,您将获得一个 on 字符串,并且对于未在该值中设置的每个位,您将获得一个 off 字符串。 比特 bits 被从右到左(从低以高序位)检查。 字符串从左到右添加到结果中,由 separator 字符串 分隔 (默认为逗号字符 , )。 检查的位数由 number_of_bits 下式 给出 ,如果未指定,则默认值为64。 number_of_bits 如果大于64,则静默地剪切为64.它被视为无符号整数,因此值-1实际上与64相同。

    MySQL的> SELECT EXPORT_SET(5,'Y','N',',',4);
            - >'Y,N,Y,N'
    MySQL的> SELECT EXPORT_SET(6,'1','0',',',10);
            - >'0,1,1,0,0,0,0,0,0,0'
    
  • FIELD(str,str1,str2,str3,...)

    返回的索引(位置) str str1 str2 str3 ... 列表。 0 如果 str 找不到则 返回

    如果所有参数 FIELD() 都是字符串, 则将所有参数 作为字符串进行比较。 如果所有参数都是数字,则将它们作为数字进行比较。 否则,参数将被比较为double。

    如果 str NULL ,返回值是 0 因为 NULL 与任何值的失败相等性比较。 FIELD() 是补充 ELT()

    MySQL的> SELECT FIELD('Bb', 'Aa', 'Bb', 'Cc', 'Dd', 'Ff');
            - > 2
    MySQL的> SELECT FIELD('Gg', 'Aa', 'Bb', 'Cc', 'Dd', 'Ff');
            - > 0
    
  • FIND_IN_SET(str,strlist)

    N 如果字符串 str 位于 strlist N 字符串 组成 的字符串列表中 返回1到1范围内的值 字符串列表是由 , 字符 分隔的子字符串组成的字符串 如果第一个参数是常量字符串而第二个参数是类型列, 则优化 SET FIND_IN_SET() 函数以使用位算术。 返回 0 if str 不在 strlist 或if strlist 是空字符串。 NULL 如果任一参数是,则 返回 NULL 如果第一个参数包含逗号,则此函数无法正常工作( , )性格。

    MySQL的> SELECT FIND_IN_SET('b','a,b,c,d');
            - > 2
    
  • FORMAT(X,D[,locale])

    将数字格式化 X 为格式 '#,###,###.##' ,舍入到 D 小数位,并将结果作为字符串返回。 如果 D 是的话 0 ,则结果没有小数点或小数部分。

    可选的第三个参数允许指定区域设置用于结果编号的小数点,千位分隔符和分隔符之间的分组。 允许的区域设置值与 lc_time_names 系统变量 的合法值相同 (请参见 第10.15节“MySQL服务器区域设置支持” )。 如果未指定区域设置,则默认为 'en_US'

    MySQL的> SELECT FORMAT(12332.123456, 4);
            - > '12,332.1235'
    MySQL的> SELECT FORMAT(12332.1,4);
            - > '12,332.1000'
    MySQL的> SELECT FORMAT(12332.2,0);
            - > '12,332'
    MySQL的> SELECT FORMAT(12332.2,2,'de_DE');
            - > '12 .332,20'
    
  • FROM_BASE64(str)

    采用使用的base-64编码规则编码的字符串 TO_BASE64() ,并将解码结果作为二进制字符串返回。 结果是 NULL 参数是否是 NULL 有效的base-64字符串。 有关 TO_BASE64() 编码和解码规则的详细信息, 请参阅说明

    MySQL的> SELECT TO_BASE64('abc'), FROM_BASE64(TO_BASE64('abc'));
            - >'JWJj','abc'
    
  • HEX(str) HEX(N)

    对于字符串参数 str HEX() 返回十六进制字符串表示形式, str 其中每个字符的每个字节 str 都转换为两个十六进制数字。 (多字节字符因此变为两位以上。)此操作的反转由。执行 UNHEX() 功能

    对于数字参数 N HEX() 返回 N 被视为longlong( BIGINT )数字 的值的十六进制字符串表示形式 这相当于 该操作的反转由执行 CONV(N,10,16) CONV(HEX(N),16,10)

    MySQL的> SELECT X'616263', HEX('abc'), UNHEX(HEX('abc'));
            - >'abc',616263,'abc'
    MySQL的> SELECT HEX(255), CONV(HEX(255),16,10);
            - >'FF',255
    
  • INSERT(str,pos,len,newstr)

    返回字符串 str ,在位置开始子 pos len 长期被字符串替换的字符 newstr 如果 pos 不在 字符串 的长度内, 则返回原始 字符串。 pos 如果 len 不在字符串其余部分的长度内, 则从位置替换字符串 的其余部分。 NULL 如果有任何参数,则 返回 NULL

    MySQL的> SELECT INSERT('Quadratic', 3, 4, 'What');
            - >'QuWhattic'
    MySQL的> SELECT INSERT('Quadratic', -1, 4, 'What');
            - >'Quadratic'
    MySQL的> SELECT INSERT('Quadratic', 3, 100, 'What');
            - >'QuWhat'
    

    此功能是多字节安全的。

  • INSTR(str,substr)

    返回 substr string中 第一次出现的子 字符串的位置 str LOCATE() 除了参数的顺序相反之外,这 与双参数形式 相同。

    MySQL的> SELECT INSTR('foobarbar', 'bar');
            - > 4
    MySQL的> SELECT INSTR('xbar', 'foobar');
            - > 0
    

    此函数是多字节安全的,并且仅当至少一个参数是二进制字符串时才区分大小写。

  • LCASE(str)

    LCASE() 是...的同义词 LOWER()

    LCASE() LOWER() 存储视图的定义时,视图中 使用的内容将被重写 (缺陷号码#12844279)

  • LEFT(str,len)

    返回 len 字符串中 最左边的 字符 str ,或者 NULL 如果有任何参数 NULL

    MySQL的> SELECT LEFT('foobarbar', 5);
            - >'fooba'
    

    此功能是多字节安全的。

  • LENGTH(str)

    返回字符串的长度 str ,以字节为单位。 多字节字符计为多个字节。 这意味着对于包含五个2字节字符的字符串, LENGTH() 返回 10 ,而 CHAR_LENGTH() 返回 5

    MySQL的> SELECT LENGTH('text');
            - > 4
    
    注意

    Length() 开放GIS空间功能被命名为 ST_Length() MySQL中。

  • LOAD_FILE(file_name)

    读取文件并以字符串形式返回文件内容。 要使用此功能,文件必须位于服务器主机上,您必须指定文件的完整路径名,并且您必须具有该 FILE 权限。 该文件必须是服务器可读的,其大小小于 max_allowed_packet 字节。 如果 secure_file_priv 系统变量设置为非空目录名,则要加载的文件必须位于该目录中。 (在MySQL 8.0.17之前,文件必须是所有人都可读的,而不仅仅是服务器可读的。)

    如果由于不满足上述条件之一而导致文件不存在或无法读取,则返回该函数 NULL

    character_set_filesystem 系统变量控制给定为文字字符串文件名的解释。

    MySQL的> UPDATE t
                SET blob_col=LOAD_FILE('/tmp/picture')
                WHERE id=1;
    
  • LOCATE(substr,str) LOCATE(substr,str,pos)

    第一个语法返回 substr string中 第一次出现的substring的位置 str 第二种语法返回 substr string中 第一次出现的substring的 str 位置,从position开始 pos 0 如果 substr 不在,则 返回 str NULL 如果有任何参数,则 返回 NULL

    MySQL的> SELECT LOCATE('bar', 'foobarbar');
            - > 4
    MySQL的> SELECT LOCATE('xbar', 'foobar');
            - > 0
    MySQL的> SELECT LOCATE('bar', 'foobarbar', 5);
            - > 7
    

    此函数是多字节安全的,并且仅当至少一个参数是二进制字符串时才区分大小写。

  • LOWER(str)

    返回 str 根据当前字符集映射将所有字符更改为小写 的字符串 默认是 utf8mb4

    MySQL的> SELECT LOWER('QUADRATICALLY');
            - >'quadratically'
    

    LOWER() (并且 UPPER() 当施加到二进制字符串()是无效的 BINARY VARBINARY BLOB )。 要执行lettercase转换,请将字符串转换为非二进制字符串:

    mysql> SET @str = BINARY 'New York';
    mysql>SELECT LOWER(@str), LOWER(CONVERT(@str USING utf8mb4));
    + ------------- + ----------------------------------- -  +
    | LOWER(@str)| LOWER(CONVERT(@str使用utf8mb4))|
    + ------------- + ----------------------------------- -  +
    | 纽约| 纽约|
    + ------------- + ----------------------------------- -  +
    

    对于Unicode字符集 的排序规则 LOWER() UPPER() 根据排序规则名称中的Unicode排序规则算法(UCA)版本(如果有)和UCA 4.0.0(如果未指定版本)工作。 例如, utf8mb4_0900_ai_ci 并且 utf8_unicode_520_ci 根据分别UCA 9.0.0和5.2.0,工作,而 utf8_unicode_ci 作品根据UCA 4.0.0。 请参见 第10.10.1节“Unicode字符集”

    此功能是多字节安全的。

    LCASE() 视图中使用的内容将被重写为 LOWER()

  • LPAD(str,len,padstr)

    返回字符串 str ,用 字符串 左边填充 padstr len 字符 长度 如果 str 长于 len ,则返回值缩短为 len 字符。

    MySQL的> SELECT LPAD('hi',4,'??');
            - >'?? hi'
    MySQL的> SELECT LPAD('hi',1,'??');
            - >'h'
    
  • LTRIM(str)

    返回 str 删除了前导空格字符 的字符串

    MySQL的> SELECT LTRIM('  barbar');
            - >'barbar'
    

    此功能是多字节安全的。

  • MAKE_SET(bits,str1,str2,...)

    返回一个设置值(包含由 , 字符 分隔的子字符串的字符串 ),包含具有 bits set中 相应位的字符串 str1 对应于位0, str2 位1,依此类推。 NULL 在价值观 str1 str2 ... 不附加到该结果。

    MySQL的> SELECT MAKE_SET(1,'a','b','c');
            - >'a'
    MySQL的> SELECT MAKE_SET(1 | 4,'hello','nice','world');
            - >'你好,世界'
    MySQL的> SELECT MAKE_SET(1 | 4,'hello','nice',NULL,'world');
            - >'你好'
    MySQL的> SELECT MAKE_SET(0,'a','b','c');
            - >''
    
  • MID(str,pos,len)

    MID(str,pos,len) 是...的同义词 SUBSTRING(str,pos,len)

  • OCT(N)

    返回八进制值的字符串表示形式 N ,其中 N longlong( BIGINT )数字。 这相当于 如果 是,则 返回 CONV(N,10,8) NULL N NULL

    MySQL的> SELECT OCT(12);
            - >'14'
    
  • OCTET_LENGTH(str)

    OCTET_LENGTH() 是...的同义词 LENGTH()

  • ORD(str)

    如果字符串的最左边的字符 str 是多字节字符,则返回该字符的代码,使用以下公式从其组成字节的数值计算:

      (第1字节代码)
    +(第2字节代码* 256)
    +(第3字节代码* 256 ^ 2)...
    

    如果最左边的字符不是多字节字符,则 ORD() 返回与...相同的值 ASCII() 函数

    MySQL的> SELECT ORD('2');
            - > 50
    
  • POSITION(substr IN str)

    POSITION(substr IN str) 是...的同义词 LOCATE(substr,str)

  • QUOTE(str)

    引用字符串以生成可在SQL语句中用作正确转义的数据值的结果。 返回的字符串用单引号括起来,每个反斜杠( \ ),单引号( ' ),ASCII NUL 和Control + Z 实例都以反斜杠 开头。 如果参数是 NULL ,则返回值是单词 NULL 而不包含单引号。

    MySQL的> SELECT QUOTE('Don\'t!');
            - >'不要!'
    MySQL的> SELECT QUOTE(NULL);
            - > NULL
    

    为了比较,请参见 第9.1.1节“字符串文字” 第28.7.7.56节“mysql_real_escape_string_quote()”中 文字字符串的引用规则和C API中的引用规则

  • REPEAT(str,count)

    返回由字符串 str 重复 count 次数 组成的字符串 如果 count 小于1,则返回空字符串。 NULL 如果 str 或是, count 返回 NULL

    MySQL的> SELECT REPEAT('MySQL', 3);
            - >'MySQLMySQLMySQL'
    
  • REPLACE(str,from_str,to_str)

    返回 str 字符串 from_str 替换 为字符串 的所有 字符串 to_str REPLACE() 搜索时执行区分大小写的匹配 from_str

    MySQL的> SELECT REPLACE('www.mysql.com', 'w', 'Ww');
            - >'WwWwWw.mysql.com'
    

    此功能是多字节安全的。

  • REVERSE(str)

    返回字符串 str 顺序颠倒 的字符串

    MySQL的> SELECT REVERSE('abc');
            - >'cba'
    

    此功能是多字节安全的。

  • RIGHT(str,len)

    返回 len 字符串中 最右边的 字符 str ,或者 NULL 是否有任何参数 NULL

    MySQL的> SELECT RIGHT('foobarbar', 4);
            - >'rbar'
    

    此功能是多字节安全的。

  • RPAD(str,len,padstr)

    返回字符串 str ,右边用字符串填充 padstr 为一个 len 字符 长度 如果 str 长于 len ,则返回值缩短为 len 字符。

    MySQL的> SELECT RPAD('hi',5,'?');
            - >'你好???
    MySQL的> SELECT RPAD('hi',1,'?');
            - >'h'
    

    此功能是多字节安全的。

  • RTRIM(str)

    返回 str 删除了尾随空格字符 的字符串

    MySQL的> SELECT RTRIM('barbar   ');
            - >'barbar'
    

    此功能是多字节安全的。

  • SOUNDEX(str)

    从中返回soundex字符串 str 听起来几乎相同的两个弦应具有相同的soundex弦。 标准soundex字符串长度为四个字符,但该 SOUNDEX() 函数返回一个任意长的字符串。 您可以 SUBSTRING() 在结果上 使用 以获得标准的soundex字符串。 str 忽略 所有非字母字符 AZ范围之外的所有国际字母字符都被视为元音。

    重要

    使用时 SOUNDEX() ,您应该了解以下限制:

    • 目前实现的此功能旨在与仅使用英语的字符串一起使用。 其他语言的字符串可能无法产生可靠的结果。

    • 无法保证此函数能够为使用多字节字符集的字符串提供一致的结果,包括 utf-8 有关更多信息,请参阅Bug#22638。

    MySQL的> SELECT SOUNDEX('Hello');
            - >'H400'
    MySQL的> SELECT SOUNDEX('Quadratically');
            - >'Q36324'
    
    注意

    此函数实现了原始的Soundex算法,而不是更流行的增强版本(也由D. Knuth描述)。 区别在于原始版本首先丢弃元音并重复第二个元素,而增强版本首先丢弃重复元素,然后丢弃元音元素。

  • expr1 SOUNDS LIKE expr2

    这是一样的 SOUNDEX(expr1) = SOUNDEX(expr2)

  • SPACE(N)

    返回由 N 空格字符 组成的字符串

    MySQL的> SELECT SPACE(6);
            - >''
    
  • SUBSTR(str,pos) SUBSTR(str FROM pos) SUBSTR(str,pos,len) SUBSTR(str FROM pos FOR len)

    SUBSTR() 是...的同义词 SUBSTRING()

  • SUBSTRING(str,pos) SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) SUBSTRING(str FROM pos FOR len)

    没有 len 参数 的表单 str 位置开始 返回字符串的子字符串 pos 带有 len 参数 的表单 len 从字符串 返回一个子字符串 字符 str ,从位置开始 pos 使用的表单 FROM 是标准SQL语法。 也可以使用负值 pos 在这种情况下,子字符串的开头是字符串 pos 末尾的字符,而不是字符串的开头。 负值可以用于 pos 该函数的任何形式。

    对于所有形式 SUBSTRING() ,将从中提取子字符串的字符串中第一个字符的位置计算为 1

    MySQL的> SELECT SUBSTRING('Quadratically',5);
            - >'ratically'
    MySQL的> SELECT SUBSTRING('foobarbar' FROM 4);
            - >'barbar'
    MySQL的> SELECT SUBSTRING('Quadratically',5,6);
            - >'ratica'
    MySQL的> SELECT SUBSTRING('Sakila', -3);
            - >'ila'
    MySQL的> SELECT SUBSTRING('Sakila', -5, 3);
            - >'aki'
    MySQL的> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
            - >'ki'
    

    此功能是多字节安全的。

    如果 len 小于1,则结果为空字符串。

  • SUBSTRING_INDEX(str,delim,count)

    str count 出现分隔符 之前 从字符串返回子字符串 delim 如果 count 为正,则返回最终分隔符左侧的所有内容(从左侧开始计算)。 如果 count 是否定的,则返回最终分隔符右侧的所有内容(从右侧开始计算)。 SUBSTRING_INDEX() 搜索时执行区分大小写的匹配 delim

    MySQL的> SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);
            - >'www.mysql'
    MySQL的> SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2);
            - >'mysql.com'
    

    此功能是多字节安全的。

  • TO_BASE64(str)

    将字符串参数转换为base-64编码形式,并将结果作为带有连接字符集和排序规则的字符串返回。 如果参数不是字符串,则在转换发生之前将其转换为字符串。 结果是 NULL 如果参数是 NULL 可以使用该 FROM_BASE64() 函数对 Base-64编码的字符串进行解码

    MySQL的> SELECT TO_BASE64('abc'), FROM_BASE64(TO_BASE64('abc'));
            - >'JWJj','abc'
    

    存在不同的base-64编码方案。 这些是由所使用的编码和解码规则 TO_BASE64() FROM_BASE64()

    • 字母值62的编码是 '+'

    • 字母值63的编码是 '/'

    • 编码输出由4个可打印字符组成。 输入数据的每3个字节使用4个字符进行编码。 如果最后一个组不完整,则用 '=' 字符 填充 长度为4。

    • 在编码输出的每76个字符之后添加换行符以将长输出分成多行。

    • 解码识别并忽略换行符,回车符,制表符和空格。

  • TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM([remstr FROM] str)

    返回 删除 str 了所有 remstr 前缀或后缀 的字符串 如果没有给出说明符 BOTH LEADING 或者 TRAILING 给出 BOTH remstr 是可选的,如果未指定,则删除空格。

    MySQL的> SELECT TRIM('  bar   ');
            - >'酒吧'
    MySQL的> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
            - >'barxxx'
    MySQL的> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
            - >'酒吧'
    MySQL的> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
            - >'barx'
    

    此功能是多字节安全的。

  • UCASE(str)

    UCASE() 是...的同义词 UPPER()

    UCASE() 视图中使用的内容将被重写为 UPPER()

  • UNHEX(str)

    对于字符串参数 str 参数中的 每对字符解释为十六进制数,并将其转换为数字表示的字节。 返回值是二进制字符串。 UNHEX(str)

    MySQL的> SELECT UNHEX('4D7953514C');
            - >'MySQL'
    MySQL的> SELECT X'4D7953514C';
            - >'MySQL'
    MySQL的> SELECT UNHEX(HEX('string'));
            - >'string'
    MySQL的> SELECT HEX(UNHEX('1267'));
            - >'1267'
    

    在参数字符串中的字符必须是合法的十六进制数字: '0' ... '9' 'A' ... 'F' 'a' ... 'f' 如果参数包含任何非十六进制数字,则结果为 NULL

    MySQL的> SELECT UNHEX('GG');
    + ------------- +
    | UNHEX('GG')|
    + ------------- +
    | NULL |
    + ------------- +
    

    NULL 可发生的结果,如果该参数 UNHEX() 是一 BINARY ,列,因为值是用0x00填充字节存储时,但这些字节不剥离上检索。 例如, '41' 存储到 CHAR(3) 列中 '41 ' 并作为 '41' (带有尾随垫空间被剥离) 检索 ,因此 UNHEX() 对于列值返回 'A' 相比之下 '41' ,存储在一 BINARY(3) 列中 '41\0' 并检索为 '41\0' (尾部填充 0x00 字节未被剥离)。 '\0' 这不是一个合法的十六进制数字 UNHEX() 列值返回 NULL

    对于数字参数 N 不执行 倒数 改用。 请参阅说明 HEX(N) UNHEX() CONV(HEX(N),16,10) HEX()

  • UPPER(str)

    返回 str 根据当前字符集映射将所有字符更改为大写 的字符串 默认是 utf8mb4

    MySQL的> SELECT UPPER('Hej');
            - >'HEJ'
    

    有关 LOWER() 同样适用的信息, 请参阅说明 UPPER() 这包括有关如何执行二进制串的大小写转换信息( BINARY VARBINARY BLOB ),用于这些功能是无效的,以及约壳体折叠的Unicode字符集的信息。

    此功能是多字节安全的。

    UCASE() 视图中使用的内容将被重写为 UPPER()

  • WEIGHT_STRING(str [AS {CHAR|BINARY}(N)] [flags])

    此函数返回输入字符串的权重字符串。 返回值是二进制字符串,表示字符串的比较和排序值。 它具有以下属性:

    WEIGHT_STRING() 是一个供内部使用的调试功能。 它的行为可以在MySQL版本之间发生变化, 它可用于测试和调试排序规则,尤其是在添加新排序规则时。 请参见 第10.13节“将字符集添加到字符集”

    该列表简要总结了这些论点。 列表后面的讨论中给出了更多细节。

    • str :输入字符串表达式。

    • AS 子句:可选; 将输入字符串转换为给定的类型和长度。

    • flags : 可选的; 没用过。

    输入字符串 str 是字符串表达式。 如果输入是一个非二进制(字符)串,诸如 CHAR VARCHAR TEXT 值,则返回值将包含该字符串核对权重。 如果输入是二进制(字节)字符串,如a BINARY VARBINARY BLOB value,则返回值与输入相同(二进制字符串中每个字节的权重是字节值)。 如果输入是 NULL ,则 WEIGHT_STRING() 返回 NULL

    例子:

    mysql> SET @s = _utf8mb4 'AB' COLLATE utf8mb4_0900_ai_ci;
    mysql>SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));
    + ------ + --------- + ------------------------ +
    | @s | 十六进制(@s)| HEX(WEIGHT_STRING(@s))|
    + ------ + --------- + ------------------------ +
    | AB | 4142 | 1C471C60 |
    + ------ + --------- + ------------------------ +
    
    mysql> SET @s = _utf8mb4 'ab' COLLATE utf8mb4_0900_ai_ci;
    mysql>SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));
    + ------ + --------- + ------------------------ +
    | @s | 十六进制(@s)| HEX(WEIGHT_STRING(@s))|
    + ------ + --------- + ------------------------ +
    | ab | 6162 | 1C471C60 |
    + ------ + --------- + ------------------------ +
    
    mysql> SET @s = CAST('AB' AS BINARY);
    mysql>SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));
    + ------ + --------- + ------------------------ +
    | @s | 十六进制(@s)| HEX(WEIGHT_STRING(@s))|
    + ------ + --------- + ------------------------ +
    | AB | 4142 | 4142 |
    + ------ + --------- + ------------------------ +
    
    mysql> SET @s = CAST('ab' AS BINARY);
    mysql>SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));
    + ------ + --------- + ------------------------ +
    | @s | 十六进制(@s)| HEX(WEIGHT_STRING(@s))|
    + ------ + --------- + ------------------------ +
    | ab | 6162 | 6162 |
    + ------ + --------- + ------------------------ +
    

    前面的示例用于 HEX() 显示 WEIGHT_STRING() 结果。 因为结果是二进制值, HEX() 当结果包含非打印值时,特别有用,以可打印的形式显示它:

    mysql> SET @s = CONVERT(X'C39F' USING utf8) COLLATE utf8_czech_ci;
    mysql>SELECT HEX(WEIGHT_STRING(@s));
    + ------------------------ +
    | HEX(WEIGHT_STRING(@s))|
    + ------------------------ +
    | 0FEA0FEA |
    + ------------------------ +
    

    对于非 NULL 返回值,值的数据类型是 VARBINARY 其长度是否在最大长度内 VARBINARY ,否则数据类型为 BLOB

    AS 可以给出 子句以将输入字符串转换为非二进制或二进制字符串并将其强制为给定长度:

    • AS CHAR(N) 将字符串强制转换为非二进制字符串,并将其填充在右侧,并使用空格填充一定长度的 N 字符。 N 必须至少为1.如果 N 小于输入字符串的长度,则字符串将截断为 N 字符。 截断没有警告。

    • AS BINARY(N) 类似但是将字符串转换为二进制字符串, N 以字节(而不是字符)来度量,并且填充使用 0x00 字节(而不是空格)。

    mysql> SET NAMES 'latin1';
    mysql>SELECT HEX(WEIGHT_STRING('ab' AS CHAR(4)));
    + ------------------------------- +
    | HEX(WEIGHT_STRING('ab'AS CHAR(4)))|
    + ------------------------------- +
    | 41422020 |
    + ------------------------------- +
    mysql> SET NAMES 'utf8';
    mysql>SELECT HEX(WEIGHT_STRING('ab' AS CHAR(4)));
    + ------------------------------- +
    | HEX(WEIGHT_STRING('ab'AS CHAR(4)))|
    + ------------------------------- +
    | 0041004200200020 |
    + ------------------------------- +
    
    MySQL的> SELECT HEX(WEIGHT_STRING('ab' AS BINARY(4)));
    + --------------------------------------- +
    | HEX(WEIGHT_STRING('ab'AS BINARY(4)))|
    + --------------------------------------- +
    | 61620000 |
    + --------------------------------------- +
    

    flags 条款目前尚未使用。

12.5.1字符串比较函数

表12.8字符串比较运算符

名称 描述
LIKE 简单的模式匹配
NOT LIKE 简单模式匹配的否定
STRCMP() 比较两个字符串

如果字符串函数被赋予二进制字符串作为参数,则结果字符串也是二进制字符串。 转换为字符串的数字被视为二进制字符串。 这仅影响比较。

通常,如果字符串比较中的任何表达式区分大小写,则以区分大小写的方式执行比较。

  • expr LIKE pat [ESCAPE 'escape_char']

    使用SQL模式进行模式匹配。 返回 1 TRUE )或 0 FALSE )。 如果是, expr 或者 pat NULL ,结果是 NULL

    模式不必是文字字符串。 例如,它可以指定为字符串表达式或表列。

    根据SQL标准, LIKE 在每个字符的基础上执行匹配,因此它可以产生与 = 比较运算符 不同的结果

    MySQL的> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
    + ----------------------------------------- +
    | 'ä'LIKE'ae'COLLATE latin1_german2_ci |
    + ----------------------------------------- +
    | 0 |
    + ----------------------------------------- +
    MySQL的> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
    + -------------------------------------- +
    | 'ä'='ae'COLLATE latin1_german2_ci |
    + -------------------------------------- +
    | 1 |
    + -------------------------------------- +
    

    特别是,尾随空格很重要,但 运营商 进行的比较 不符合 CHAR VARCHAR 比较 =

    MySQL的> SELECT 'a' = 'a ', 'a' LIKE 'a ';
    + ------------ + --------------- +
    | 'a'='a'| 'a'喜欢'a'|
    + ------------ + --------------- +
    | 1 | 0 |
    + ------------ + --------------- +
    1排(0.00秒)
    

    有了 LIKE 可以使用的图案以下两个通配符:

    • % 匹配任意数量的字符,甚至零个字符。

    • _ 恰好匹配一个字符。

    MySQL的> SELECT 'David!' LIKE 'David_';
            - > 1
    MySQL的> SELECT 'David!' LIKE '%D%v%';
            - > 1
    

    要测试通配符的文字实例,请在其前面加上转义字符。 如果您未指定 ESCAPE 字符, \ 则假定。

    • \% 匹配一个 % 字符。

    • \_ 匹配一个 _ 字符。

    MySQL的> SELECT 'David!' LIKE 'David\_';
            - > 0
    MySQL的> SELECT 'David_' LIKE 'David\_';
            - > 1
    

    要指定其他转义字符,请使用以下 ESCAPE 子句:

    MySQL的> SELECT 'David_' LIKE 'David|_' ESCAPE '|';
            - > 1
    

    转义序列应为空或一个字符长。 表达式必须在执行时计算为常量。 如果 NO_BACKSLASH_ESCAPES 启用 SQL模式,则序列不能为空。

    以下两个语句说明字符串比较不区分大小写,除非其中一个操作数区分大小写(使用区分大小写的排序规则或是二进制字符串):

    MySQL的> SELECT 'abc' LIKE 'ABC';
            - > 1
    MySQL的> SELECT 'abc' LIKE _utf8mb4 'ABC' COLLATE utf8mb4_0900_as_cs;
            - > 0
    MySQL的> SELECT 'abc' LIKE _utf8mb4 'ABC' COLLATE utf8mb4_bin;
            - > 0
    MySQL的> SELECT 'abc' LIKE BINARY 'ABC';
            - > 0
    

    作为标准SQL的扩展,MySQL允许 LIKE 使用数字表达式。

    MySQL的> SELECT 10 LIKE '1%';
            - > 1
    
    注意

    因为MySQL在字符串中使用C转义语法(例如, \n 表示换行符),所以必须 \ 将在 LIKE 字符串中 使用的 任何 一个 加倍 例如,要搜索 \n ,请将其指定为 \\n 要搜索 \ ,请将其指定为 \\\\ ; 这是因为反斜杠被解析器剥离一次,并且在进行模式匹配时再次剥离,留下一个反斜杠来匹配。

    例外:在模式字符串的末尾,反斜杠可以指定为 \\ 在字符串的末尾,反斜杠代表自己,因为没有任何东西可以逃脱。 假设一个表包含以下值:

    MySQL的> SELECT filename FROM t1;
    + -------------- +
    | 文件名|
    + -------------- +
    | C:|
    | C:\ |
    | C:\ Programs |
    | C:\ Programs \ |
    + -------------- +
    

    要测试以反斜杠结尾的值,可以使用以下任一模式匹配值:

    MySQL的> SELECT filename, filename LIKE '%\\' FROM t1;
    + -------------- + --------------------- +
    | 文件名| filename LIKE'%\\'|
    + -------------- + --------------------- +
    | C:| 0 |
    | C:\ | 1 |
    | C:\ Programs | 0 |
    | C:\ Programs \ | 1 |
    + -------------- + --------------------- +
    
    MySQL的> SELECT filename, filename LIKE '%\\\\' FROM t1;
    + -------------- + ----------------------- +
    | 文件名| 文件名LIKE'%\\\\'|
    + -------------- + ----------------------- +
    | C:| 0 |
    | C:\ | 1 |
    | C:\ Programs | 0 |
    | C:\ Programs \ | 1 |
    + -------------- + ----------------------- +
    
  • expr NOT LIKE pat [ESCAPE 'escape_char']

    这是一样的 NOT (expr LIKE pat [ESCAPE 'escape_char'])

    注意

    涉及 NOT LIKE 与包含列的比较的 聚合查询 NULL 可能会产生意外结果。 例如,请考虑以下表格和数据:

    CREATE TABLE foo(bar VARCHAR(10));
    
    INSERT INTO foo VALUES(NULL),(NULL);
    

    查询 SELECT COUNT(*) FROM foo WHERE bar LIKE '%baz%'; 返回 0 你可能会认为 SELECT COUNT(*) FROM foo WHERE bar NOT LIKE '%baz%'; 会返回 2 但是,情况并非如此:第二个查询返回 0 这是因为 无论价值如何, 总是返回 对于涉及 和使用 或的 比较的 聚合查询也是如此 在这种情况下,您必须明确测试 使用 (而不是 ),如下所示: NULL NOT LIKE expr NULL expr NULL NOT RLIKE NOT REGEXP NOT NULL OR AND

    SELECT COUNT(*)FROM foo WHERE bar NOT LIKE'%baz%'或bar is NULL;
    
  • STRCMP(expr1,expr2)

    STRCMP() 0 如果字符串相同, -1 如果第一个参数根据当前排序顺序小于第二个参数 返回 1 否则返回。

    MySQL的> SELECT STRCMP('text', 'text2');
            - > -1
    MySQL的> SELECT STRCMP('text2', 'text');
            - > 1
    MySQL的> SELECT STRCMP('text', 'text');
            - > 0
    

    STRCMP() 使用参数的排序规则执行比较。

    mysql> SET @s1 = _utf8mb4 'x' COLLATE utf8mb4_0900_ai_ci;
    mysql> SET @s2 = _utf8mb4 'X' COLLATE utf8mb4_0900_ai_ci;
    mysql> SET @s3 = _utf8mb4 'x' COLLATE utf8mb4_0900_as_cs;
    mysql> SET @s4 = _utf8mb4 'X' COLLATE utf8mb4_0900_as_cs;
    mysql>SELECT STRCMP(@s1, @s2), STRCMP(@s3, @s4);
    + ------------------ + ------------------ +
    | STRCMP(@ s1,@ s2)| STRCMP(@ s3,@ s4)|
    + ------------------ + ------------------ +
    | 0 | -1 |
    + ------------------ + ------------------ +
    

    如果排序规则不兼容,则必须将其中一个参数转换为与另一个相互兼容。 请参见 第10.8.4节“表达式中的校对强制性”

    mysql> SET @ s1 = _utf8mb4'x'COLLATE utf8mb4_0900_ai_ci;
    mysql> SET @ s2 = _utf8mb4'X'COLLATE utf8mb4_0900_ai_ci;
    mysql> SET @ s3 = _utf8mb4'x'COLLATE utf8mb4_0900_as_cs;
    mysql> SET @ s4 = _utf8mb4'X'COLLATE utf8mb4_0900_as_cs;
    - >
    MySQL的> SELECT STRCMP(@s1, @s3);
    ERROR 1267(HY000):非法混合排序(utf8mb4_0900_ai_ci,IMPLICIT)
    和(utf8mb4_0900_as_cs,IMPLICIT)用于操作'strcmp'
    MySQL的> SELECT STRCMP(@s1, @s3 COLLATE utf8mb4_0900_ai_ci);
    + --------------------------------------------- +
    | STRCMP(@ s1,@ s3 COLLATE utf8mb4_0900_ai_ci)|
    + --------------------------------------------- +
    | 0 |
    + --------------------------------------------- +
    

12.5.2正则表达式

表12.9正则表达式函数和运算符

名称 描述
NOT REGEXP REGEXP的否定
REGEXP string是否匹配正则表达式
REGEXP_INSTR() 匹配正则表达式的子串的起始索引
REGEXP_LIKE() string是否匹配正则表达式
REGEXP_REPLACE() 替换匹配正则表达式的子字符串
REGEXP_SUBSTR() 返回子串匹配正则表达式
RLIKE string是否匹配正则表达式

正则表达式是为复杂搜索指定模式的强大方法。 本节讨论可用于正则表达式匹配的函数和运算符,并通过示例说明可用于正则表达式运算的一些特殊字符和构造。 另请参见 第3.3.4.7节“模式匹配”

MySQL使用国际Unicode组件(ICU)实现正则表达式支持,ICU提供完整的Unicode支持并且是多字节安全的。 (在MySQL 8.0.4之前,MySQL使用Henry Spencer的正则表达式实现,它以字节方式运行并且不是多字节安全的。有关使用正则表达式的应用程序可能受实现更改影响的方式的信息,请参阅 正则表达式兼容性注意事项 。)

正则表达式函数和运算符

  • expr NOT REGEXP pat expr NOT RLIKE pat

    这是一样的 NOT (expr REGEXP pat)

  • expr REGEXP pat expr RLIKE pat

    如果字符串 expr 与模式指定的正则表达式匹配,则 返回1,否则返回 pat 0。 如果 expr 或者 pat NULL ,返回值是 NULL

    REGEXP 并且 RLIKE 是同义词 REGEXP_LIKE()

    有关如何进行匹配的其他信息,请参阅说明 REGEXP_LIKE()

    MySQL的> SELECT 'Michael!' REGEXP '.*';
    + ------------------------ +
    | “迈克尔!” REGEXP'。*'|
    + ------------------------ +
    | 1 |
    + ------------------------ +
    MySQL的> SELECT 'new*\n*line' REGEXP 'new\\*.\\*line';
    + --------------------------------------- +
    | 'new * \ n * line'REGEXP'new \\ *。\\ * line'|
    + --------------------------------------- +
    | 0 |
    + --------------------------------------- +
    MySQL的> SELECT 'a' REGEXP '^[a-d]';
    + --------------------- +
    | 'a'REGEXP'^ [ad]'|
    + --------------------- +
    | 1 |
    + --------------------- +
    MySQL的> SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A';
    + ---------------- + ----------------------- +
    | 'a'REGEXP'A'| 'a'REGEXP BINARY'A'|
    + ---------------- + ----------------------- +
    | 1 | 0 |
    + ---------------- + ----------------------- +
    
  • REGEXP_INSTR(expr, pat[, pos[, occurrence[, return_option[, match_type]]]])

    返回与 expr 模式指定的正则表达式匹配 的字符串子字符串的起始索引 pat ,如果没有匹配则返回0。 如果 expr 或者 pat NULL ,返回值是 NULL 字符索引从1开始。

    REGEXP_INSTR() 采用这些可选参数:

    • pos expr 开始搜索的位置。 如果省略,则默认值为1。

    • occurrence :要搜索哪个匹配项。 如果省略,则默认值为1。

    • return_option :返回哪种类型的职位。 如果此值为0,则 REGEXP_INSTR() 返回匹配的子字符串的第一个字符的位置。 如果此值为1,则 REGEXP_INSTR() 返回匹配的子字符串后面的位置。 如果省略,则默认值为0。

    • match_type :一个字符串,指定如何执行匹配。 含义如上所述 REGEXP_LIKE()

    有关如何进行匹配的其他信息,请参阅说明 REGEXP_LIKE()

    MySQL的> SELECT REGEXP_INSTR('dog cat dog', 'dog');
    + ------------------------------------ +
    | REGEXP_INSTR('狗猫狗','狗')|
    + ------------------------------------ +
    | 1 |
    + ------------------------------------ +
    MySQL的> SELECT REGEXP_INSTR('dog cat dog', 'dog', 2);
    + --------------------------------------- +
    | REGEXP_INSTR('狗猫狗','狗',2)|
    + --------------------------------------- +
    | 9 |
    + --------------------------------------- +
    MySQL的> SELECT REGEXP_INSTR('aa aaa aaaa', 'a{2}');
    + ------------------------------- +
    | REGEXP_INSTR('aa aaa aaaa','a {2}')|
    + ------------------------------- +
    | 1 |
    + ------------------------------- +
    MySQL的> SELECT REGEXP_INSTR('aa aaa aaaa', 'a{4}');
    + ------------------------------- +
    | REGEXP_INSTR('aa aaa aaaa','a {4}')|
    + ------------------------------- +
    | 8 |
    + ------------------------------- +
    
  • REGEXP_LIKE(expr, pat[, match_type])

    如果字符串 expr 与模式指定的正则表达式匹配,则 返回1,否则返回 pat 0。 如果 expr 或者 pat NULL ,返回值是 NULL

    该模式可以是扩展的正则表达式,其语法在 正则表达式语法中 讨论 模式不必是文字字符串。 例如,它可以指定为字符串表达式或表列。

    可选 match_type 参数是一个字符串,可以包含指定如何执行匹配的任何或所有以下字符:

    • c :区分大小写的匹配。

    • i :不区分大小写的匹配。

    • m :多行模式。 识别字符串中的行终止符。 默认行为是仅在字符串表达式的开头和结尾处匹配行终止符。

    • n . 字符匹配行终止符。 默认设置是 . 匹配以在行尾停止。

    • u :仅限Unix的行结尾。 只有换行字符识别为结束一条线 . ^ 以及 $ 匹配运算符。

    如果在其中指定了指定矛盾选项的字符 match_type ,则最右边的 字符 优先。

    默认情况下,正则表达式操作 在决定字符类型和执行比较时 使用 expr pat 参数 的字符集和排序规则 如果参数具有不同的字符集或排序规则,则应用强制性规则,如 第10.8.4节“表达式中的排序规范性”中所述 可以使用显式排序规则指定参数来更改比较行为。

    MySQL的> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE');
    + --------------------------------------- +
    | REGEXP_LIKE('CamelCase','CAMELCASE')|
    + --------------------------------------- +
    | 1 |
    + --------------------------------------- +
    MySQL的> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs);
    + ------------------------------------------------- ----------------- +
    | REGEXP_LIKE('CamelCase','CAMELCASE'COLLATE utf8mb4_0900_as_cs)|
    + ------------------------------------------------- ----------------- +
    | 0 |
    + ------------------------------------------------- ----------------- +
    

    match_type 可以使用 c i 字符 指定 覆盖默认区分大小写。 例外:如果任一参数是二进制字符串,则参数将以区分大小写的方式处理为二进制字符串,即使 match_type 包含该 i 字符也是如此。

    注意

    因为MySQL在字符串中使用C转义语法(例如, \n 表示换行符),所以必须 \ 将您在 expr pat 参数中 使用的 任何 一个 加倍

    MySQL的> SELECT REGEXP_LIKE('Michael!', '.*');
    + ------------------------------- +
    | REGEXP_LIKE('迈克尔!','。*')|
    + ------------------------------- +
    | 1 |
    + ------------------------------- +
    MySQL的> SELECT REGEXP_LIKE('new*\n*line', 'new\\*.\\*line');
    + ---------------------------------------------- +
    | REGEXP_LIKE('new * \ n * line','new \\ *。\\ * line')|
    + ---------------------------------------------- +
    | 0 |
    + ---------------------------------------------- +
    MySQL的> SELECT REGEXP_LIKE('a', '^[a-d]');
    + ---------------------------- +
    | REGEXP_LIKE('a','^ [ad]')|
    + ---------------------------- +
    | 1 |
    + ---------------------------- +
    MySQL的> SELECT REGEXP_LIKE('a', 'A'), REGEXP_LIKE('a', BINARY 'A');
    + ----------------------- + ------------------------- ----- +
    | REGEXP_LIKE('a','A')| REGEXP_LIKE('a',BINARY'A')|
    + ----------------------- + ------------------------- ----- +
    | 1 | 0 |
    + ----------------------- + ------------------------- ----- +
    
    MySQL的> SELECT REGEXP_LIKE('abc', 'ABC');
    + --------------------------- +
    | REGEXP_LIKE('abc','ABC')|
    + --------------------------- +
    | 1 |
    + --------------------------- +
    MySQL的> SELECT REGEXP_LIKE('abc', 'ABC', 'c');
    + -------------------------------- +
    | REGEXP_LIKE('abc','ABC','c')|
    + -------------------------------- +
    | 0 |
    + -------------------------------- +
    
  • REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])

    将字符串 expr 中与模式指定的正则表达式匹配的匹配项 pat 替换为替换字符串 repl ,并返回结果字符串。 如果 expr pat 或者 repl 就是 NULL ,返回值 NULL

    REGEXP_REPLACE() 采用这些可选参数:

    • pos expr 开始搜索的位置。 如果省略,则默认值为1。

    • occurrence :要替换哪个匹配项。 如果省略,则默认值为0(表示 替换所有出现次数 )。

    • match_type :一个字符串,指定如何执行匹配。 含义如上所述 REGEXP_LIKE()

    在MySQL 8.0.17之前,此函数返回的结果使用了 UTF-16 字符集; 在MySQL 8.0.17及更高版本中,使用搜索匹配的表达式的字符集和排序规则。 (Bug#94203,Bug#29308212)

    有关如何进行匹配的其他信息,请参阅说明 REGEXP_LIKE()

    MySQL的> SELECT REGEXP_REPLACE('a b c', 'b', 'X');
    + ----------------------------------- +
    | REGEXP_REPLACE('ab c','b','X')|
    + ----------------------------------- +
    | 一个X c |
    + ----------------------------------- +
    MySQL的> SELECT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3);
    + ------------------------------------------------- --- +
    | REGEXP_REPLACE('abc def ghi','[az] +','X',1,3)|
    + ------------------------------------------------- --- +
    | abc def X |
    + ------------------------------------------------- --- +
    
  • REGEXP_SUBSTR(expr, pat[, pos[, occurrence[, match_type]]])

    如果没有匹配 返回与 expr 模式指定的正则表达式匹配 的字符串的子字符串 如果 或者 ,返回值是 pat NULL expr pat NULL NULL

    REGEXP_SUBSTR() 采用这些可选参数:

    • pos expr 开始搜索的位置。 如果省略,则默认值为1。

    • occurrence :要搜索哪个匹配项。 如果省略,则默认值为1。

    • match_type :一个字符串,指定如何执行匹配。 含义如上所述 REGEXP_LIKE()

    在MySQL 8.0.17之前,此函数返回的结果使用了 UTF-16 字符集; 在MySQL 8.0.17及更高版本中,使用搜索匹配的表达式的字符集和排序规则。 (Bug#94203,Bug#29308212)

    有关如何进行匹配的其他信息,请参阅说明 REGEXP_LIKE()

    MySQL的> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+');
    + ---------------------------------------- +
    | REGEXP_SUBSTR('abc def ghi','[az] +')|
    + ---------------------------------------- +
    | abc |
    + ---------------------------------------- +
    MySQL的> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3);
    + ---------------------------------------------- +
    | REGEXP_SUBSTR('abc def ghi','[az] +',1,3)|
    + ---------------------------------------------- +
    | ghi |
    + ---------------------------------------------- +
    

正则表达式语法

正则表达式描述了一组字符串。 最简单的正则表达式是其中没有特殊字符的表达式。 例如,正则表达式 hello 匹配 hello ,没有别的。

非平凡的正则表达式使用某些特殊结构,以便它们可以匹配多个字符串。 例如,正则表达式 hello|world 包含 | 交替运算符并匹配 hello world

作为一个更复杂的实例中,正则表达式 B[an]*s 匹配的任何串的 Bananas Baaaaas Bs ,和任何其他字符串开头的 B ,与结束 s ,和含有任何数目的 a n 在字符之间。

以下列表介绍了可在正则表达式中使用的一些基本特殊字符和构造。 有关用于实现正则表达式支持的ICU库支持的完整正则表达式语法的信息,请访问 International Components for Unicode网站

  • ^

    匹配字符串的开头。

    mysql> SELECT REGEXP_LIKE('fo\nfo', '^fo$');                   - > 0
    mysql> SELECT REGEXP_LIKE('fofo', '^fo');                      - > 1
    
  • $

    匹配字符串的结尾。

    mysql> SELECT REGEXP_LIKE('fo\no', '^fo\no$');                 - > 1
    mysql> SELECT REGEXP_LIKE('fo\no', '^fo$');                    - > 0
    
  • .

    匹配任何字符(包括回车符和换行符,但要在字符串中间匹配这些字符, 必须给出 m (多行)匹配控制字符或 (?m) 模式内修饰符)。

    mysql> SELECT REGEXP_LIKE('fofo', '^f.*$');                    - > 1
    mysql> SELECT REGEXP_LIKE('fo\r\nfo', '^f.*$');                - > 0
    mysql> SELECT REGEXP_LIKE('fo\r\nfo', '^f.*$', 'm');           - > 1
    mysql> SELECT REGEXP_LIKE('fo\r\nfo', '(?m)^f.*$');           - > 1
    
  • a*

    匹配零个或多个 a 字符的 任何序列

    mysql> SELECT REGEXP_LIKE('Ban', '^Ba*n');                     - > 1
    mysql> SELECT REGEXP_LIKE('Baaan', '^Ba*n');                   - > 1
    mysql> SELECT REGEXP_LIKE('Bn', '^Ba*n');                      - > 1
    
  • a+

    匹配一个或多个 a 字符的 任何序列

    mysql> SELECT REGEXP_LIKE('Ban', '^Ba+n');                     - > 1
    mysql> SELECT REGEXP_LIKE('Bn', '^Ba+n');                      - > 0
    
  • a?

    匹配零个或一个 a 字符。

    mysql> SELECT REGEXP_LIKE('Bn', '^Ba?n');                      - > 1
    mysql> SELECT REGEXP_LIKE('Ban', '^Ba?n');                     - > 1
    mysql> SELECT REGEXP_LIKE('Baan', '^Ba?n');                    - > 0
    
  • de|abc

    轮换; 匹配任一序列 de abc

    mysql> SELECT REGEXP_LIKE('pi', 'pi|apa');                     - > 1
    mysql> SELECT REGEXP_LIKE('axe', 'pi|apa');                    - > 0
    mysql> SELECT REGEXP_LIKE('apa', 'pi|apa');                    - > 1
    mysql> SELECT REGEXP_LIKE('apa', '^(pi|apa)$');                - > 1
    mysql> SELECT REGEXP_LIKE('pi', '^(pi|apa)$');                 - > 1
    mysql> SELECT REGEXP_LIKE('pix', '^(pi|apa)$');                - > 0
    
  • (abc)*

    匹配序列的零个或多个实例 abc

    mysql> SELECT REGEXP_LIKE('pi', '^(pi)*$');                    - > 1
    mysql> SELECT REGEXP_LIKE('pip', '^(pi)*$');                   - > 0
    mysql> SELECT REGEXP_LIKE('pipi', '^(pi)*$');                  - > 1
    
  • {1} {2,3}

    重复; 表示法提供了一种更通用的方法来编写正则表达式,这些正则表达式匹配模式的前一个原子(或 片段 )的 多次出现 并且 是整数。 {n} {m,n} m n

    • a*

      可以写成 a{0,}

    • a+

      可以写成 a{1,}

    • a?

      可以写成 a{0,1}

    更确切地说, 匹配完全匹配的 实例 匹配 或更多的实例 通过 实例 匹配 ,包括在内。 如果两个 给出, 必须小于或等于 a{n} n a a{n,} n a a{m,n} m n a m n m n

    mysql> SELECT REGEXP_LIKE('abcde', 'a[bcd]{2}e');              - > 0
    mysql> SELECT REGEXP_LIKE('abcde', 'a[bcd]{3}e');              - > 1
    mysql> SELECT REGEXP_LIKE('abcde', 'a[bcd]{1,10}e');           - > 1
    
  • [a-dX] [^a-dX]

    匹配任何字符,该字符(或不是,如果 ^ 被使用)任一 a b c d X - 其它两个字符之间的字符形成一个所有字符从所述第一字符向所述第二匹配范围。 例如, [0-9] 匹配任何十进制数字。 要包含文字 ] 字符,它必须紧跟在左括号后面 [ 要包含文字 - 字符,必须先写入或最后写入。 任何在a内没有特定含义的字符 [] 对只匹配自己。

    mysql> SELECT REGEXP_LIKE('aXbc', '[a-dXYZ]');                 - > 1
    mysql> SELECT REGEXP_LIKE('aXbc', '^[a-dXYZ]$');               - > 0
    mysql> SELECT REGEXP_LIKE('aXbc', '^[a-dXYZ]+$');              - > 1
    mysql> SELECT REGEXP_LIKE('aXbc', '^[^a-dXYZ]+$');             - > 0
    mysql> SELECT REGEXP_LIKE('gheis', '^[^a-dXYZ]+$');            - > 1
    mysql> SELECT REGEXP_LIKE('gheisa', '^[^a-dXYZ]+$');           - > 0
    
  • [=character_class=]

    在括号表达式(使用 [ 编写 ] )中, [=character_class=] 表示等价类。 它匹配具有相同排序值的所有字符,包括其自身。 例如,如果 o (+) 是一个等价类的成员, [[=o=]] [[=(+)=]] ,和 [o(+)] 都是同义。 等价类不能用作范围的端点。

  • [:character_class:]

    在括号表达式(使用 [ 编写 ] )中, [:character_class:] 表示与属于该类的所有字符匹配的字符类。 下表列出了标准类名。 这些名称代表 ctype(3) 手册页中 定义的字符类 特定区域设置可以提供其他类名。 字符类不能用作范围的端点。

    字符类名称 含义
    alnum 字母数字字符
    alpha 字母字符
    blank 空白字符
    cntrl 控制字符
    digit 数字字符
    graph 图形字符
    lower 小写字母字符
    print 图形或空格字符
    punct 标点字符
    space 空格,制表符,换行符和回车符
    upper 大写字母字符
    xdigit 十六进制数字字符
    mysql> SELECT REGEXP_LIKE('justalnums', '[[:alnum:]]+');       - > 1
    mysql> SELECT REGEXP_LIKE('!!', '[[:alnum:]]+');               - > 0
    

要在正则表达式中使用特殊字符的文字实例,请在其前面加上两个反斜杠(\)字符。 MySQL解析器解释其中一个反斜杠,正则表达式库解释另一个反斜杠。 例如,要匹配 1+2 包含特殊 + 字符 的字符串 ,只有以下正则表达式中的最后一个是正确的:

mysql> SELECT REGEXP_LIKE('1+2', '1+2');                       - > 0
mysql> SELECT REGEXP_LIKE('1+2', '1\+2');                      - > 0
mysql> SELECT REGEXP_LIKE('1+2', '1\\+2');                     - > 1

正则表达式资源控制

REGEXP_LIKE() 和类似的函数使用可以通过设置系统变量来控制的资源:

  • 匹配引擎将内存用于其内部堆栈。 要以字节为单位控制堆栈的最大可用内存,请设置 regexp_stack_limit 系统变量。

  • 匹配引擎分步运行。 要控制引擎执行的最大步数(以及间接执行时间),请设置 regexp_time_limit 系统变量。 由于此限制表示为步数,因此仅间接影响执行时间。 通常,它大约为毫秒。

正则表达式兼容性注意事项

在MySQL 8.0.4之前,MySQL使用Henry Spencer正则表达式库来支持正则表达式操作,而不是使用Unicode的国际组件(ICU)。 以下讨论描述了可能影响应用程序的Spencer和ICU库之间的差异:

  • 使用Spencer库, REGEXP RLIKE 运算符以字节方式工作,因此它们不是多字节安全的,并且可能会产生多字节字符集的意外结果。 此外,这些运算符通过字节值比较字符,并且即使给定的排序规则将重音字符视为相等,重音字符也可能无法比较。

    ICU具有完整的Unicode支持并且是多字节安全的。 它的正则表达式函数将所有字符串视为 UTF-16 您应该记住,位置索引基于16位块而不是代码点。 这意味着,当传递给这些函数时,使用多个块的字符可能会产生意外结果,如下所示:

    MySQL的> SELECT REGEXP_INSTR('🍣🍣b', 'b');
    + -------------------------- +
    | REGEXP_INSTR('?? b','b')|
    + -------------------------- +
    | 5 |
    + -------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT REGEXP_INSTR('🍣🍣bxxx', 'b', 4);
    + -------------------------------- +
    | REGEXP_INSTR('?? bxxx','b',4)|
    + -------------------------------- +
    | 5 |
    + -------------------------------- +
    1排(0.00秒)
    

    Unicode基本多语言平面中的字符(包括大多数现代语言使用的字符)在这方面是安全的:

    MySQL的> SELECT REGEXP_INSTR('бжb', 'b');
    + ---------------------------- +
    | REGEXP_INSTR('бжb','b')|
    + ---------------------------- +
    | 3 |
    + ---------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT REGEXP_INSTR('עבb', 'b');
    + ---------------------------- +
    | REGEXP_INSTR('עבb','b')|
    + ---------------------------- +
    | 3 |
    + ---------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT REGEXP_INSTR('µå周çб', '周');
    + ------------------------------------ +
    | REGEXP_INSTR('μå周çб','周')|
    + ------------------------------------ +
    | 3 |
    + ------------------------------------ +
    1排(0.00秒)
    

    表情符号,例如 前两个例子中使用 寿司 字符 🍣 (U + 1F363),不包括在基本多语言平面中,而是包含在Unicode的辅助多语言平面中。 表情符号和其他4字节字符可能会出现另一个问题 REGEXP_SUBSTR() 或类似的功能开始在角色中间搜索。 以下示例中的两个语句中的每一个都从第一个参数中的第二个2字节位置开始。 第一个语句适用于仅由2字节(BMP)字符组成的字符串。 第二个语句包含4字节字符,这些字符在结果中被错误地解释,因为前两个字节被剥离,因此字符数据的其余部分未对齐。

    MySQL的> SELECT REGEXP_SUBSTR('周周周周', '.*', 2);
    + ---------------------------------------- +
    | REGEXP_SUBSTR('周周周周','。*',2)|
    + ---------------------------------------- +
    | 周周周|
    + ---------------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT REGEXP_SUBSTR('🍣🍣🍣🍣', '.*', 2);
    + -------------------------------- +
    | REGEXP_SUBSTR('????','。*',2)|
    + -------------------------------- +
    | ?㳟揘㳟揘㳟揘|
    + -------------------------------- +
    1排(0.00秒)
    
  • 对于 . 运算符,Spencer库将字符串终止符(回车符,换行符)与字符串表达式中的任何位置匹配,包括在中间。 要匹配字符串中间的行终止符和ICU,请指定 m 匹配控制字符。

  • Spencer库支持单词开头和单词结束边界标记( [[:<:]] 以及 [[:>:]] 表示法)。 ICU没有。 对于ICU,您可以使用 \b 匹配字边界; 加倍反斜杠,因为MySQL将其解释为字符串中的转义字符。

  • Spencer库支持整理元素括号表达式( [.characters.] 表示法)。 ICU没有。

  • 对于重复计数( {n} {m,n} 表示法),Spencer库最多为255.虽然可以通过设置 regexp_time_limit 系统变量 来限制匹配引擎步骤的最大数量,但ICU没有此限制

  • ICU将括号解释为元字符。 ( 在正则表达式中 指定文字左括号 ,必须对其进行转义:

    MySQL的> SELECT REGEXP_LIKE('(', '(');
    ERROR 3692(HY000):正则表达式中的括号不匹配。
    MySQL的> SELECT REGEXP_LIKE('(', '\\(');
    + ------------------------- +
    | REGEXP_LIKE('(','\\(')|
    + ------------------------- +
    | 1 |
    + ------------------------- +
    

12.5.3函数结果的字符集和校对

MySQL有许多返回字符串的运算符和函数。 本节回答了这样一个问题:这种字符串的字符集和整理是什么?

对于采用字符串输入并将字符串结果作为输出返回的简单函数,输出的字符集和排序规则与主输入值的字符集和排序规则相同。 例如, 返回一个字符串和排序规则相同的字符串 这同样适用于 ,和 UPPER(X) X INSTR() LCASE() LOWER() LTRIM() MID() REPEAT() REPLACE() REVERSE() RIGHT() RPAD() RTRIM() SOUNDEX() SUBSTRING() TRIM() UCASE() UPPER()

注意

REPLACE() 与所有其他函数不同, 函数始终忽略字符串输入的排序规则并执行区分大小写的比较。

如果字符串输入或函数结果是二进制字符串,则该字符串具有 binary 字符集和排序规则。 这可以通过使用 CHARSET() COLLATION() 函数 来检查 ,这两个函数都返回 binary 二进制字符串参数:

MySQL的> SELECT CHARSET(BINARY 'a'), COLLATION(BINARY 'a');
+ --------------------- + ----------------------- +
| CHARSET(BINARY'a')| COLLATION(BINARY'a')|
+ --------------------- + ----------------------- +
| 二进制| 二进制|
+ --------------------- + ----------------------- +

对于组合多个字符串输入并返回单个字符串输出的操作, 标准SQL 聚合规则 适用于确定结果的排序 规则

  • 如果发生显式 ,请使用 COLLATE Y Y

  • 如果显式 发生,则引发错误。 COLLATE Y COLLATE Z

  • 否则,如果所有归类都是 Y ,请使用 Y

  • 否则,结果没有排序规则。

例如,使用 ,得到的校对是 这同样适用于 ,和 CASE ... WHEN a THEN b WHEN b THEN c COLLATE X END X UNION || CONCAT() ELT() GREATEST() IF() LEAST()

对于转换为字符数据的操作,字符集和从该操作得到的字符串核对由定义 character_set_connection collation_connection 用于确定默认的连接字符集和归类的系统变量(见 第10.4节,“连接字符集和校对” ) 。 这仅适用于 BIN_TO_UUID() CAST() CONV() FORMAT() HEX() ,和 SPACE()

对于虚拟生成列的表达式,会出现前一个原则的例外情况。 在这样的表达式中,表的字符集被用于 BIN_TO_UUID() CONV() HEX() 结果,而不管连接字符集。

如果对字符串函数返回的结果的字符集或排序规则有任何疑问,请使用 CHARSET() COLLATION() 函数查找:

MySQL的> SELECT USER(), CHARSET(USER()), COLLATION(USER());
+ ---------------- + ----------------- + -------------- ----- +
| USER()| CHARSET(USER())| COLLATION(USER())|
+ ---------------- + ----------------- + -------------- ----- +
| 测试@ localhost | utf8 | utf8_general_ci |
+ ---------------- + ----------------- + -------------- ----- +
MySQL的> SELECT CHARSET(COMPRESS('abc')), COLLATION(COMPRESS('abc'));
+ -------------------------- + ---------------------- ------ +
| CHARSET(COMPRESS('abc'))| COLLATION(COMPRESS('abc'))|
+ -------------------------- + ---------------------- ------ +
| 二进制| 二进制|
+ -------------------------- + ---------------------- ------ +

12.6数字函数和运算符

表12.10数字函数和运算符

名称 描述
ABS() 返回绝对值
ACOS() 返回反余弦
ASIN() 返回圆弧正弦
ATAN() 返回反正切
ATAN2() ATAN() 返回两个参数的反正切
CEIL() 返回不小于参数的最小整数值
CEILING() 返回不小于参数的最小整数值
CONV() 转换不同数字基数之间的数字
COS() 返回余弦
COT() 归还余切
CRC32() 计算循环冗余校验值
DEGREES() 将弧度转换为度数
DIV 整数除法
/ 分部运营商
EXP() 提升到的力量
FLOOR() 返回不大于参数的最大整数值
LN() 返回参数的自然对数
LOG() 返回第一个参数的自然对数
LOG10() 返回参数的以10为底的对数
LOG2() 返回参数的base-2对数
- 减号运算符
MOD() 归还剩下的
% MOD 模数运算符
PI() 返回pi的值
+ 加法运算符
POW() 将引发的参数返回到指定的幂
POWER() 将引发的参数返回到指定的幂
RADIANS() 返回参数转换为弧度
RAND() 返回随机浮点值
ROUND() 围绕论点
SIGN() 返回参数的符号
SIN() 返回参数的正弦值
SQRT() 返回参数的平方根
TAN() 返回参数的正切值
* 乘法运算符
TRUNCATE() 截断到指定的小数位数
- 更改参数的符号

12.6.1算术运算符

表12.11算术运算符

名称 描述
DIV 整数除法
/ 分部运营商
- 减号运算符
% MOD 模数运算符
+ 加法运算符
* 乘法运算符
- 更改参数的符号

通常的算术运算符可用。 结果根据以下规则确定:

  • ,和 的情况下 - 如果两个操作数都是整数, 则以 (64位)精度 计算结果 + * BIGINT

  • 如果两个操作数都是整数且其中任何一个都是无符号的,则结果是无符号整数。 对于减法,如果 NO_UNSIGNED_SUBTRACTION 启用 SQL模式,即使任何操作数未签名,结果也会被签名。

  • 如果任何一个操作数 + - / * % 是一个真正的或字符串值,其结果的精度与最大精度运算的精度。

  • 在执行的除法中 / ,使用两个精确值操作数时的结果比例是第一个操作数的比例加上 div_precision_increment 系统变量 的值 (默认为4)。 例如,表达式的结果 5.05 / 0.014 具有六个小数位( 360.714286 的比例

这些规则适用于每个操作,因此嵌套计算意味着每个组件的精度。 因此, (14620 / 9432456) / (24250 / 9432456) 首先解析 (0.0014) / (0.0026) ,最终结果有8个小数位( 0.60288653 )。

由于这些规则及其应用方式,应注意确保计算的组件和子组件使用适当的精度级别。 请参见 第12.10节“强制转换函数和运算符”

有关在数值表达式求值中处理溢出的信息,请参见 第11.2.6节“超出范围和溢出处理”

算术运算符适用于数字。 对于其他类型的值,可以使用替代操作。 例如,要添加日期值,请使用 DATE_ADD() ; 请参见 第12.7节“日期和时间函数”

  • +

    加成:

    MySQL的> SELECT 3+5;
            - > 8
    
  • -

    减法:

    MySQL的> SELECT 3-5;
            - > -2
    
  • -

    一元减。 此运算符更改操作数的符号。

    MySQL的> SELECT - 2;
            - > -2
    
    注意

    如果此运算符与a一起使用 BIGINT ,则返回值也是a BIGINT 这意味着您应该避免使用 - 值为-2 63的 整数

  • *

    乘法:

    MySQL的> SELECT 3*5;
            - > 15
    MySQL的> SELECT 18014398509481984*18014398509481984.0;
            - > 324518553658426726783156020576256.0
    MySQL的> SELECT 18014398509481984*18014398509481984;
            - >超出范围的错误
    

    最后一个表达式产生错误,因为整数乘法的结果超过了64位 BIGINT 计算 范围 (参见 第11.2节“数字类型” 。)

  • /

    师:

    MySQL的> SELECT 3/5;
            - > 0.60
    

    除以零产生 NULL 结果:

    MySQL的> SELECT 102/(1-1);
            - > NULL
    

    BIGINT 仅当在其结果转换为整数的上下文中执行时,才 使用 算术 计算除法

  • DIV

    整数除法。 从除法中丢弃会导致小数点右边的任何小数部分。

    如果任一操作数具有非整数类型,则 在将结果转换为之前 ,操作数将转换为 DECIMAL 并使用 DECIMAL 算术进行 除法 BIGINT 如果结果超出 BIGINT 范围,则会发生错误。

    MySQL的> SELECT 5 DIV 2, -5 DIV 2, 5 DIV -2, -5 DIV -2;
            - > 2,-2,-2,2
    
  • N % M N MOD M

    模数运算。 返回 N 除以 的余数 M 欲了解更多信息,请参阅说明 MOD() 功能 节12.6.2,“数学函数”

12.6.2数学函数

表12.12数学函数

名称 描述
ABS() 返回绝对值
ACOS() 返回反余弦
ASIN() 返回圆弧正弦
ATAN() 返回反正切
ATAN2() ATAN() 返回两个参数的反正切
CEIL() 返回不小于参数的最小整数值
CEILING() 返回不小于参数的最小整数值
CONV() 转换不同数字基数之间的数字
COS() 返回余弦
COT() 归还余切
CRC32() 计算循环冗余校验值
DEGREES() 将弧度转换为度数
EXP() 提升到的力量
FLOOR() 返回不大于参数的最大整数值
LN() 返回参数的自然对数
LOG() 返回第一个参数的自然对数
LOG10() 返回参数的以10为底的对数
LOG2() 返回参数的base-2对数
MOD() 归还剩下的
PI() 返回pi的值
POW() 将引发的参数返回到指定的幂
POWER() 将引发的参数返回到指定的幂
RADIANS() 返回参数转换为弧度
RAND() 返回随机浮点值
ROUND() 围绕论点
SIGN() 返回参数的符号
SIN() 返回参数的正弦值
SQRT() 返回参数的平方根
TAN() 返回参数的正切值
TRUNCATE() 截断到指定的小数位数

所有数学函数 NULL 在发生错误时 返回

  • ABS(X)

    返回绝对值 X

    MySQL的> SELECT ABS(2);
            - > 2
    MySQL的> SELECT ABS(-32);
            - > 32
    

    此功能可安全地与 BIGINT 一起使用

  • ACOS(X)

    返回反余弦值 X ,即余弦值为的值 X 返回 NULL 如果 X 不在范围内 -1 1

    MySQL的> SELECT ACOS(1);
            - > 0
    MySQL的> SELECT ACOS(1.0001);
            - > NULL
    MySQL的> SELECT ACOS(0);
            - > 1.5707963267949
    
  • ASIN(X)

    返回正弦 X 值的正弦值,即正弦值 X 返回 NULL 如果 X 不在范围内 -1 1

    MySQL的> SELECT ASIN(0.2);
            - > 0.20135792079033
    MySQL的> SELECT ASIN('foo');
    
    + ------------- +
    | ASIN('foo')|
    + ------------- +
    | 0 |
    + ------------- +
    1排,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS;
    + --------- + ------ + -------------------------------- --------- +
    | 等级| 代码| 消息|
    + --------- + ------ + -------------------------------- --------- +
    | 警告| 1292 | 截断不正确的DOUBLE值:'foo'|
    + --------- + ------ + -------------------------------- --------- +
    
  • ATAN(X)

    返回 X 其正切值的反正切值 X

    MySQL的> SELECT ATAN(2);
            - > 1.1071487177941
    MySQL的> SELECT ATAN(-2);
            - > -1.1071487177941
    
  • ATAN(Y,X) ATAN2(Y,X)

    返回两个变量的反正切 X Y 它类似于计算反正切 ,除了两个参数的符号用于确定结果的象限。 Y / X

    MySQL的> SELECT ATAN(-2,2);
            - > -0.78539816339745
    MySQL的> SELECT ATAN2(PI(),0);
            - > 1.5707963267949
    
  • CEIL(X)

    CEIL() 是...的同义词 CEILING()

  • CEILING(X)

    返回不小于的最小整数值 X

    MySQL的> SELECT CEILING(1.23);
            - > 2
    MySQL的> SELECT CEILING(-1.23);
            - > -1
    

    对于精确值数字参数,返回值具有精确值数字类型。 对于字符串或浮点参数,返回值具有浮点类型。

  • CONV(N,from_base,to_base)

    转换不同数字基数之间的数字。 返回数字的字符串表示形式 N ,从base转换 from_base 为base to_base NULL 如果有任何参数,则 返回 NULL 该参数 N 被解释为整数,但可以指定为整数或字符串。 最小基数是 2 ,最大基数是 36 如果 from_base 是负数, N 则视为带符号的数字。 否则, N 被视为未签名。 CONV() 使用64位精度。

    MySQL的> SELECT CONV('a',16,2);
            - >'1010'
    MySQL的> SELECT CONV('6E',18,8);
            - >'172'
    MySQL的> SELECT CONV(-17,10,-18);
            - >'-H'
    MySQL的> SELECT CONV(10+'10'+'10'+X'0a',10,10);
            - > '40'
    
  • COS(X)

    返回余弦 X X 以弧度为单位给出。

    MySQL的> SELECT COS(PI());
            - > -1
    
  • COT(X)

    返回的余切 X

    MySQL的> SELECT COT(12);
            - > -1.5726734063977
    MySQL的> SELECT COT(0);
            - >超出范围的错误
    
  • CRC32(expr)

    计算循环冗余校验值并返回32位无符号值。 结果是 NULL 如果参数是 NULL 该参数应该是一个字符串,并且(如果可能的话)被视为一个,如果不是的话。

    MySQL的> SELECT CRC32('MySQL');
            - > 3259397556
    MySQL的> SELECT CRC32('mysql');
            - > 2501908538
    
  • DEGREES(X)

    返回 X 从弧度转换为度数 的参数

    MySQL的> SELECT DEGREES(PI());
            - > 180
    MySQL的> SELECT DEGREES(PI() / 2);
            - > 90
    
  • EXP(X)

    返回 e 的值 (自然对数的基数)提升到的幂 X 此函数的反函数是 LOG() (仅使用单个参数)或 LN()

    MySQL的> SELECT EXP(2);
            - > 7.3890560989307
    MySQL的> SELECT EXP(-2);
            - > 0.13533528323661
    MySQL的> SELECT EXP(0);
            - > 1
    
  • FLOOR(X)

    返回不大于的最大整数值 X

    MySQL的> SELECT FLOOR(1.23), FLOOR(-1.23);
            - > 1,-2
    

    对于精确值数字参数,返回值具有精确值数字类型。 对于字符串或浮点参数,返回值具有浮点类型。

  • FORMAT(X,D)

    将数字格式化 X 为格式 '#,###,###.##' ,舍入到 D 小数位,并将结果作为字符串返回。 有关详细信息,请参见 第12.5节“字符串函数”

  • HEX(N_or_S)

    此函数可用于获取十进制数或字符串的十六进制表示形式; 它的表达方式根据参数的类型而有所不同。 有关详细信息,请参见 第12.5节“字符串函数”中的 此函数的说明

  • LN(X)

    返回自然对数 X ; 也就是碱基 ê 的对数 X 如果 X 小于或等于0.0E0,函数返回 NULL 和警告 的对数无效参数 报道。

    MySQL的> SELECT LN(2);
            - > 0.69314718055995
    MySQL的> SELECT LN(-2);
            - > NULL
    

    这个功能就是代名词 该函数的反函数是 函数。 LOG(X) EXP()

  • LOG(X) LOG(B,X)

    如果使用一个参数调用,则此函数返回自然对数 X 如果 X 小于或等于0.0E0,函数返回 NULL 和警告 的对数无效参数 报道。

    此函数的反函数(使用单个参数调用时)是 EXP() 函数。

    MySQL的> SELECT LOG(2);
            - > 0.69314718055995
    MySQL的> SELECT LOG(-2);
            - > NULL
    

    如果使用两个参数调用,则此函数返回 X 基数 的对数 B 如果 X 小于或等于0,或者 B 小于或等于1,则 NULL 返回。

    MySQL的> SELECT LOG(2,65536);
            - > 16
    MySQL的> SELECT LOG(10,100);
            - > 2
    MySQL的> SELECT LOG(1,100);
            - > NULL
    

    LOG(B,X) 相当于 LOG(X) / LOG(B)

  • LOG2(X)

    返回的基数为2的对数 X 如果 X 小于或等于0.0E0,函数返回 NULL 和警告 的对数无效参数 报道。

    MySQL的> SELECT LOG2(65536);
            - > 16
    MySQL的> SELECT LOG2(-100);
            - > NULL
    

    LOG2() 有助于找出一个数字需要存储的位数。 此函数等效于表达式 LOG(X) / LOG(2)

  • LOG10(X)

    返回基数为10的对数 X 如果 X 小于或等于0.0E0,函数返回 NULL 和警告 的对数无效参数 报道。

    MySQL的> SELECT LOG10(2);
            - > 0.30102999566398
    MySQL的> SELECT LOG10(100);
            - > 2
    MySQL的> SELECT LOG10(-100);
            - > NULL
    

    LOG10(X) 相当于 LOG(10,X)

  • MOD(N,M) N % M N MOD M

    模数运算。 返回 N 除以 的余数 M

    MySQL的> SELECT MOD(234, 10);
            - > 4
    MySQL的> SELECT 253 % 7;
            - > 1
    MySQL的> SELECT MOD(29,9);
            - > 2
    MySQL的> SELECT 29 MOD 9;
            - > 2
    

    此功能可安全地与 BIGINT 一起使用

    MOD() 也适用于具有小数部分的值,并在除法后返回精确的余数:

    MySQL的> SELECT MOD(34.5,3);
            - > 1.5
    

    MOD(N,0) 回报 NULL

  • PI()

    返回π(pi)的值。 显示的默认小数位数为7,但MySQL在内部使用完整的双精度值。

    MySQL的> SELECT PI();
            - > 3.141593
    MySQL的> SELECT PI()+0.000000000000000000;
            - > 3.141592653589793116
    
  • POW(X,Y)

    返回 X raise的幂值 Y

    MySQL的> SELECT POW(2,2);
            - > 4
    MySQL的> SELECT POW(2,-2);
            - > 0.25
    
  • POWER(X,Y)

    这是一个同义词 POW()

  • RADIANS(X)

    返回参数 X ,从度数转换为弧度。 (注意π弧度等于180度。)

    MySQL的> SELECT RADIANS(90);
            - > 1.5707963267949
    
  • RAND([N])

    返回 <= < v 范围内 的随机浮点值 要获取 范围 <= < 的随机整数 ,请使用表达式 - 例如,要获取范围 <= < 范围内的随机整数 ,请使用以下语句: 0 v 1.0 R i R j FLOOR(i + RAND() * (j i)) 7 R 12

    SELECT FLOOR(7 +(RAND()* 5));
    

    如果 N 指定 了整数参数 ,则将其用作种子值:

    • 使用常量初始化参数,在执行之前,在准备语句时初始化种子。

    • 使用非常量初始值设定项参数(例如列名称),使用每次调用的值初始化种子 RAND()

    这种行为的一个含义是,对于相等的参数值, 每次都返回相同的值,从而产生可重复的列值序列。 在下面的示例中,生成的值序列在 它出现的两个位置都是相同的。 RAND(N) RAND(3)

    
    MySQL的> CREATE TABLE t (i INT);
    查询OK,0行受影响(0.42秒)
    
    MySQL的> INSERT INTO t VALUES(1),(2),(3);
    查询OK,3行受影响(0.00秒)
    记录:3个重复:0个警告:0
    
    MySQL的> SELECT i, RAND() FROM t;
    + ------ + ------------------ +
    | 我| 兰德()|
    + ------ + ------------------ +
    | 1 | 0.61914388706828 |
    | 2 | 0.93845168309142 |
    | 3 | 0.83482678498591 |
    + ------ + ------------------ +
    3组(0.00秒)
    
    MySQL的> SELECT i, RAND(3) FROM t;
    + ------ + ------------------ +
    | 我| 兰德(3)|
    + ------ + ------------------ +
    | 1 | 0.90576975597606 |
    | 2 | 0.37307905813035 |
    | 3 | 0.14808605345719 |
    + ------ + ------------------ +
    3组(0.00秒)
    
    MySQL的> SELECT i, RAND() FROM t;
    + ------ + ------------------ +
    | 我| 兰德()|
    + ------ + ------------------ +
    | 1 | 0.35877890638893 |
    | 2 | 0.28941420772058 |
    | 3 | 0.37073435016976 |
    + ------ + ------------------ +
    3组(0.00秒)
    
    MySQL的> SELECT i, RAND(3) FROM t;
    + ------ + ------------------ +
    | 我| 兰德(3)|
    + ------ + ------------------ +
    | 1 | 0.90576975597606 |
    | 2 | 0.37307905813035 |
    | 3 | 0.14808605345719 |
    + ------ + ------------------ +
    3行(0.01秒)
    

    RAND() WHERE 子句中计算每一行(从一个表中选择时)或行组合(从多表连接中选择时)。 因此,出于优化程序的目的, RAND() 它不是常量值,不能用于索引优化。 有关更多信息,请参见 第8.2.1.19节“函数调用优化”

    RAND() ORDER BY or GROUP BY 子句中 使用 具有 的列 可能会产生意外结果,因为对于任一子句, RAND() 可以对同一行多次计算表达式,每次返回不同的结果。 如果目标是以随机顺序检索行,则可以使用如下语句:

    SELECT * FROM tbl_nameORDER BY RAND();
    

    从一组行中选择一个随机样本,结合 ORDER BY RAND() LIMIT

    SELECT * FROM table1,table2 WHERE a = b AND c <d ORDER BY RAND()LIMIT 1000;
    

    RAND() 并不意味着是一个完美的随机发生器。 这是一种快速生成按需随机数的方法,可以在同一MySQL版本的平台之间移植。

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • ROUND(X) ROUND(X,D)

    将参数舍入 X D 小数位。 舍入算法取决于数据类型 X D 如果未指定,则默认为0。 D 可以为负,导致 D 值的小数点左边的数字 X 变为零。

    MySQL的> SELECT ROUND(-1.23);
            - > -1
    MySQL的> SELECT ROUND(-1.58);
            - > -2
    MySQL的> SELECT ROUND(1.58);
            - > 2
    MySQL的> SELECT ROUND(1.298, 1);
            - > 1.3
    MySQL的> SELECT ROUND(1.298, 0);
            - > 1
    MySQL的> SELECT ROUND(23.298, -1);
            - > 20
    

    返回值与第一个参数具有相同的类型(假设它是整数,双精度或十进制)。 这意味着对于整数参数,结果是一个整数(没有小数位):

    MySQL的> SELECT ROUND(150.000,2), ROUND(150,2);
    + ------------------ + -------------- +
    | ROUND(150.000,2)| ROUND(150,2)|
    + ------------------ + -------------- +
    | 150.00 | 150 |
    + ------------------ + -------------- +
    

    ROUND() 根据第一个参数的类型使用以下规则:

    • 对于精确值数字, ROUND() 使用 从零开始的一半 向最近的方向 规则:如果为正数,则向下舍入到下一个整数或向下舍入到下一个整数负。 (换句话说,它从零开始舍入。)小数小于.5的值如果为正则向下舍入到下一个整数,如果为负,则向下舍入到下一个整数。

    • 对于近似值数字,结果取决于C库。 在许多系统中,这意味着 ROUND() 使用 舍入到最接近的偶数 规则:具有正好在两个整数之间的小数部分的值被舍入到最接近的偶数整数。

    以下示例显示精确值和近似值的舍入方式有何不同:

    MySQL的> SELECT ROUND(2.5), ROUND(25E-1);
    + ------------ + -------------- +
    | ROUND(2.5)| ROUND(25E-1)|
    + ------------ + -------------- +
    | 3 | 2 |
    + ------------ + -------------- +
    

    有关更多信息,请参见 第12.25节“精确数学”

  • SIGN(X)

    返回参数的符号为 -1 0 或者 1 ,根据是否 X 是负数,零或正。

    MySQL的> SELECT SIGN(-32);
            - > -1
    MySQL的> SELECT SIGN(0);
            - > 0
    MySQL的> SELECT SIGN(234);
            - > 1
    
  • SIN(X)

    返回的正弦值 X ,其中 X 以弧度给出。

    MySQL的> SELECT SIN(PI());
            - > 1.2246063538224e-16
    MySQL的> SELECT ROUND(SIN(PI()));
            - > 0
    
  • SQRT(X)

    返回非负数的平方根 X

    MySQL的> SELECT SQRT(4);
            - > 2
    MySQL的> SELECT SQRT(20);
            - > 4.4721359549996
    MySQL的> SELECT SQRT(-16);
            - > NULL
    
  • TAN(X)

    返回切线 X ,其中 X 以弧度为单位。

    MySQL的> SELECT TAN(PI());
            - > -1.2246063538224e-16
    MySQL的> SELECT TAN(PI()+1);
            - > 1.5574077246549
    
  • TRUNCATE(X,D)

    返回数字 X ,截断为 D 小数位。 如果 D 0 ,则结果没有小数点或小数部分。 D 可以为负,导致 D 值的小数点左边的数字 X 变为零。

    MySQL的> SELECT TRUNCATE(1.223,1);
            - > 1.2
    MySQL的> SELECT TRUNCATE(1.999,1);
            - > 1.9
    MySQL的> SELECT TRUNCATE(1.999,0);
            - > 1
    MySQL的> SELECT TRUNCATE(-1.999,1);
            - > -1.9
    MySQL的> SELECT TRUNCATE(122,-2);
           - > 100
    MySQL的> SELECT TRUNCATE(10.28*100,0);
           - > 1028
    

    所有数字都向零舍入。

12。7日期和时间函数

本节介绍可用于处理时间值的函数。 有关 每种日期和时间类型具有的值范围以及可以指定值的有效格式的说明, 请参见 第11.3节“日期和时间类型”

表12。13日期和时间函数

名称 描述
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() 返回月中的某一天(0-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() 从日期参数返回季度
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() 在datetime表达式中添加间隔
TIMESTAMPDIFF() 从日期时间表达式中减去间隔
TO_DAYS() 返回转换为days的日期参数
TO_SECONDS() 返回自0年以来转换为秒的日期或日期时间参数
UNIX_TIMESTAMP() 返回Unix时间戳
UTC_DATE() 返回当前的UTC日期
UTC_TIME() 返回当前的UTC时间
UTC_TIMESTAMP() 返回当前的UTC日期和时间
WEEK() 返回周数
WEEKDAY() 返回工作日索引
WEEKOFYEAR() 返回日期的日历周(1-53)
YEAR() 回归年份
YEARWEEK() 返回年份和星期

这是一个使用日期函数的示例。 以下查询选择具有 date_col 最近30天内值的 所有行

mysql> 
    - >SELECT something FROM tbl_nameWHERE DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= date_col;

该查询还会选择日期位于将来的行。

期望日期值的函数通常接受日期时间值并忽略时间部分。 期望时间值的函数通常接受日期时间值并忽略日期部分。

返回当前日期或时间的函数在查询执行开始时每个查询仅评估一次。 这意味着对诸如 NOW() 单个查询内 的函数的多个引用 总是产生相同的结果。 (对于我们而言,单一的查询还包括对存储程序的调用(存储程序,触发器或事件)以及所有子程序由该程序调用。)这个原则也适用于 CURDATE() CURTIME() UTC_DATE() UTC_TIME() UTC_TIMESTAMP() ,和他们的任何同义词。

CURRENT_TIMESTAMP() CURRENT_TIME() CURRENT_DATE() ,和 FROM_UNIXTIME() 功能在当前会话中的时区,这可作为的会话值返回值 time_zone 系统变量。 此外, UNIX_TIMESTAMP() 假设其参数是会话时区中的日期时间值。 请参见 第5.1.13节“MySQL服务器时区支持”

某些日期函数可以使用 日期或不完整日期,例如 '2001-11-00' ,而其他 日期函数 则不能。 提取日期部分的函数通常使用不完整的日期,因此当您可能期望非零值时可以返回0。 例如:

MySQL的> SELECT DAYOFMONTH('2001-11-00'), MONTH('2005-00-00');
        - > 0,0

其他功能期望完整日期和 NULL 不完整日期的 返回 这些包括执行日期算术或将日期部分映射到名称的函数。 例如:

MySQL的> SELECT DATE_ADD('2006-05-00',INTERVAL 1 DAY);
        - > NULL
MySQL的> SELECT DAYNAME('2006-05-00');
        - > NULL

当传递 DATE() 函数值作为参数 时,有几个函数更严格, 并且在零日的零部分拒绝不完整的日期。 这些功能被影响: CONVERT_TZ() DATE_ADD() DATE_SUB() DAYOFYEAR() LAST_DAY() (允许零天一部分), , TIMESTAMPDIFF() TO_DAYS() TO_SECONDS() WEEK() WEEKDAY() WEEKOFYEAR() YEARWEEK()

支持 ,和 值的小 数秒 TIME 精度高达微秒。 采用时态参数的函数接受带小数秒的值。 时间函数的返回值包括适当的小数秒。 DATETIME TIMESTAMP

  • ADDDATE(date,INTERVAL expr unit) ADDDATE(expr,days)

    当使用 INTERVAL 第二个参数 形式 调用时 ADDDATE() 是同义词 DATE_ADD() 相关功能 SUBDATE() 是其同义词 DATE_SUB() 有关 INTERVAL unit 参数的 信息 ,请参阅 时间间隔

    MySQL的> SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);
            - >'2008-02-02'
    MySQL的> SELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);
            - >'2008-02-02'
    

    当使用 days 第二个参数 形式 调用时 ,MySQL会将其视为要添加的整数天数 expr

    MySQL的> SELECT ADDDATE('2008-01-02', 31);
            - >'2008-02-02'
    
  • ADDTIME(expr1,expr2)

    ADDTIME() 增加了 expr2 expr1 并返回结果。 expr1 是时间或日期时间表达式, expr2 是时间表达式。

    MySQL的> SELECT ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002');
            - >'2008-01-02 01:01:01.000001'
    MySQL的> SELECT ADDTIME('01:00:00.999999', '02:00:00.999998');
            - > '03:00:01.999997'
    
  • CONVERT_TZ(dt,from_tz,to_tz)

    CONVERT_TZ() 将datetime值 dt 从给定的时区 转换为 给定 from_tz 的时区, to_tz 并返回结果值。 时区的指定如 第5.1.13节“MySQL服务器时区支持”中所述 NULL 如果参数无效,则 返回此函数

    如果在 TIMESTAMP from_tz UTC 转换 为UTC 该值超出支持的 类型 范围,则 不会发生转换。 第11.1.2节“日期和时间类型概述”中 TIMESTAMP 介绍了 范围

    MySQL的> SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
            - >'2004-01-01 13:00:00'
    MySQL的> SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');
            - >'2004-01-01 22:00:00'
    
    注意

    要使用诸如 'MET' 或的 命名时区 'Europe/Amsterdam' ,必须正确设置时区表。 有关说明,请参见 第5.1.13节“MySQL服务器时区支持”

  • CURDATE()

    以值 'YYYY-MM-DD' YYYYMMDD 格式 返回当前日期 ,具体取决于函数是在字符串还是数字上下文中使用。

    MySQL的> SELECT CURDATE();
            - >'2008-06-13'
    MySQL的> SELECT CURDATE() + 0;
            - > 20080613
    
  • CURRENT_DATE CURRENT_DATE()

    CURRENT_DATE 并且 CURRENT_DATE() 是同义词 CURDATE()

  • CURRENT_TIME CURRENT_TIME([fsp])

    CURRENT_TIME 并且 CURRENT_TIME() 是同义词 CURTIME()

  • CURRENT_TIMESTAMP CURRENT_TIMESTAMP([fsp])

    CURRENT_TIMESTAMP 并且 CURRENT_TIMESTAMP() 是同义词 NOW()

  • CURTIME([fsp])

    以值 'hh:mm:ss' hhmmss 格式 返回当前时间 ,具体取决于函数是在字符串还是数值上下文中使用。 该值以会话时区表示。

    如果 fsp 给出参数以指定从0到6的小数秒精度,则返回值包括该多个数字的小数秒部分。

    MySQL的> SELECT CURTIME();
            - > '23:50:26'
    MySQL的> SELECT CURTIME() + 0;
            - > 235026.000000
    
  • DATE(expr)

    提取日期或日期时间表达式的日期部分 expr

    MySQL的> SELECT DATE('2003-12-31 01:02:03');
            - >'2003-12-31'
    
  • DATEDIFF(expr1,expr2)

    DATEDIFF() 返回 expr1 - expr2 表示为从一个日期到另一个日期的天数值。 expr1 并且 expr2 是日期或日期和时间表达式。 在计算中仅使用值的日期部分。

    MySQL的> SELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30');
            - > 1
    MySQL的> SELECT DATEDIFF('2010-11-30 23:59:59','2010-12-31');
            - > -31
    
  • DATE_ADD(date,INTERVAL expr unit) DATE_SUB(date,INTERVAL expr unit)

    这些函数执行日期算术。 date 参数指定起始日期或日期时间值。 expr 是一个表达式,用于指定要从开始日期添加或减去的区间值。 expr 被评估为一个字符串; 它可能 - 以负间隔开始。 unit 是一个关键字,指示应该解释表达式的单位。

    有关时间间隔语法的更多信息,包括完整的 unit 说明符 列表, expr 每个 unit 参数 的预期形式 ,以及时间算术中操作数解释的规则,请参阅 时间间隔

    返回值取决于参数:

    • DATE 如果 date 参数是一个 DATE 值,你的计算只涉及 YEAR MONTH DAY 部分(即,没有时间部分)。

    • DATETIME 如果第一个参数是一个 DATETIME (或 TIMESTAMP )值,或者如果第一个参数是一个 DATE unit 值使用 HOURS MINUTES SECONDS

    • 否则为字符串

    为确保结果 DATETIME ,您可以使用 CAST() 将第一个参数转换为 DATETIME

    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'
    
  • DATE_FORMAT(date,format)

    date 根据 format 字符串 格式化

    下表中显示的说明符可以在 format 字符串中使用。 % 格式说明符字符前需要 字符。 该说明符适用于其它功能: STR_TO_DATE() TIME_FORMAT() UNIX_TIMESTAMP()

    描述
    %a 工作日缩写名称( Sun .. Sat
    %b 缩写的月份名称( Jan .. Dec
    %c 月,数字( 0 .. 12
    %D 这个月的一天,英语后缀( 0th 1st 2nd 3rd ,...)
    %d 每月的某一天,数字( 00 .. 31
    %e 每月的某一天,数字( 0 .. 31
    %f 微秒( 000000 ... 999999
    %H 小时( 00 .. 23
    %h 小时( 01 .. 12
    %I 小时( 01 .. 12
    %i 分钟,数字( 00 .. 59
    %j 一年中的一天( 001 .. 366
    %k 小时( 0 .. 23
    %l 小时( 1 .. 12
    %M 月份名称( January .. December
    %m 月,数字( 00 .. 12
    %p AM 要么 PM
    %r 时间,12小时( hh:mm:ss 其次是 AM PM
    %S 秒( 00 ... 59
    %s 秒( 00 ... 59
    %T 时间,24小时( hh:mm:ss
    %U 周( 00 .. 53 ),周日是一周的第一天; WEEK() 模式0
    %u 周( 00 .. 53 ),周一是一周的第一天; WEEK() 模式1
    %V 周( 01 .. 53 ),周日是一周的第一天; WEEK() 模式2; 用于 %X
    %v 周( 01 .. 53 ),周一是一周的第一天; WEEK() 模式3; 用于 %x
    %W 工作日名称( Sunday .. Saturday
    %w 星期几( 0 =星期日.. 6 =星期六)
    %X 星期日是星期的第一天的星期,数字,四位数; 用于 %V
    %x 一周的年份,星期一是一周的第一天,数字,四位数; 用于 %v
    %Y 年份,数字,四位数
    %y 年份,数字(两位数)
    %% 文字 % 字符
    %x x ,对于 上面未列出的 任何 x

    由于MySQL允许存储不完整的日期,例如,因此月份和日期说明符的范围从零开始 '2014-00-00'

    用于日期和月份名称和缩写的语言由 lc_time_names 系统变量 的值控制 第10.15节“MySQL服务器区域设置支持” )。

    对于 %U %u %V ,和 %v 说明符,看到的描述 WEEK() 有关模式值的信息的功能。 该模式会影响周编号的发生方式。

    DATE_FORMAT() 返回由给定的字符集和校对规则的字符串 character_set_connection ,并 collation_connection 使其可以返回一个包含非ASCII字符月和星期名。

    MySQL的> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
            - >'2009年10月10日'
    MySQL的> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
            - > '22:23:00'
    mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
        - >                '%D %y %a %d %m %b %j');
            - >'4th 00 Thu 04 10 Oct 277'
    mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
        - >                '%H %k %I %r %T %S %w');
            - > '22 22 10 10:23:00 PM 22:23:00 00 6'
    MySQL的> SELECT DATE_FORMAT('1999-01-01', '%X %V');
            - >'1998 52'
    MySQL的> SELECT DATE_FORMAT('2006-06-00', '%d');
            - > '00'
    
  • DATE_SUB(date,INTERVAL expr unit)

    请参阅说明 DATE_ADD()

  • DAY(date)

    DAY() 是...的同义词 DAYOFMONTH()

  • DAYNAME(date)

    返回工作日的名称 date 用于名称的语言由 lc_time_names 系统变量 的值控制 第10.15节“MySQL服务器区域设置支持” )。

    MySQL的> SELECT DAYNAME('2007-02-03');
            - >'星期六'
    
  • DAYOFMONTH(date)

    返回月份的 日期 date ,范围 1 31 ,或者 0 日期,例如 '0000-00-00' '2008-00-00' 具有零日部分的日期。

    MySQL的> SELECT DAYOFMONTH('2007-02-03');
            - > 3
    
  • DAYOFWEEK(date)

    返回 date 1 = Sunday, 2 = Monday,..., 7 = Saturday) 的工作日索引 这些索引值对应于ODBC标准。

    MySQL的> SELECT DAYOFWEEK('2007-02-03');
            - > 7
    
  • DAYOFYEAR(date)

    返回一年中的某一天, date 范围 1 366

    MySQL的> SELECT DAYOFYEAR('2007-02-03');
            - > 34
    
  • EXTRACT(unit FROM date)

    EXTRACT() 函数使用与 or 相同类型的 unit 说明符 ,但从日期中提取部分而不是执行日期算术。 有关 参数的 信息 ,请参阅 时间间隔 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
    MySQL的> SELECT EXTRACT(DAY_MINUTE FROM '2019-07-02 01:02:03');
            - > 20102
    mysql> SELECT EXTRACT(MICROSECOND
        - >                FROM '2003-01-02 10:30:00.000123');
            - > 123
    
  • FROM_DAYS(N)

    给定一个天数 N ,返回一个 DATE 值。

    MySQL的> SELECT FROM_DAYS(730669);
            - >'2000-07-03'
    

    FROM_DAYS() 在旧约会上谨慎 使用 它不适用于格里高利历(1582年)出现之前的值。 请参见 第12.8节“MySQL使用什么日历?”

  • FROM_UNIXTIME(unix_timestamp[,format])

    返回 unix_timestamp 参数 的表示形式, 作为值 'YYYY-MM-DD hh:mm:ss' YYYYMMDDhhmmss.uuuuuu 格式,具体取决于函数是在字符串还是数字上下文中使用。 unix_timestamp 是一个内部时间戳值,表示自 '1970-01-01 00:00:00' UTC 以来的秒数 ,例如由 UNIX_TIMESTAMP() 函数 生成的 值。

    返回值以会话时区表示。 (客户端可以按照 第5.1.13节“MySQL服务器时区支持”中 所述设置会话时区 。) format 字符串(如果给定)用于格式化结果,方法与 DATE_FORMAT() 函数 条目中描述的方式相同

    MySQL的> SELECT FROM_UNIXTIME(1447430881);
            - >'2015-11-13 10:08:01'
    MySQL的> SELECT FROM_UNIXTIME(1447430881) + 0;
            - > 20151113100801
    mysql> SELECT FROM_UNIXTIME(1447430881,
        - >                      '%Y %D %M %h:%i:%s %x');
            - >'2015年11月13日10:08:01 2015'
    
    注意

    如果您使用 UNIX_TIMESTAMP() FROM_UNIXTIME() 转换非UTC时区中的值和Unix时间戳值,则转换是有损的,因为映射在两个方向上都不是一对一的。 有关详细信息,请参阅该 UNIX_TIMESTAMP() 功能 的说明

  • GET_FORMAT({DATE|TIME|DATETIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'})

    返回格式字符串。 此功能与 功能 DATE_FORMAT() STR_TO_DATE() 功能 结合使用非常有用

    第一个和第二个参数的可能值导致几个可能的格式字符串(对于使用的 DATE_FORMAT() 说明符 ,请参阅 函数说明中 的表 )。 ISO格式是指ISO 9075,而不是ISO 8601。

    TIMESTAMP 也可以用作第一个参数 GET_FORMAT() ,在这种情况下,函数返回 与之 相同的值 DATETIME

    MySQL的> SELECT DATE_FORMAT('2003-10-03',GET_FORMAT(DATE,'EUR'));
            - > '03 .10.2003'
    MySQL的> SELECT STR_TO_DATE('10.31.2003',GET_FORMAT(DATE,'USA'));
            - >'2003-10-31'
    
  • HOUR(time)

    返回小时 time 返回值的范围是 0 23 时间的日值。 但是, TIME 的范围 实际上要大得多,因此 HOUR 可以返回大于的值 23

    MySQL的> SELECT HOUR('10:05:03');
            - > 10
    MySQL的> SELECT HOUR('272:59:59');
            - > 272
    
  • LAST_DAY(date)

    采用日期或日期时间值并返回该月最后一天的相应值。 NULL 如果参数无效,则 返回

    MySQL的> SELECT LAST_DAY('2003-02-05');
            - >'2003-02-28'
    MySQL的> SELECT LAST_DAY('2004-02-05');
            - >'2004-02-29'
    MySQL的> SELECT LAST_DAY('2004-01-01 01:01:01');
            - >'2004-01-31'
    MySQL的> SELECT LAST_DAY('2003-03-32');
            - > NULL
    
  • LOCALTIME LOCALTIME([fsp])

    LOCALTIME 并且 LOCALTIME() 是同义词 NOW()

  • LOCALTIMESTAMP LOCALTIMESTAMP([fsp])

    LOCALTIMESTAMP 并且 LOCALTIMESTAMP() 是同义词 NOW()

  • MAKEDATE(year,dayofyear)

    返回给定年份和年份值的日期。 dayofyear 必须大于0或结果是 NULL

    MySQL的> SELECT MAKEDATE(2011,31), MAKEDATE(2011,32);
            - >'2011-01-31','2011-02-01'
    MySQL的> SELECT MAKEDATE(2011,365), MAKEDATE(2014,365);
            - >'2011-12-31','2014-12-31'
    MySQL的> SELECT MAKEDATE(2011,0);
            - > NULL
    
  • MAKETIME(hour,minute,second)

    返回从计算出的时间值 hour minute second 参数。

    second 参数可以有小数部分。

    MySQL的> SELECT MAKETIME(12,15,30);
            - > '12:15:30'
    
  • MICROSECOND(expr)

    返回时间或日期时间表达式中的微秒, expr 作为从 0 的范围内的数字 999999

    MySQL的> SELECT MICROSECOND('12:00:00.123456');
            - > 123456
    MySQL的> SELECT MICROSECOND('2019-12-31 23:59:59.000010');
            - > 10
    
  • MINUTE(time)

    返回分钟 time ,范围 0 59

    MySQL的> SELECT MINUTE('2008-02-03 10:05:03');
            - > 5
    
  • MONTH(date)

    返回一个月 date ,在范围内 1 ,以 12 供1- 12月,或 0 为日期,如 '0000-00-00' '2008-00-00' 有一个零一个月的一部分。

    MySQL的> SELECT MONTH('2008-02-03');
            - > 2
    
  • MONTHNAME(date)

    返回月份的全名 date 用于名称的语言由 lc_time_names 系统变量 的值控制 第10.15节“MySQL服务器区域设置支持” )。

    MySQL的> SELECT MONTHNAME('2008-02-03');
            - >'二月'
    
  • NOW([fsp])

    以值 'YYYY-MM-DD hh:mm:ss' YYYYMMDDhhmmss 格式 返回当前日期和时间 ,具体取决于函数是在字符串还是数字上下文中使用。 该值以会话时区表示。

    如果 fsp 给出参数以指定从0到6的小数秒精度,则返回值包括该多个数字的小数秒部分。

    MySQL的> SELECT NOW();
            - >'2007-12-15 23:50:26'
    MySQL的> SELECT NOW() + 0;
            - > 20071215235026.000000
    

    NOW() 返回一个常量时间,指示语句开始执行的时间。 (在存储的函数或触发器中, NOW() 返回函数或触发语句开始执行的时间。)这与行为不同 SYSDATE() ,后者返回执行它的确切时间。

    MySQL的> SELECT NOW(), SLEEP(2), NOW();
    + --------------------- + ---------- + ---------------- ----- +
    | 现在()| SLEEP(2)| 现在()|
    + --------------------- + ---------- + ---------------- ----- +
    | 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |
    + --------------------- + ---------- + ---------------- ----- +
    
    MySQL的> SELECT SYSDATE(), SLEEP(2), SYSDATE();
    + --------------------- + ---------- + ---------------- ----- +
    | SYSDATE()| SLEEP(2)| SYSDATE()|
    + --------------------- + ---------- + ---------------- ----- +
    | 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |
    + --------------------- + ---------- + ---------------- ----- +
    

    此外,该 SET TIMESTAMP 语句会影响返回的值, NOW() 但不会 影响 SYSDATE() 这意味着二进制日志中的时间戳设置对调用没有影响 SYSDATE() 将时间戳设置为非零值会导致每次后续调用都 NOW() 返回该值。 将时间戳设置为零会取消此效果,以便 NOW() 再次返回当前日期和时间。

    有关这 SYSDATE() 两个功能之间差异的其他信息, 请参阅说明

  • PERIOD_ADD(P,N)

    添加 N 月份到期间 P (格式 YYMM YYYYMM )。 返回格式的值 YYYYMM

    注意

    该时期的说法 P 没有 日期值。

    MySQL的> SELECT PERIOD_ADD(200801,2);
            - > 200803
    
  • PERIOD_DIFF(P1,P2)

    返回句点 P1 之间的月数 P2 P1 并且 P2 应该采用格式 YYMM YYYYMM 注意周期参数 P1 P2 不是 日期值。

    MySQL的> SELECT PERIOD_DIFF(200802,200703);
            - > 11
    
  • QUARTER(date)

    返回一年的季度 date ,范围 1 4

    MySQL的> SELECT QUARTER('2008-04-01');
            - > 2
    
  • SECOND(time)

    返回 time 范围 0 的第二个 59

    MySQL的> SELECT SECOND('10:05:03');
            - > 3
    
  • SEC_TO_TIME(seconds)

    返回 seconds 参数,转换为小时,分钟和秒,作为 TIME 值。 结果的范围限制为 TIME 数据类型的范围。 如果参数对应于该范围之外的值,则会发出警告。

    MySQL的> SELECT SEC_TO_TIME(2378);
            - > '00:39:38'
    MySQL的> SELECT SEC_TO_TIME(2378) + 0;
            - > 3938
    
  • STR_TO_DATE(str,format)

    这是 DATE_FORMAT() 函数 的反 函数。 它需要一个字符串 str 和一个格式字符串 format 如果格式字符串包含日期和时间部分,则 STR_TO_DATE() 返回 DATETIME 值;如果字符串仅包含日期或时间部分,则 返回 DATE TIME 值。 如果从中提取的日期,时间或日期时间值 str 是非法的,则 STR_TO_DATE() 返回 NULL 并生成警告。

    服务器扫描 str 尝试匹配 format 它。 格式字符串可以包含以字母开头的文字字符和格式说明符 % 文字字符 format 必须符合字面意思 str 格式说明符 format 必须与日期或时间部分匹配 str 有关可以使用 format DATE_FORMAT() 说明符 ,请参阅 函数说明。

    MySQL的> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y');
            - >'2013-05-01'
    MySQL的> SELECT STR_TO_DATE('May 1, 2013','%M %d,%Y');
            - >'2013-05-01'
    

    扫描在开始时开始, str 如果 format 发现不匹配则 失败 末尾的额外字符将 str 被忽略。

    MySQL的> SELECT STR_TO_DATE('a09:30:17','a%h:%i:%s');
            - > '09:30:17'
    MySQL的> SELECT STR_TO_DATE('a09:30:17','%h:%i:%s');
            - > NULL
    MySQL的> SELECT STR_TO_DATE('09:30:17a','%h:%i:%s');
            - > '09:30:17'
    

    未指定的日期或时间部分的值为0,因此未完全指定的值会 str 产生一些或所有部分设置为0的结果:

    MySQL的> SELECT STR_TO_DATE('abc','abc');
            - >'0000-00-00'
    MySQL的> SELECT STR_TO_DATE('9','%m');
            - >'0000-09-00'
    MySQL的> SELECT STR_TO_DATE('9','%s');
            - > '00:00:09'
    

    对日期值部分的范围检查如 第11.3.1节“DATE,DATETIME和TIMESTAMP类型”中所述 这意味着,例如, 除非将SQL模式设置为禁止此类值,否则允许部分值为0的 日期或日期。

    MySQL的> SELECT STR_TO_DATE('00/00/0000', '%m/%d/%Y');
            - >'0000-00-00'
    MySQL的> SELECT STR_TO_DATE('04/31/2004', '%m/%d/%Y');
            - >'2004-04-31'
    

    如果 启用 SQL NO_ZERO_DATE NO_ZERO_IN_DATE SQL模式,则不允许零日期或部分日期。 在这种情况下, STR_TO_DATE() 返回 NULL 并生成警告:

    mysql> SET sql_mode = '';
    mysql>SELECT STR_TO_DATE('15:35:00', '%H:%i:%s');
    + ------------------------------- +
    | STR_TO_DATE('15:35:00','%H:%i:%s')|
    + ------------------------------- +
    | 15:35:00 |
    + ------------------------------- +
    mysql> SET sql_mode = 'NO_ZERO_IN_DATE';
    mysql>SELECT STR_TO_DATE('15:35:00', '%h:%i:%s');
    + ------------------------------- +
    | STR_TO_DATE('15:35:00','%h:%i:%s')|
    + ------------------------------- +
    | NULL |
    + ------------------------------- +
    MySQL的> SHOW WARNINGS\G
    *************************** 1。排******************** *******
      等级:警告
       代码:1411
    消息:日期时间值不正确:'15:35:00'表示函数str_to_date
    
    注意

    您不能使用格式 "%X%V" 将年周字符串转换为日期,因为如果周超过月边界,则年和周的组合不能唯一标识年和月。 要将年周转换为日期,您还应指定工作日:

    MySQL的> SELECT STR_TO_DATE('200442 Monday', '%X%V %W');
            - >'2004-10-18'
    
  • SUBDATE(date,INTERVAL expr unit) SUBDATE(expr,days)

    当使用 INTERVAL 第二个参数 形式 调用时 SUBDATE() 是同义词 DATE_SUB() 有关 INTERVAL unit 参数的 信息 ,请参阅讨论 DATE_ADD()

    MySQL的> SELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);
            - >'2007-12-02'
    MySQL的> SELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);
            - >'2007-12-02'
    

    第二种形式允许使用整数值 days 在这种情况下,它被解释为从日期或日期时间表达式中减去的天数 expr

    MySQL的> SELECT SUBDATE('2008-01-02 12:00:00', 31);
            - >'2007-12-02 12:00:00'
    
  • SUBTIME(expr1,expr2)

    SUBTIME() 返回 expr1 - expr2 表示为与格式相同的值 expr1 expr1 是时间或日期时间表达式, expr2 是时间表达式。

    MySQL的> SELECT SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002');
            - >'2007-12-30 22:58:58.999997'
    MySQL的> SELECT SUBTIME('01:00:00.999999', '02:00:00.999998');
            - >' -  00:59:59.999999'
    
  • SYSDATE([fsp])

    以值 'YYYY-MM-DD hh:mm:ss' YYYYMMDDhhmmss 格式 返回当前日期和时间 ,具体取决于函数是在字符串还是数字上下文中使用。

    如果 fsp 给出参数以指定从0到6的小数秒精度,则返回值包括该多个数字的小数秒部分。

    SYSDATE() 返回它执行的时间。 这与行为不同 NOW() ,后者返回一个表示语句开始执行的时间的常量时间。 (在存储的函数或触发器中, NOW() 返回函数或触发语句开始执行的时间。)

    MySQL的> SELECT NOW(), SLEEP(2), NOW();
    + --------------------- + ---------- + ---------------- ----- +
    | 现在()| SLEEP(2)| 现在()|
    + --------------------- + ---------- + ---------------- ----- +
    | 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |
    + --------------------- + ---------- + ---------------- ----- +
    
    MySQL的> SELECT SYSDATE(), SLEEP(2), SYSDATE();
    + --------------------- + ---------- + ---------------- ----- +
    | SYSDATE()| SLEEP(2)| SYSDATE()|
    + --------------------- + ---------- + ---------------- ----- +
    | 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |
    + --------------------- + ---------- + ---------------- ----- +
    

    此外,该 SET TIMESTAMP 语句会影响返回的值, NOW() 但不会 影响 SYSDATE() 这意味着二进制日志中的时间戳设置对调用没有影响 SYSDATE()

    因为 SYSDATE() 即使在同一语句中也可以返回不同的值,并且不受其影响 SET TIMESTAMP ,因此如果使用基于语句的二进制日志记录,则它是不确定的,因此对于复制是不安全的。 如果这是一个问题,您可以使用基于行的日志记录。

    或者,您可以使用该 --sysdate-is-now 选项使其 SYSDATE() 成为别名 NOW() 如果在主服务器和从服务器上都使用该选项,则此方法有效。

    非确定性 SYSDATE() 也意味着索引不能用于评估引用它的表达式。

  • TIME(expr)

    提取时间或日期时间表达式的时间部分 expr 并将其作为字符串返回。

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

    MySQL的> SELECT TIME('2003-12-31 01:02:03');
            - > '01:02:03'
    MySQL的> SELECT TIME('2003-12-31 01:02:03.000123');
            - > '01:02:03.000123'
    
  • TIMEDIFF(expr1,expr2)

    TIMEDIFF() 返回 expr1 - expr2 表示为时间值。 expr1 并且 expr2 是时间或日期和时间表达式,但两者必须是相同的类型。

    返回的结果 TIMEDIFF() 仅限于 TIME 允许的范围 另外,您也可以使用的功能 TIMESTAMPDIFF() UNIX_TIMESTAMP() ,两者返回整数。

    mysql> SELECT TIMEDIFF('2000:01:01 00:00:00',
        - >                 '2000:01:01 00:00:00.000001');
            - >'-00:00:00.000001'
    mysql> SELECT TIMEDIFF('2008-12-31 23:59:59.000001',
        - >                '2008-12-30 01:01:01.000002');
            - > '46:58:57.999999'
    
  • TIMESTAMP(expr) TIMESTAMP(expr1,expr2)

    使用单个参数,此函数将日期或日期时间表达式 expr 作为日期时间值返回。 使用两个参数,它将时间表达式添加 expr2 到日期或日期时间表达式 expr1 ,并将结果作为日期时间值返回。

    MySQL的> SELECT TIMESTAMP('2003-12-31');
            - >'2003-12-31 00:00:00'
    MySQL的> SELECT TIMESTAMP('2003-12-31 12:00:00','12:00:00');
            - >'2004-01-01 00:00:00'
    
  • TIMESTAMPADD(unit,interval,datetime_expr)

    将整数表达式添加 interval 到日期或日期时间表达式 datetime_expr 为单元 interval 将被给定 unit 参数,它应为以下值中的一个: MICROSECOND (微秒), , SECOND MINUTE HOUR DAY WEEK MONTH QUARTER YEAR

    unit 可以使用所示的关键字之一或前缀为,来指定 SQL_TSI_ 例如, DAY 并且 SQL_TSI_DAY 都是合法的。

    MySQL的> SELECT TIMESTAMPADD(MINUTE,1,'2003-01-02');
            - >'2003-01-02 00:01:00'
    MySQL的> SELECT TIMESTAMPADD(WEEK,1,'2003-01-02');
            - >'2003-01-09'
    
  • TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)

    返回 datetime_expr2 - datetime_expr1 ,where datetime_expr1 datetime_expr2 date或datetime表达式。 一个表达式可以是日期,另一个表达式可以是日期时间; 日期值被视为具有 '00:00:00' 必要 时间部分的日期时间 结果的单位(整数)由 unit 参数 给出 合法值 unit TIMESTAMPADD() 函数 说明中列出的 相同

    MySQL的> SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');
            - > 3
    MySQL的> SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');
            - > -1
    MySQL的> SELECT TIMESTAMPDIFF(MINUTE,'2003-02-01','2003-05-01 12:05:55');
            - > 128885
    
    注意

    此函数的date或datetime参数的顺序 TIMESTAMP() 与使用2个参数调用时与函数 使用的顺序相反

  • TIME_FORMAT(time,format)

    这与 DATE_FORMAT() 函数 类似 ,但 format 字符串可能只包含小时,分钟,秒和微秒的格式说明符。 其他说明符产生一个 NULL 值或 0

    如果该 time 值中包含一个小时的部分是大于 23 ,则 %H %k 小时的格式说明产生比通常范围大的值 0..23 其他小时格式说明符生成模数为12的小时值。

    MySQL的> SELECT TIME_FORMAT('100:00:00', '%H %k %h %I %l');
            - > '100 100 04 04 4'
    
  • TIME_TO_SEC(time)

    返回 time 参数,转换为秒。

    MySQL的> SELECT TIME_TO_SEC('22:23:00');
            - > 80580
    MySQL的> SELECT TIME_TO_SEC('00:39:38');
            - > 2378
    
  • TO_DAYS(date)

    给定日期 date ,返回日期编号(自0年以来的天数)。

    MySQL的> SELECT TO_DAYS(950501);
            - > 728779
    MySQL的> SELECT TO_DAYS('2007-10-07');
            - > 733321
    

    TO_DAYS() 不适用于格里高利历(1582年)出现之前的值,因为它不考虑日历更改时丢失的日期。 对于1582年之前的日期(可能是其他语言环境中的后一年),此函数的结果不可靠。 有关详细信息 请参见 第12.8节“MySQL使用什么日历?”

    请记住,MySQL使用 第11.3节“日期和时间类型”中 的规则将日期中的两位数年份值转换为四位数形式 例如, '2008-10-07' 并且 '08-10-07' 被看作是相同的日期:

    MySQL的> SELECT TO_DAYS('2008-10-07'), TO_DAYS('08-10-07');
            - > 733687,733687
    

    在MySQL中,零日期被定义为 '0000-00-00' ,即使此日期本身被视为无效。 这意味着,for '0000-00-00' '0000-01-01' TO_DAYS() 返回此处显示的值:

    MySQL的> SELECT TO_DAYS('0000-00-00');
    + ----------------------- +
    | to_days('0000-00-00')|
    + ----------------------- +
    | NULL |
    + ----------------------- +
    1排,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS;
    + --------- + ------ + -------------------------------- -------- +
    | 等级| 代码| 消息|
    + --------- + ------ + -------------------------------- -------- +
    | 警告| 1292 | 日期时间值不正确:'0000-00-00'|
    + --------- + ------ + -------------------------------- -------- +
    1排(0.00秒)
    
    
    MySQL的> SELECT TO_DAYS('0000-01-01');
    + ----------------------- +
    | to_days('0000-01-01')|
    + ----------------------- +
    | 1 |
    + ----------------------- +
    1排(0.00秒)
    

    无论是否 ALLOW_INVALID_DATES 启用S​​QL服务器模式,都是如此。

  • TO_SECONDS(expr)

    给定日期或日期时间 expr ,返回自年份0以来的秒数。如果 expr 不是有效的日期或日期时间值,则返回 NULL

    MySQL的> SELECT TO_SECONDS(950501);
            - > 62966505600
    MySQL的> SELECT TO_SECONDS('2009-11-29');
            - > 63426672000
    MySQL的> SELECT TO_SECONDS('2009-11-29 13:43:32');
            - > 63426721412
    MySQL的> SELECT TO_SECONDS( NOW() );
            - > 63426721458
    

    例如 TO_DAYS() TO_SECONDS() 不适用于格里高利历(1582年)出现之前的值,因为它没有考虑日历更改时丢失的日期。 对于1582年之前的日期(可能是其他语言环境中的后一年),此函数的结果不可靠。 有关详细信息 请参见 第12.8节“MySQL使用什么日历?”

    例如 TO_DAYS() TO_SECONDS() 使用 第11.3节“日期和时间类型”中 的规则将日期中的两位数年份值转换为四位数形式

    在MySQL中,零日期被定义为 '0000-00-00' ,即使此日期本身被视为无效。 这意味着,for '0000-00-00' '0000-01-01' TO_SECONDS() 返回此处显示的值:

    MySQL的> SELECT TO_SECONDS('0000-00-00');
    + -------------------------- +
    | TO_SECONDS('0000-00-00')|
    + -------------------------- +
    | NULL |
    + -------------------------- +
    1排,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS;
    + --------- + ------ + -------------------------------- -------- +
    | 等级| 代码| 消息|
    + --------- + ------ + -------------------------------- -------- +
    | 警告| 1292 | 日期时间值不正确:'0000-00-00'|
    + --------- + ------ + -------------------------------- -------- +
    1排(0.00秒)
    
    
    MySQL的> SELECT TO_SECONDS('0000-01-01');
    + -------------------------- +
    | TO_SECONDS('0000-01-01')|
    + -------------------------- +
    | 86400 |
    + -------------------------- +
    1排(0.00秒)
    

    无论是否 ALLOW_INVALID_DATES 启用S​​QL服务器模式,都是如此。

  • UNIX_TIMESTAMP([date])

    如果 UNIX_TIMESTAMP() 没有 date 参数调用,则返回表示自 '1970-01-01 00:00:00' UTC 以来秒数的Unix时间戳

    如果 UNIX_TIMESTAMP() 使用 date 参数调用,则它将参数的值返回为 '1970-01-01 00:00:00' UTC后的 秒数 服务器将其解释 date 为会话时区中的值,并将其转换为UTC的内部Unix时间戳值。 (客户端可以设置会话时区中描述 第5.1.13,“MySQL服务器时区支持” 。)该 date 参数可以是一个 DATE DATETIME TIMESTAMP 串,或在多个 YYMMDD YYMMDDhhmmss YYYYMMDD ,或者 YYYYMMDDhhmmss 格式。 如果参数包括时间部分,则它可以可选地包括小数秒部分。

    如果没有给出参数或者参数不包含小数秒部分,或者 DECIMAL 如果给出包含小数秒部分的参数,则 返回值是整数

    date 参数是 TIMESTAMP 列时, UNIX_TIMESTAMP() 直接返回内部时间戳值,没有隐式的 字符串到Unix时间戳 转换。

    参数值的有效范围与 TIMESTAMP 数据类型 相同 '1970-01-01 00:00:01.000000' UTC到 '2038-01-19 03:14:07.999999' UTC。 如果您将超出范围的日期传递给 UNIX_TIMESTAMP() ,则返回 0

    MySQL的> SELECT UNIX_TIMESTAMP();
            - > 1447431666
    MySQL的> SELECT UNIX_TIMESTAMP('2015-11-13 10:20:19');
            - > 1447431619
    MySQL的> SELECT UNIX_TIMESTAMP('2015-11-13 10:20:19.012');
            - > 1447431619.012
    

    如果您使用 UNIX_TIMESTAMP() FROM_UNIXTIME() 转换非UTC时区中的值和Unix时间戳值,则转换是有损的,因为映射在两个方向上都不是一对一的。 例如,由于夏令时(DST)等本地时区更改的约定,可以 UNIX_TIMESTAMP() 将两个在非UTC时区中不同的值映射到相同的Unix时间戳值。 FROM_UNIXTIME() 将该值映射回原始值中的一个。 下面是一个示例,使用 MET 时区 中不同的值

    mysql> SET time_zone = 'MET';
    mysql>SELECT UNIX_TIMESTAMP('2005-03-27 03:00:00');
    + --------------------------------------- +
    | UNIX_TIMESTAMP('2005-03-27 03:00:00')|
    + --------------------------------------- +
    | 1111885200 |
    + --------------------------------------- +
    MySQL的> SELECT UNIX_TIMESTAMP('2005-03-27 02:00:00');
    + --------------------------------------- +
    | UNIX_TIMESTAMP('2005-03-27 02:00:00')|
    + --------------------------------------- +
    | 1111885200 |
    + --------------------------------------- +
    MySQL的> SELECT FROM_UNIXTIME(1111885200);
    + --------------------------- +
    | FROM_UNIXTIME(1111885200)|
    + --------------------------- +
    | 2005-03-27 03:00:00 |
    + --------------------------- +
    
    注意

    要使用诸如 'MET' 或的 命名时区 'Europe/Amsterdam' ,必须正确设置时区表。 有关说明,请参见 第5.1.13节“MySQL服务器时区支持”

    如果要减去 UNIX_TIMESTAMP() 列,可能需要将它们转换为有符号整数。 请参见 第12.10节“强制转换函数和运算符”

  • UTC_DATE UTC_DATE()

    以值 'YYYY-MM-DD' YYYYMMDD 格式 返回当前UTC日期 ,具体取决于函数是在字符串还是数字上下文中使用。

    MySQL的> SELECT UTC_DATE(), UTC_DATE() + 0;
            - >'2003-08-14',20030814
    
  • UTC_TIME UTC_TIME([fsp])

    以值 'hh:mm:ss' hhmmss 格式 返回当前UTC时间 ,具体取决于函数是在字符串还是数字上下文中使用。

    如果 fsp 给出参数以指定从0到6的小数秒精度,则返回值包括该多个数字的小数秒部分。

    MySQL的> SELECT UTC_TIME(), UTC_TIME() + 0;
            - > '18:07:53',180753.000000
    
  • UTC_TIMESTAMP UTC_TIMESTAMP([fsp])

    以值 'YYYY-MM-DD hh:mm:ss' YYYYMMDDhhmmss 格式 返回当前UTC日期和时间 ,具体取决于函数是在字符串还是数字上下文中使用。

    如果 fsp 给出参数以指定从0到6的小数秒精度,则返回值包括该多个数字的小数秒部分。

    MySQL的> SELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() + 0;
            - >'2003-08-14 18:08:04',20030814180804.000000
    
  • WEEK(date[,mode])

    此函数返回的周数 date 的双参数形式 WEEK() 允许你指定星期是否在周日或周一,以及是否返回值应在范围从启动 0 53 或者从 1 53 如果 mode 省略 参数, default_week_format 则使用系统变量 的值 请参见 第5.1.8节“服务器系统变量”

    下表描述了 mode 参数的工作原理。

    模式 一周的第一天 范围 第1周是第一周......
    0 星期日 0-53 在今年的一个星期天
    1 星期一 0-53 今年有4天或更多天
    2 星期日 1-53 在今年的一个星期天
    3 星期一 1-53 今年有4天或更多天
    4 星期日 0-53 今年有4天或更多天
    星期一 0-53 在今年的星期一
    6 星期日 1-53 今年有4天或更多天
    7 星期一 1-53 在今年的星期一

    对于 mode 具有的意义价值 有4个或更多天,今年 , ” 1988年:周根据ISO 8601编号:

    • 如果包含1月1日的一周在新的一年中有4天或更多天,则为第1周。

    • 否则,它是上一年的最后一周,下一周是第1周。

    MySQL的> SELECT WEEK('2008-02-20');
            - > 7
    MySQL的> SELECT WEEK('2008-02-20',0);
            - > 7
    MySQL的> SELECT WEEK('2008-02-20',1);
            - > 8
    MySQL的> SELECT WEEK('2008-12-31',1);
            - > 53
    

    如果日期落入在上周的前一年,MySQL的返回 0 ,如果你不使用 2 3 6 ,或 7 作为可选的 mode 参数:

    MySQL的> SELECT YEAR('2000-01-01'), WEEK('2000-01-01',0);
            - > 2000,0
    

    可能有人会说 WEEK() 应该返回 52 ,因为给定的日期实际上是在1999年的第52周时 WEEK() 的回报 0 ,而不是使返回值是 给定年份的周数。 WEEK() 当与从日期中提取日期部分的其他功能结合 使用时,这使得该 功能可靠。

    如果你喜欢就包含了一周的指定日期的第一天计算一年的结果,使用 0 2 5 ,或 7 作为可选 mode 参数。

    MySQL的> SELECT WEEK('2000-01-01',2);
            - > 52
    

    或者,使用以下 YEARWEEK() 功能:

    MySQL的> SELECT YEARWEEK('2000-01-01');
            - > 199952
    MySQL的> SELECT MID(YEARWEEK('2000-01-01'),5,2);
            - > '52'
    
  • WEEKDAY(date)

    返回 date 0 = Monday, 1 = Tuesday,... 6 = Sunday) 的工作日索引

    MySQL的> SELECT WEEKDAY('2008-02-03 22:23:00');
            - > 6
    MySQL的> SELECT WEEKDAY('2007-11-06');
            - > 1
    
  • WEEKOFYEAR(date)

    返回日期从范围内的数字日历星期 1 53 WEEKOFYEAR() 是一个相当于的兼容性函数 WEEK(date,3)

    MySQL的> SELECT WEEKOFYEAR('2008-02-20');
            - > 8
    
  • YEAR(date)

    返回年 date ,范围 1000 9999 ,或 0 日期。

    MySQL的> SELECT YEAR('1987-01-01');
            - > 1987年
    
  • YEARWEEK(date) YEARWEEK(date,mode)

    返回日期的年份和星期。 结果中的年份可能与一年中第一周和最后一周的日期参数中的年份不同。

    mode 论证的作用与 mode 参数 完全相同 WEEK() 对于单参数语法,使用 mode 值0。 不同 WEEK() ,价值 default_week_format 不会影响 YEARWEEK()

    MySQL的> SELECT YEARWEEK('1987-01-01');
            - > 198652
    

    周数是从什么不同的 WEEK() 函数将返回( 0 )的可选参数 0 1 作为 WEEK() 然后返回周中的给定年份的情况下。

12.8 MySQL使用什么日历?

MySQL使用所谓的 公历格里高利历

每个从朱利安日历到格里高利历的国家都不得不在转换期间丢弃至少十天。 要了解其工作原理,请考虑1582年10月,即第一个Julian-to-Gregorian切换发生的月份。

星期一 星期二 星期三 星期四 星期五 星期六 星期日
1 2 3 4 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 三十 31

10月4日至10月15日之间没有日期。这种不连续性称为 转换 切换前的任何日期都是朱利安,切换后的任何日期都是格里高利。 切换期间的日期不存在。

应用于未实际使用的日期的日历称为 预感 因此,如果我们假设从来没有切换和格里高利规则总是统治,我们有一个预感格里高利历。 这是MySQL使用的,正如标准SQL所要求的那样。 出于这个原因,切换之前的日期存储为MySQL DATE DATETIME 必须调整值以补偿差异。 重要的是要意识到切换并非在所有国家同时发生,而且发生的时间越晚,丢失的天数就越多。 例如,在英国,它发生在1752年,当时9月2日星期三之后是9月14日星期四。俄罗斯一直保持朱利安历法直到1918年,在此过程中损失了13天,并且通常被称为 十月” 根据格里高利历法, 革命 发生在11月。

12.9全文搜索功能

MATCH (col1,col2,...) AGAINST (expr [search_modifier])

search_modifier:
  {
       在自然语言模式
     | 具有查询扩展的自然语言模式
     | 在布尔模式
     | 随着扩展
  }

MySQL支持全文索引和搜索:

  • MySQL中的全文索引是类型的索引 FULLTEXT

  • 全文索引只能使用 InnoDB MyISAM 表格,并且只能用于创建 CHAR VARCHAR TEXT 列。

  • MySQL 提供了一个内置的全文ngram解析器,支持中文,日文和韩文(CJK),以及一个可安装的日文版MeCab全文解析器插件。 解析差异在 第12.9.8节“ngram全文分析器” 第12.9.9节“MeCab全文分析器插件” 中概述

  • FULLTEXT 索引定义可以在被给予 CREATE TABLE 的语句中创建表时,或者稍后使用添加 ALTER TABLE CREATE INDEX

  • 对于大型数据集,将数据加载到没有 FULLTEXT 索引 的表中, 然后在此之后创建索引 要快得多 ,而不是将数据加载到具有现有 FULLTEXT 索引 的表中

使用 MATCH() ... AGAINST 语法 执行全文搜索 MATCH() 采用逗号分隔的列表来命名要搜索的列。 AGAINST 获取要搜索的字符串,以及指示要执行的搜索类型的可选修饰符。 搜索字符串必须是在查询评估期间保持不变的字符串值。 例如,这排除了表列,因为每行可能不同。

有三种类型的全文搜索:

  • 自然语言搜索将搜索字符串解释为自然人类语言(自由文本中的短语)中的短语。 没有特殊运算符,但双引号(“)字符除外。 禁用 词列表适用。有关 禁用 词列表的更多信息,请参见 第12.9.4节”全文 停用词

    如果 IN NATURAL LANGUAGE MODE 给出修饰符或者没有给出修饰符,则 全文搜索是自然语言搜索 有关更多信息,请参见 第12.9.1节“自然语言全文搜索”

  • 布尔搜索使用特殊查询语言的规则来解释搜索字符串。 该字符串包含要搜索的单词。 它还可以包含指定要求的运算符,以便在匹配的行中必须存在或不存在单词,或者它应该比通常更高或更低的权重。 搜索索引中省略了某些常用词(停用词),如果搜索字符串中存在,则不匹配。 IN BOOLEAN MODE 修饰符指定一个布尔搜索。 有关更多信息,请参见 第12.9.2节“布尔全文搜索”

  • 查询扩展搜索是自然语言搜索的修改。 搜索字符串用于执行自然语言搜索。 然后将搜索返回的最相关行中的单词添加到搜索字符串中,然后再次进行搜索。 查询返回第二次搜索中的行。 IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION WITH QUERY EXPANSION 修改指定查询扩展搜索。 有关更多信息,请参见 第12.9.3节“使用查询扩展的全文搜索”

有关 FULLTEXT 查询性能的 信息 ,请参见 第8.3.5节“列索引”

有关 InnoDB FULLTEXT 索引的 更多信息 ,请参见 第15.6.2.4节“InnoDB FULLTEXT索引”

第12.9.5节“全文限制” 中列出了对全文搜索的 约束

myisam_ftdump 工具转储的内容 MyISAM 全文索引。 这可能有助于调试全文查询。 请参见 第4.6.3节“ myisam_ftdump - 显示全文索引信息”

12.9.1自然语言全文检索

默认情况下或使用 IN NATURAL LANGUAGE MODE 修饰符, MATCH() 函数会针对 文本集合 执行字符串的自然语言搜索 集合是 FULLTEXT 索引中 包含的一个或多个列的集合 搜索字符串作为参数给出 AGAINST() 对于表中的每一行, MATCH() 返回相关值; 也就是说,搜索字符串与 MATCH() 列表中 指定的列中该行中的文本之间的相似性度量

MySQL的> CREATE TABLE articles (
          id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
          title VARCHAR(200),
          body TEXT,
          FULLTEXT (title,body)
        ) ENGINE=InnoDB;
查询正常,0行受影响(0.08秒)

MySQL的> INSERT INTO articles (title,body) VALUES
        ('MySQL Tutorial','DBMS stands for DataBase ...'),
        ('How To Use MySQL Well','After you went through a ...'),
        ('Optimizing MySQL','In this tutorial we will show ...'),
        ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
        ('MySQL vs. YourSQL','In the following database comparison ...'),
        ('MySQL Security','When configured properly, MySQL ...');
查询OK,6行受影响(0.01秒)
记录:6个重复:0个警告:0

MySQL的> SELECT * FROM articles
        WHERE MATCH (title,body)
        AGAINST ('database' IN NATURAL LANGUAGE MODE);
+ ---- + ------------------- + ------------------------ ------------------ +
| id | 标题| 身体|
+ ---- + ------------------- + ------------------------ ------------------ +
| 1 | MySQL教程| DBMS代表DataBase ... |
| 5 | MySQL与YourSQL | 在以下数据库比较中...... |
+ ---- + ------------------- + ------------------------ ------------------ +
2行(0.00秒)

默认情况下,搜索以不区分大小写的方式执行。 要执行区分大小写的全文搜索,请对索引列使用区分大小写或二进制排序规则。 例如, utf8mb4 可以为 使用 字符集的 分配整数 utf8mb4_0900_as_cs utf8mb4_bin 使其对全文搜索区分大小写。

MATCH() WHERE 子句中 使用时 ,如前面所示的示例中所示,返回的行将首先自动排序,具有最高相关性。 相关性值是非负浮点数。 零相关意味着没有相似性。 相关性是根据行(文档)中的单词数,行中唯一单词的数量,集合中的单词总数以及包含特定单词的行数计算的。

注意

术语 文档 可以与术语 互换使用 ,并且两个术语都指行的索引部分。 术语 集合 指的是索引列并包含所有行。

要简单地计算匹配,您可以使用如下查询:

MySQL的> SELECT COUNT(*) FROM articles
    WHERE MATCH (title,body)
    AGAINST ('database' IN NATURAL LANGUAGE MODE);
+ ---------- +
| COUNT(*)|
+ ---------- +
| 2 |
+ ---------- +
1排(0.00秒)

您可能会发现重写查询的速度更快,如下所示:

MySQL的> SELECT
    COUNT(IF(MATCH (title,body) AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL))
    AS count
    FROM articles;
+ ------- +
| 计数|
+ ------- +
| 2 |
+ ------- +
1排(0.03秒)

第一个查询执行一些额外的工作(按相关性对结果进行排序),但也可以使用基于该 WHERE 子句 的索引查找 如果搜索匹配几行,索引查找可能会使第一个查询更快。 第二个查询执行全表扫描,如果搜索词存在于大多数行中,则可能比索引查找更快。

对于自然语言全文搜索, MATCH() 函数中 指定的列 必须与表中某些 FULLTEXT 索引中 包含的列相同 对于前面的查询,请注意 MATCH() 函数( title body )中指定的列与 article FULLTEXT 索引 定义中指定 的列 相同 单独 搜索 title body 单独 搜索 ,可以 FULLTEXT 为每列 创建单独的 索引。

您还可以执行布尔搜索或使用查询扩展进行搜索。 第12.9.2节“布尔全文搜索” 第12.9.3节“使用查询扩展 的全文搜索” 中介绍了这些搜索类型

使用索引的全文搜索只能从 MATCH() 子句中 的单个表中命名列, 因为索引不能跨越多个表。 对于 MyISAM 表,可以在没有索引的情况下进行布尔搜索(尽管速度较慢),在这种情况下,可以从多个表中命名列。

上面的示例是一个基本插图,显示了如何使用按 MATCH() 相关性降低的顺序返回行 函数。 下一个示例显示了如何显式检索相关性值。 返回的行不是有序的,因为该 SELECT 语句既不包含 WHERE 也不 包含 ORDER BY 子句:

MySQL的> SELECT id, MATCH (title,body)
    AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) AS score
    FROM articles;
+ ---- + --------------------- +
| id | 得分|
+ ---- + --------------------- +
| 1 | 0.22764469683170319 |
| 2 | 0 |
| 3 | 0.22764469683170319 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
+ ---- + --------------------- +
6行(0.00秒)

以下示例更复杂。 查询返回相关性值,它还按相关性递减的顺序对行进行排序。 要实现此结果,请指定 MATCH() 两次:一次在 SELECT 列表中,一次在 WHERE 子句中。 这不会产生额外的开销,因为MySQL优化器注意到这两个 MATCH() 调用是相同的,只调用一次全文搜索代码。

MySQL的> SELECT id, body, MATCH (title,body) AGAINST
    ('Security implications of running MySQL as root'
    IN NATURAL LANGUAGE MODE) AS score
    FROM articles WHERE MATCH (title,body) AGAINST
    ('Security implications of running MySQL as root'
    IN NATURAL LANGUAGE MODE);
+ ---- + ------------------------------- + ------ ----------- +
| id | 身体| 得分|
+ ---- + ------------------------------- + ------ ----------- +
| 4 | 1.永远不要以root身份运行mysqld。2. ... | 1.5219271183014 |
| 6 | 正确配置后,MySQL ... | 1.3114095926285 |
+ ---- + ------------------------------- + ------ ----------- +
2行(0.00秒)

双引号( " )字符中包含的短语仅匹配 字面上 包含短语的行 ,因为它是键入的 全文引擎将短语拆分为单词,并 FULLTEXT 在单词 索引中 执行搜索 非单词字符不需要完全匹配:短语搜索只需要匹配包含与短语完全相同的单词并且顺序相同。 例如, "test phrase" 匹配 "test, phrase" 如果短语不包含索引中的单词,则结果为空。 例如,如果所有单词都是停用词或短于索引单词的最小长度,则结果为空。

MySQL FULLTEXT 实现将任何真实单词字符序列(字母,数字和下划线)视为单词。 该序列也可能包含撇号( ' ),但不能超过一行。 这意味着它 aaa'bbb 被视为一个词,但 aaa''bbb 被视为两个词。 FULLTEXT 解析器 剥离一个单词开头或结尾的撇号 ; 'aaa'bbb' 将被解析为 aaa'bbb

内置 FULLTEXT 解析器通过查找某些分隔符来确定单词的开始和结束位置; 例如,   (空格), , (逗号)和 . (句点)。 如果单词没有用分隔符分隔(例如,中文),则内置 FULLTEXT 解析器无法确定单词的开始或结束位置。 为了能够将这些语言中的单词或其他索引术语添加到 FULLTEXT 使用内置 FULLTEXT 解析器 索引 ,您必须对它们进行预处理,以便它们由某个任意分隔符分隔。 或者,您可以创建 FULLTEXT 使用ngram解析器插件(中文,日文或韩文)或MeCab解析器插件(日文)的索引。

可以编写一个替换内置全文解析器的插件。 有关详细信息,请参见 第29.2节“MySQL插件API” 例如解析器插件源代码,请参阅 plugin/fulltext MySQL源代码分发 目录。

在全文搜索中会忽略某些单词:

  • 任何太短的单词都会被忽略。 通过全文搜索找到的默认最小单词长度是 InnoDB 搜索索引的 三个字符 ,或者四个字符 MyISAM :您可以通过创建索引之前设置一个配置选项来控制截止 innodb_ft_min_token_size 的配置选项 InnoDB 搜索索引,或 ft_min_word_len MyISAM

    注意

    此行为不适用于 FULLTEXT 使用ngram解析器的索引。 对于ngram解析器,令牌长度由 ngram_token_size 选项 定义

  • 禁用词列表中的单词将被忽略。 禁用词是诸如 the some ”之 类的词 ,它是如此常见以至于它被认为具有零语义值。 有一个内置的禁用词列表,但它可以被用户定义的列表覆盖。 对于 InnoDB 搜索索引和 MyISAM 一些 ,停用词列表和相关配置选项是不同 的。 停用词处理由配置选项来控制 innodb_ft_enable_stopword innodb_ft_server_stopword_table innodb_ft_user_stopword_table 用于 InnoDB 搜索的索引,并且 ft_stopword_file 对于 MyISAM 那些。

请参见 第12.9.4节“全文 停用词 以查看默认的停用词列表以及如何更改它们。 可以按 第12.9.6节“微调MySQL全文搜索”中 所述更改默认的最小字长

集合和查询中的每个正确单词都根据其在集合或查询中的重要性进行加权。 因此,许多文档中存在的单词具有较低的权重,因为它在该特定集合中具有较低的语义值。 相反,如果这个词很少见,它会获得更高的权重。 组合单词的权重以计算行的相关性。 这种技术最适合大型集合。

MyISAM限制

对于非常小的表,单词分布不能充分反映其语义值,并且此模型有时可能会对 MyISAM 上的搜索索引产生奇怪的结果 例如,尽管 前面显示 表格的 每一行都有 MySQL articles 一词,但 MyISAM 搜索索引中 的单词 搜索不会产生任何结果:

MySQL的> SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST ('MySQL' IN NATURAL LANGUAGE MODE);
空集(0.00秒)

搜索结果为空,因为 MySQL 一词出现在至少50%的行中,因此被有效地视为一个停用词。 这种过滤技术更适用于大型数据集,您可能不希望结果集从1GB表中返回每隔一行,而不是小型数据集,因为它可能会导致流行术语的结果不佳。

当您第一次尝试全文搜索以查看其工作方式时,50%的阈值会让您感到惊讶,并使 InnoDB 表格更适合全文搜索的实验。 如果您创建一个 MyISAM 表并仅在其中插入一行或两行文本,则文本中的每个单词都会出现在至少50%的行中。 因此,在表包含更多行之前,搜索不会返回任何结果。 需要绕过50%限制的用户可以在 InnoDB 上构建搜索索引 ,或使用 第12.9.2节“布尔全文搜索”中 介绍的布尔搜索模式

12.9.2布尔全文搜索

MySQL可以使用 IN BOOLEAN MODE 修饰符 执行布尔全文搜索 使用此修饰符,某些字符在搜索字符串中的单词的开头或结尾处具有特殊含义。 在以下查询中, + - 运算符分别表示必须存在或不存在单词才能进行匹配。 因此,查询检索包含单词 MySQL 包含单词 YourSQL ”的所有行

MySQL的> SELECT * FROM articles WHERE MATCH (title,body)
    AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
+ ---- + ----------------------- + -------------------- ----------------- +
| id | 标题| 身体|
+ ---- + ----------------------- + -------------------- ----------------- +
| 1 | MySQL教程| DBMS代表DataBase ... |
| 2 | 如何使用MySQL井 经过一段时间...... |
| 3 | 优化MySQL | 在本教程中,我们将展示... |
| 4 | 1001 MySQL技巧| 1.永远不要以root身份运行mysqld。2. ... |
| 6 | MySQL安全| 正确配置后,MySQL ... |
+ ---- + ----------------------- + -------------------- ----------------- +
注意

在实现此功能时,MySQL使用有时被称为 隐含布尔逻辑 的内容

  • + 代表 AND

  • - 代表 NOT

  • [ 无操作员 ]暗示 OR

布尔全文搜索具有以下特征:

  • 它们不会按相关性降低的顺序自动对行进行排序。

  • InnoDB 表需要 表达式的 FULLTEXT 所有列上的索引 MATCH() 来执行布尔查询。 MyISAM 即使没有 FULLTEXT 索引, 搜索索引的 布尔查询 也可以工作 ,尽管以这种方式执行的搜索会非常慢。

  • 最小和最大字长全文参数适用于 FULLTEXT 使用内置 FULLTEXT 解析器和MeCab解析器插件 创建的索引 innodb_ft_min_token_size innodb_ft_max_token_size 用于 InnoDB 搜索索引。 ft_min_word_len ft_max_word_len 用于 MyISAM 搜索索引。

    最小和最大字长全文参数不适用于 FULLTEXT 使用ngram解析器创建的索引。 ngram标记大小由 ngram_token_size 选项 定义

  • 停止字适用,通过控制 innodb_ft_enable_stopword innodb_ft_server_stopword_table 以及 innodb_ft_user_stopword_table InnoDB 搜索索引,并 ft_stopword_file MyISAM 那些。

  • InnoDB 全文搜索不支持在单个搜索词上使用多个运算符,如下例所示: '++apple' 在单个搜索词上使用多个运算符会将语法错误返回到标准输出。 MyISAM全文搜索将成功处理相同的搜索,忽略除紧邻搜索词的运算符之外的所有运算符。

  • InnoDB 全文搜索仅支持前导加号或减号。 例如, InnoDB 支持 '+apple' 但不支持 'apple+' 指定尾随加号或减号会导致 InnoDB 报告语法错误。

  • InnoDB 全文搜索不支持使用带有通配符( '+*' ),加号和减号组合( '+-' )或带正号和减号组合( '+-apple' )的 前导加号 这些无效查询返回语法错误。

  • InnoDB 全文搜索不支持 @ 在布尔 全文搜索中使用该 符号。 @ 符号保留供 @distance 邻近搜索运算符使用。

  • 它们不使用适用于 MyISAM 搜索索引 的50%阈值

布尔全文搜索功能支持以下运算符:

  • +

    前导或尾随加号表示该单词 必须 出现在返回的每一行中。 InnoDB 只支持领先加号。

  • -

    前导或尾随减号表示该单词 不得 出现在任何返回的行中。 InnoDB 只支持领先的减号。

    注意: - 运算符仅用于排除其他搜索项以其他方式匹配的行。 因此,仅包含前面的术语的布尔模式搜索 - 返回空结果。 它不会返回 除包含任何排除条款的行之外的所有行。

  • (没有运营商)

    默认情况下(当既未 指定 + - 指定时),该单词是可选的,但包含它的行的等级更高。 这模仿了 MATCH() ... AGAINST() 没有 IN BOOLEAN MODE 修饰符 的行为

  • @distance

    此运算符 InnoDB 适用于 表。 它测试两个或多个单词是否都在相互指定的距离内开始,用单词测量。 例如, 运算符 之前的双引号字符串中指定搜索词 @distance MATCH(col1) AGAINST('"word1 word2 word3" @8' IN BOOLEAN MODE)

  • > <

    这两个运算符用于更改单词对分配给行的相关性值的贡献。 > 运营商的贡献增加以及 < 运营商降低它。 请参阅此列表后面的示例。

  • ( )

    括号将单词组合成子表达式。 括号内的组可以嵌套。

  • ~

    前导波浪号充当否定运算符,导致该词对该行相关性的贡献为负。 这对标记 噪音 很有用 包含这样一个单词的行的评级低于其他行,但不会像 - 操作员 那样完全排除

  • *

    星号用作截断(或通配符)运算符。 与其他运算符不同,它 附加 到要受影响的单词。 如果单词以 * 操作符 前面的单词开头,则单词匹配

    如果使用截断运算符指定了一个单词,则它不会从布尔查询中删除,即使它太短或是一个停用词。 无论一个字太短从确定 innodb_ft_min_token_size 设置为 InnoDB 表,或 ft_min_word_len MyISAM 表。 这些选项不适用于 FULLTEXT 使用ngram解析器的索引。

    通配字被视为必须出现在一个或多个单词的开头的前缀。 如果最小字长为4,则搜索 可以返回比搜索更少的行 ,因为第二个查询忽略了太短的搜索项 '+word +the*' '+word +the' the

  • "

    双引号( " )字符中包含的短语仅匹配 字面上 包含短语的行 ,因为它是键入的 全文引擎将短语拆分为单词,并 FULLTEXT 在单词 索引中 执行搜索 非单词字符不需要完全匹配:短语搜索只需要匹配包含与短语完全相同的单词并且顺序相同。 例如, "test phrase" 匹配 "test, phrase"

    如果短语不包含索引中的单词,则结果为空。 由于多种因素的组合,单词可能不在索引中:如果它们在文本中不存在,则是停用词,或者短于索引单词的最小长度。

以下示例演示了一些使用布尔全文运算符的搜索字符串:

  • 'apple banana'

    查找包含两个单词中至少一个的行。

  • '+apple +juice'

    查找包含两个单词的行。

  • '+apple macintosh'

    查找包含单词 apple ”的 行,但如果它们也包含 macintosh ”, 则将行排名更高

  • '+apple -macintosh'

    查找包含单词 apple 但不 包含 macintosh ”的行

  • '+apple ~macintosh'

    查找包含单词 apple 的行,但如果该行还包含单词 macintosh ,则将其 评级 为低于不行的行。 比搜索 更柔和 '+apple -macintosh' macintosh 的存在 导致行根本不返回。

  • '+apple +(>turnover <strudel)'

    查找包含单词 apple turnover ,或 apple strudel (按任意顺序)的行,但排名 apple turnover 高于 apple strudel

  • 'apple*'

    查找包含诸如 apple apples applesauce applet 等字词的行

  • '"some words"'

    查找包含具体字词行 有些字 (例如,包含的行 的一些智慧的话 而不是 一些干扰词 )。 请注意, " 包含该短语的字符是分隔该短语的运算符字符。 它们不是包含搜索字符串本身的引号。

InnoDB布尔模式搜索的相关性排名

InnoDB 全文搜索以 Sphinx 全文搜索引擎 为模型,所 使用的算法基于 BM25 TF-IDF 排名算法。 由于这些原因, InnoDB 布尔全文搜索的 MyISAM 相关性排名 可能与 相关性排名 不同

InnoDB 使用 术语频率 - 逆文档频率 TF-IDF )加权系统的变体来对给定全文搜索查询的文档的相关性进行排名。 TF-IDF 权重是基于一个字如何频繁地出现在文档中,通过字如何频繁地出现在集合中的所有文件偏移。 换句话说,单词出现在文档中的频率越高,单词出现在文档集合中的频率越低,文档排名越高。

如何计算相关性排名

术语frequency( TF )值是单词在文档中出现的次数。 IDF 使用以下公式计算单词 的逆文档频率( )值,其中 total_records 是集合中 matching_records 的记录数,以及搜索项出现的记录数。

$ {IDF} = log10($ {total_records} / $ {matching_records})  

当文档多次包含单词时,IDF值乘以TF值:

$ {TF} * $ {IDF}

使用 TF IDF 值,使用以下公式计算文档的相关性排名:

$ {rank} = $ {TF} * $ {IDF} * $ {IDF}

该配方在以下实施例中说明。

单个单词搜索的相关性排名

此示例演示单字搜索的相关性排名计算。

mysql> CREATE TABLE文章(
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
主体,
FULLTEXT(标题,正文)
)ENGINE = InnoDB;
查询OK,0行受影响(1.04秒)

mysql> INSERT INTO文章(标题,正文)VALUES
('MySQL Tutorial','这个数据库教程......'),
(“如何使用MySQL”,“在你经历了......”之后),
('优化数据库','在此数据库教程中......'),
('MySQL vs. YourSQL','比较数据库......'),
('MySQL Security','配置正确,MySQL ......'),
('数据库,数据库,数据库','数据库数据库'),
('1001 MySQL Tricks','1。永远不要以root身份运行mysqld.2。......'),
('MySQL全文索引','MySQL全文索引使用..');                  
查询OK,8行受影响(0.06秒)
记录:8个重复:0个警告:0

mysql> SELECT id,title,body,MATCH(title,body)AGAINST('database'IN BOOLEAN MODE)
AS评分来自文章ORDER BY得分DESC;
+ ---- + ------------------------------ + ------------- ------------------------ + --------------------- +
| id | 标题| 身体| 得分|
+ ---- + ------------------------------ + ------------- ------------------------ + --------------------- +
| 6 | 数据库,数据库,数据库| 数据库数据库| 1.0886961221694946 |
| 3 | 优化您的数据库| 在这个数据库教程中...... | 0.36289870738983154 |
| 1 | MySQL教程| 这个数据库教程...... | 0.18144935369491577 |
| 2 | 如何使用MySQL | 经过一段时间...... | 0 |
| 4 | MySQL与YourSQL | 比较数据库时... | 0 |
| 5 | MySQL安全| 正确配置后,MySQL ... | 0 |
| 7 | 1001 MySQL技巧| 1.永远不要以root身份运行mysqld。2. ... | 0 |
| 8 | MySQL全文索引| MySQL全文索引使用.. | 0 |
+ ---- + ------------------------------ + ------------- ------------------------ + --------------------- +
8行(0.00秒)

总共有8条记录,其中3条与 数据库 搜索词 匹配 第一个记录( id 6 )包含搜索词6次,相关性排名为 1.0886961221694946 该等级值使用 TF 值6( 数据库 搜索词在记录中出现6次 id 6 )和 IDF 值0.42596873216370745计算,其计算如下(其中8是记录总数,3是记录数)搜索词出现在:):

$ {IDF} = log10(8/3)= 0.42596873216370745

然后 TF IDF 值输入到排名公式中:

$ {rank} = $ {TF} * $ {IDF} * $ {IDF}

在MySQL命令行客户端中执行计算会返回排名值1.088696164686938。

mysql> SELECT 6 * log10(8/3)* log10(8/3);
+ ------------------------- +
| 6 * log10(8/3)* log10(8/3)|
+ ------------------------- +
| 1.088696164686938 |
+ ------------------------- +
1排(0.00秒)
注意

您可能会注意到在返回的排名值略有差异 SELECT ... MATCH ... AGAINST 语句和MySQL命令行客户端( 1.0886961221694946 1.088696164686938 )。 不同之处在于整数和浮点数/双精度之间的转换是如何在内部执行的 InnoDB (以及相关的精度和舍入决策),以及它们如何在其他地方执行,例如在MySQL命令行客户端或其他类型的计算器中。

多字搜索的相关性排名

此示例演示了基于 articles 前一示例中使用 表和数据 的多字全文搜索的相关性排名计算

如果您搜索多个单词,则相关性排名值是每个单词的相关性排名值的总和,如下面的公式所示:

$ {rank} = $ {TF} * $ {IDF} * $ {IDF} + $ {TF} * $ {IDF} * $ {IDF}

对两个术语执行搜索('mysql tutorial')会返回以下结果:

mysql> SELECT id,title,body,MATCH(title,body)AGAINST('mysql tutorial'IN BOOLEAN MODE)
    AS评分来自文章ORDER BY得分DESC;
+ ---- + ------------------------------ + ------------- ------------------------ + ---------------------- +
| id | 标题| 身体| 得分|
+ ---- + ------------------------------ + ------------- ------------------------ + ---------------------- +
| 1 | MySQL教程| 这个数据库教程...... | 0.7405621409416199 |
| 3 | 优化您的数据库| 在这个数据库教程中...... | 0.3624762296676636 |
| 5 | MySQL安全| 正确配置后,MySQL ... | 0.031219376251101494 |
| 8 | MySQL全文索引| MySQL全文索引使用.. | 0.031219376251101494 |
| 2 | 如何使用MySQL | 经过一段时间...... | 0.015609688125550747 |
| 4 | MySQL与YourSQL | 比较数据库时... | 0.015609688125550747 |
| 7 | 1001 MySQL技巧| 1.永远不要以root身份运行mysqld。2. ... | 0.015609688125550747 |
| 6 | 数据库,数据库,数据库| 数据库数据库| 0 |
+ ---- + ------------------------------ + ------------- ------------------------ + ---------------------- +
8行(0.00秒)

在第一个记录( id 8 )中,'mysql'出现一次,'tutorial'出现两次。 'mysql'有六个匹配记录,'tutorial'有两个匹配记录。 当将这些值插入到多字搜索的排名公式中时,MySQL命令行客户端返回预期的排名值:

mysql> SELECT(1 * log10(8/6)* log10(8/6))+(2 * log10(8/2)* log10(8/2));
+ ------------------------------------------------- ------ +
| (1 * log10(8/6)* log10(8/6))+(2 * log10(8/2)* log10(8/2))|
+ ------------------------------------------------- ------ +
| 0.7405621541938003 |
+ ------------------------------------------------- ------ +
1排(0.00秒)
注意

SELECT ... MATCH ... AGAINST 在前面的示例中解释 语句和MySQL命令行客户端 返回的排名值的细微差别

12.9.3使用查询扩展的全文搜索

全文搜索支持查询扩展(特别是其变体 盲查询扩展 )。 当搜索短语太短时,这通常很有用,这通常意味着用户依赖于全文搜索引擎所缺乏的隐含知识。 例如,搜索 数据库 的用户 可能实际上意味着 MySQL Oracle DB2 RDBMS 都是应该匹配 数据库 ”的 短语 也应该归还。 这是隐含的知识。

通过添加 WITH QUERY EXPANSION IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 跟随搜索短语 来启用盲查询扩展(也称为自动相关性反馈) 它通过执行两次搜索来工作,其中第二次搜索的搜索短语是与来自第一次搜索的几个最高度相关的文档连接的原始搜索短语。 因此,如果其中一个文档包含单词 databases 和单词 MySQL ,则第二个搜索查找包含单词 MySQL 的文档, 即使它们不包含单词 database 以下示例显示了这种差异:

MySQL的> SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST ('database' IN NATURAL LANGUAGE MODE);
+ ---- + ------------------- + ------------------------ ------------------ +
| id | 标题| 身体|
+ ---- + ------------------- + ------------------------ ------------------ +
| 1 | MySQL教程| DBMS代表DataBase ... |
| 5 | MySQL与YourSQL | 在以下数据库比较中...... |
+ ---- + ------------------- + ------------------------ ------------------ +
2行(0.00秒)

MySQL的> SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST ('database' WITH QUERY EXPANSION);
+ ---- + ----------------------- + -------------------- ---------------------- +
| id | 标题| 身体|
+ ---- + ----------------------- + -------------------- ---------------------- +
| 5 | MySQL与YourSQL | 在以下数据库比较中...... |
| 1 | MySQL教程| DBMS代表DataBase ... |
| 3 | 优化MySQL | 在本教程中,我们将展示... |
| 6 | MySQL安全| 正确配置后,MySQL ... |
| 2 | 如何使用MySQL井 经过一段时间...... |
| 4 | 1001 MySQL技巧| 1.永远不要以root身份运行mysqld。2. ... |
+ ---- + ----------------------- + -------------------- ---------------------- +
6行(0.00秒)

另一个例子是Georges Simenon关于Maigret的书,当用户不确定如何拼写 Maigret ”时 搜索 Megre和不情愿的证人 只发现 Maigret和不情愿的见证人 而没有查询扩展。 使用查询扩展进行搜索会 在第二遍中 找到所有带有 Maigret 字样的书籍

注意

由于盲查询扩展往往会通过返回非相关文档而显着增加噪声,因此仅在搜索短语较短时才使用它。

12.9.4全文停用词

停止字被加载并使用服务器字符集和校对规则(该值搜索全文查询 character_set_server collation_server 系统变量)。 假命中或遗漏如果停止字的文件或使用全文索引或搜索列有一个字符集或整理从不同的可能发生的禁用词查找 character_set_server collation_server

禁用词查找的区分大小写取决于服务器排序规则。 例如,如果排序规则 utf8mb4_0900_ai_ci ,则查找 不区分大小写 ,而如果排序规则为 utf8mb4_0900_as_cs ,则查找区分大小写 utf8mb4_bin

InnoDB搜索索引的停用词

InnoDB 有一个相对较短的默认停用词列表,因为来自技术,文学和其他来源的文档通常使用短词作为关键词或重要短语。 例如,您可能会搜索 成为或不成为 并期望获得合理的结果,而不是忽略所有这些单词。

要查看默认的 InnoDB 停用词列表,请查询该 INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD 表。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;
+ ------- +
| 价值|
+ ------- +
| a |
| 关于|
| 一个|
| 是|
| 作为|
| 在|
| 是|
| 通过|
| com |
| 德|
| en |
| 为|
| 来自|
| 如何|
| 我|
| 在|
| 是|
| 它|
| la |
| 
| 在|
| 或者
| 那个|
| |
| 这个|
| 到|
| 是|
| 什么|
| 当|
| 哪里|
| 谁|
| 将|
| 与|
| und |
| |
| www |
+ ------- +
36行(0.00秒)

要为所有 InnoDB 定义自己的停用词列表 ,请定义一个与表结构相同的 INNODB_FT_DEFAULT_STOPWORD 表,使用停用词填充它,并 在创建全文索引之前 innodb_ft_server_stopword_table 选项的值设置为表单中的值 停用词表必须有一个 名为的列 以下示例演示如何为其创建和配置新的全局停用词表 db_name/table_name VARCHAR value InnoDB

- 创建一个新的停用词表

mysql> CREATE TABLE my_stopwords(value VARCHAR(30))ENGINE = INNODB;
查询OK,0行受影响(0.01秒)

- 插入停用词(为简单起见,在此示例中使用单个停用词)

mysql> INSERT INTO my_stopwords(value)VALUES('Ishmael');
查询正常,1行受影响(0.00秒)

- 创建表格

mysql> CREATE TABLE opening_lines(
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
opening_line TEXT(500),
作者VARCHAR(200),
title VARCHAR(200)
)ENGINE = InnoDB;
查询OK,0行受影响(0.01秒)

- 将数据插入表中

mysql> INSERT INTO opening_lines(opening_line,author,title)VALUES
('叫我以实玛利。','赫尔曼梅尔维尔','白鲸'),
('尖叫声来到天空。','托马斯品钦','重力彩虹',
('我是一个看不见的人。','拉尔夫埃利森','看不见的男人'),
('现在在哪里?谁现在?现在?','Samuel Beckett','The Unnamable'),
('一见钟情。','约瑟夫海勒','Catch-22'),
('所有这一切都发生了,或多或少。','Kurt Vonnegut','屠宰场五'),
('达洛卫太太说她会自己买花。','弗吉尼亚伍尔夫','达洛卫夫人',
('很高兴燃烧。','雷布拉德伯里','华氏451');
查询OK,8行受影响(0.00秒)
记录:8个重复:0个警告:0

- 将innodb_ft_server_stopword_table选项设置为新的停用词表

mysql> SET GLOBAL innodb_ft_server_stopword_table ='test / my_stopwords';
查询正常,0行受影响(0.00秒)

- 创建全文索引(如果未定义FTS_DOC_ID列,则重建表)

mysql> CREATE FULLTEXT INDEX idx ON opening_lines(opening_line);
查询正常,0行受影响,1警告(1.17秒)
记录:0重复:0警告:1

通过查询中的单词,验证指定的停用词('Ishmael')是否未出现 INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE

注意

默认情况下,长度小于3个字符或长度大于84个字符的单词不会出现在 InnoDB 全文搜索索引中。 可以使用 innodb_ft_max_token_size innodb_ft_min_token_size 变量 配置最大和最小字长值 此默认行为不适用于ngram解析器插件。 ngram标记大小由 ngram_token_size 选项 定义

mysql> SET GLOBAL innodb_ft_aux_table ='test / opening_lines';
查询正常,0行受影响(0.00秒)

mysql> SELECT word FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE LIMIT 15;
+ ----------- +
| 字|
+ ----------- +
| 跨越|
| 所有|
| 烧伤|
| 买|
| 打电话
| 来了|
| dalloway |
| 第一个|
| 鲜花|
| 发生了|
| 她自己
| 看不见的
| 少了
| 爱|
| 男人|
+ ----------- +
15行(0.00秒)

要逐个表创建停用词列表,请创建其他停用词表,并使用该 innodb_ft_user_stopword_table 选项指定在创建全文索引之前要使用的停用词表。

MyISAM搜索索引的停用词

停止字文件被加载并使用搜索 latin1 ,如果 character_set_server ucs2 utf16 utf16le ,或 utf32

要覆盖MyISAM表的默认禁用词列表,请设置 ft_stopword_file 系统变量。 (请参见 第5.1.8节“服务器系统变量” 。)变量值应该是包含禁用词列表的文件的路径名,或者是用于禁用禁用词过滤的空字符串。 除非给出绝对路径名以指定其他目录,否则服务器将在数据目录中查找该文件。 更改此变量的值或停用词文件的内容后,重新启动服务器并重建 FULLTEXT 索引。

禁用词列表是自由格式的,将停用词与任何非字母数字字符(如换行符,空格或逗号)分隔开来。 例外是下划线字符( _ )和单个撇号( ' ),它们被视为单词的一部分。 禁用词列表的字符集是服务器的默认字符集; 请参见 第10.3.2节“服务器字符集和排序规则”

以下列表显示了 MyISAM 搜索索引 的默认停用词 在MySQL源代码分发中,您可以在 storage/myisam/ft_static.c 文件中 找到此列表

一个能够达到以上的能力
之后事后实际上相应
再次反对并非全部允许
几乎已经允许了
虽然总是在其中
在一个和另一个中
无论如何任何人都有
无论如何,在任
适当的是不在身边
旁边问一下相关的问题
很可能成为了
因为变得变得过去了
之前在相信之前
除了最好的以外旁边
两者之间的短暂而且
通过c'mon c来了可以
不能不能导致原因
某些肯定会明显改变co
因此,com来了
考虑考虑包含含有
相应的可能当前不能
绝对描述尽管没有
不同的做不做
不要在期间完成
每个教育,例如八个
其他地方尤其如此
等等甚至每一个
每个人每个人到处都是
确切的例子,除了很少
第五个前五个跟随
以前是前者
进一步得到四个
得到给予放弃
走了就走了
问候几乎没有发生
已经没有了
因此,他是你的帮助
她此后来到这里
在这里,她自己嗨
希望他自己也好好相待
但是我怎么会这样
如果我被忽略了,我就是这样
确实很快就会出现这种情况
表明内部表示内部
相反,进入内心则不是
它就是它的全部
本身只是保持不变
知道最近才知道
后来后者至少少了
以免让我们喜欢
可能看起来很小看
有限公司可能很多
我的意思同时只是可能
更重要的是,大部分都是
我必须说出自己的名字
接近几乎必要的需要
不需要从来没有新的
接下来的九个没有人没有
没有人,通常也没有
现在没有什么新奇的了
经常哦好的
一次就好了
仅限于或其他
其他人应该是我们的
我们在外面整体而言
特别是每个人都有
大概请加上可能
可能提供que相当qv
相当合情合理
无论如何相对分别
右说同样的说法
说第二个说第二
看起来似乎看似似乎
看到自我明智的发送
认真严肃的七个应该
她应该不应该六岁
所以有些人不知何故有人
有时某种程度上某些地方
很抱歉指定指定
仍然是这样的肯定
采取倾向      
感谢谢谢
这就是他们的
他们自己然后从那里开始
从那以后就有了
其中就有这些他们
他们是他们,他们是他们认为的
第三,彻底彻底那些
虽然三穿过整个过程
因此也在一起
朝向真正尝试的尝试
尝试两次尝试两次
不幸的是,除非不可能
在我们身上使用
通常使用有用的用途
价值各种非常通过即
vs想要的不是
我们的方式我们就是这样
我们很受欢迎
不是什么时候什么都没有
无论何时何地何地何地
而其中,无论何处何地
无论是谁,谁
谁是谁谁谁谁
为什么愿意和
在没有不会怀疑的情况下
不会是你还是你
你是你,你是你的
你自己零        

12.9.5全文限制

  • 支持 InnoDB MyISAM 表格 的全文搜索

  • 分区表不支持全文搜索。 请参见 第23.6节“分区的限制和限制”

  • 全文搜索可以与大多数多字节字符集一起使用。 例外情况是,对于Unicode, utf8 可以使用字符集,但不能使用 ucs2 字符集。 虽然 无法使用列上的 FULLTEXT 索引 ucs2 ,但您可以 IN BOOLEAN MODE ucs2 没有此类索引 执行 搜索

    该言论 utf8 也适用于 utf8mb4 ,并为言论 ucs2 也适用于 utf16 utf16le utf32

  • 中文和日文等表意语言没有单词分隔符。 因此,内置全文本解析器 无法确定单词在这些语言和其他此类语言中的开始和结束位置

    支持中文,日文和韩文(CJK)的基于字符的ngram全文解析器,以及支持日语的基于单词的MeCab解析器插件,用于 InnoDB MyISAM 一起使用

  • 虽然支持在单个表中使用多个字符集,但 FULLTEXT 索引中的 所有列都 必须使用相同的字符集和排序规则。

  • MATCH() 列列表必须完全在一些列的列表匹配 FULLTEXT 的表索引的定义,除非这 MATCH() IN BOOLEAN MODE 一个 MyISAM 表。 对于 MyISAM 表,布尔模式搜索可以在非索引列上完成,尽管它们可能很慢。

  • 参数 AGAINST() 必须是在查询评估期间保持不变的字符串值。 例如,这排除了表列,因为每行可能不同。

  • 索引提示对于 FULLTEXT 搜索而言比对非 FULLTEXT 搜索 更有限 请参见 第8.9.4节“索引提示”

  • 对于 InnoDB 所有DML操作( INSERT UPDATE DELETE )与全文索引以事务处理涉及列提交时间。 例如,对于 INSERT 操作,插入的字符串被标记化并分解成单个单词。 然后,在提交事务时,将单个单词添加到全文索引表中。 因此,全文搜索仅返回已提交的数据。

  • '%'字符不是全文搜索支持的通配符。

12.9.6微调MySQL全文搜索

MySQL的全文搜索功能几乎没有用户可调参数。 如果您有MySQL源代码分发,则可以对全文搜索行为施加更多控制,因为某些更改需要修改源代码。 请参见 第2.9节“从源安装MySQL”

仔细调整全文搜索的有效性。 在大多数情况下修改默认行为实际上会降低有效性。 除非您知道自己在做什么,否则不要更改MySQL源代码

必须在服务器启动时设置本节中描述的大多数全文变量。 需要重新启动服务器才能更改它们; 它们在服务器运行时无法修改。

某些变量更改要求您重建 FULLTEXT 表中 索引。 有关这样做的说明将在本节后面给出。

配置最小和最大字长

要索引词的最小和最大长度由被定义 innodb_ft_min_token_size innodb_ft_max_token_size 用于 InnoDB 搜索索引,以及 ft_min_word_len ft_max_word_len 用于 MyISAM 人。

注意

最小和最大字长全文参数不适用于 FULLTEXT 使用ngram解析器创建的索引。 ngram标记大小由 ngram_token_size 选项 定义

更改任何这些选项后,重建 FULLTEXT 索引以使更改生效。 例如,要使两个字符的单词可搜索,您可以将以下行放在选项文件中:

的[mysqld]
innodb_ft_min_token_size = 2
的ft_min_word_len = 2

然后重新启动服务器并重建 FULLTEXT 索引。 对于 MyISAM 表格,请注意有关 重建 全文索引 的说明中 有关 myisamchk的 注释 MyISAM

配置自然语言搜索阈值

对于 MyISAM 搜索索引,自然语言搜索的50%阈值由所选的特定加权方案确定。 要禁用它,请在以下位置查找以下行 storage/myisam/ftdefs.h

#define GWS_IN_USE GWS_PROB

将该行更改为:

#define GWS_IN_USE GWS_FREQ

然后重新编译MySQL。 在这种情况下,无需重建索引。

注意

通过进行此更改,会 严重 降低MySQL为 MATCH() 函数 提供足够相关值的能力 如果你真的需要搜索这样的常用词,那么最好使用 IN BOOLEAN MODE 相反的 搜索 ,而不是观察50%的阈值。

修改布尔全文搜索运算符

要更改用于对 MyISAM 进行布尔全文搜索的运算符 ,请设置 ft_boolean_syntax 系统变量。 InnoDB 没有等效设置。)可以在服务器运行时更​​改此变量,但必须具有足以设置全局系统变量的权限(请参见 第5.1.9.1节“系统变量权限” )。 在这种情况下,不需要重建索引。

字符集修改

对于内置的全文本解析器,您可以通过多种方式更改被视为单词字符的字符集,如以下列表中所述。 进行修改后,重建包含任何 FULLTEXT 索引的 每个表的 索引。 假设您要将连字符(' - ')视为单词字符。 使用以下方法之一:

  • 修改MySQL源:在 storage/innobase/handler/ha_innodb.cc (for InnoDB )或in storage/myisam/ftdefs.h (for MyISAM )中,查看 true_word_char() misc_word_char() 宏。 添加 '-' 到其中一个宏并重新编译MySQL。

  • 修改字符集文件:这不需要重新编译。 true_word_char() 宏使用 字符类型 表来从其他字符区分字母和数字。 您可以 <ctype><map> 在其中一个字符集XML文件中 编辑 数组 的内容, 以指定它 '-' 是一个 字母”。 然后使用给定的 FULLTEXT 索引 字符集 有关 <ctype><map> 数组格式的信息,请参见 第10.12.1节“字符定义数组”

  • 为索引列使用的字符集添加新的排序规则,并更改列以使用该排序规则。 有关添加排序 规则的 一般信息,请参见 第10.13节“将排序规则添加到字符集” 有关特定于全文索引的示例,请参见 第12.9.7节“为全文索引添加归类”

重建InnoDB全文索引

为使更改生效, FULLTEXT 索引必须修改以下任何全文索引变量后重建: innodb_ft_min_token_size ; innodb_ft_max_token_size ; innodb_ft_server_stopword_table ; innodb_ft_user_stopword_table ; innodb_ft_enable_stopword ; ngram_token_size 修改 innodb_ft_min_token_size innodb_ft_max_token_size ngram_token_size 需要重新启动服务器。

要重建 FULLTEXT 索引的 InnoDB 表,使用 ALTER TABLE DROP INDEX ADD INDEX 选项删除并重新创建每个索引。

优化InnoDB全文索引

OPTIMIZE TABLE 在具有全文索引的表上 运行会 重建全文索引,删除已删除的文档ID并在可能的情况下合并同一个单词的多个条目。

要优化全文索引,请启用 innodb_optimize_fulltext_only 并运行 OPTIMIZE TABLE

mysql> set GLOBAL innodb_optimize_fulltext_only = ON;
查询OK,0行受影响(0.01秒)

mysql> OPTIMIZE TABLE opening_lines;
+ -------------------- + ---------- + ---------- + ------ ---- +
| 表| Op | Msg_type | Msg_text |
+ -------------------- + ---------- + ---------- + ------ ---- +
| test.opening_lines | 优化| 状态| 好的
+ -------------------- + ---------- + ---------- + ------ ---- +
1排(0.01秒)    

要避免大型表上的全文索引的冗长重建时间,可以使用该 innodb_ft_num_word_optimize 选项分阶段执行优化。 innodb_ft_num_word_optimize 选项定义每次 OPTIMIZE TABLE 运行时 优化的单词数 默认设置为2000,这意味着每次 OPTIMIZE TABLE 运行 都会 优化2000个字 后续 OPTIMIZE TABLE 操作从前一 OPTIMIZE TABLE 操作结束的 地方继续

重建MyISAM全文索引

如果修改影响索引( ft_min_word_len ft_max_word_len ft_stopword_file 的全文变量 ,或者更改了停用词文件本身,则必须 FULLTEXT 在进行更改并重新启动服务器后 重建 索引。

要重建 FULLTEXT 索引,只需 MyISAM 执行 QUICK 修复操作即可:

MySQL的> REPAIR TABLE tbl_name QUICK;

或者,如上所述使用 ALTER TABLE 在某些情况下,这可能比修复操作更快。

FULLTEXT 必须修复 包含任何 索引的 每个表, 如刚才所示。 否则,对表的查询可能会产生不正确的结果,对表的修改将导致服务器将表视为损坏并需要修复。

如果使用 myisamchk 执行修改 MyISAM 表索引 的操作 (例如修复或分析),则 FULLTEXT 使用 默认 的全文参数值(最小字长,最大字长和停用词文件 重建索引 ,除非您另行指定。 这可能导致查询失败。

出现此问题的原因是这些参数仅由服务器知道。 它们不存储在 MyISAM 索引文件中。 为了避免这个问题,如果你已经修改服务器所使用的最小或最大字长或停止字文件值,指定相同的 ft_min_word_len ft_max_word_len 以及 ft_stopword_file 对价值观 myisamchk的 ,你使用 的mysqld 例如,如果您将最小字长设置为3,则可以使用 myisamchk 修复表, 如下所示:

myisamchk --recover --ft_min_word_len = 3 tbl_name.MYI

为了确保 myisamchk的 和服务器使用相同的值进行全文参数,将每一项都在 [mysqld] [myisamchk] 选项文件的部分:

的[mysqld]
的ft_min_word_len = 3

[myisamchk的]
的ft_min_word_len = 3

到使用替代 myisamchk的 用于 MyISAM 表索引修改是使用 REPAIR TABLE ANALYZE TABLE OPTIMIZE TABLE ,或 ALTER TABLE 语句。 这些语句由服务器执行,服务器知道要使用的正确的全文参数值。

12.9.7为全文索引添加排序规则

本节介绍如何使用内置全文本解析器为全文搜索添加新的排序规则。 样本排序规则类似, latin1_swedish_ci 但将 '-' 字符视为字母而不是标点符号,以便将其编入索引为单词字符。 有关添加排序 规则的 一般信息,请参见 第10.13节“向字符集添加排序规则” ; 假设您已阅读并熟悉所涉及的文件。

要为全文索引添加排序规则,请使用以下过程。 此处的说明为简单字符集 添加了排序规则 ,如 第10.13节“向字符集添加排序规则”中所述 ,可以使用描述字符集属性的配置文件创建。 对于Unicode等复杂字符集,使用描述字符集属性的C源文件创建排序规则。

  1. Index.xml 文件 添加排序规则 归类ID必须未使用,因此如果已在系统上使用该ID,请选择不同于1000的值。

    <charset name =“latin1”>
    ...
    <collat​​ion name =“latin1_fulltext_ci”id =“1000”/>
    </字符集>
    
  2. 声明文件中排序规则的排序顺序 latin1.xml 在这种情况下,订单可以从 latin1_swedish_ci 以下位置 复制

    <collat​​ion name =“latin1_fulltext_ci”>
    <地图>
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
    20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
    30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
    50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
    60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
    50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
    80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
    90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
    A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
    B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
    41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
    44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
    41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
    44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
    </地图>
    </核对>
    
  3. 修改 ctype 数组 latin1.xml 将对应于0x2D(这是 '-' 字符 的代码 )的值从10(标点符号)更改为01(大写字母)。 在下面的数组中,这是第四行中的元素,第三行中的元素。

    <CTYPE>
    <地图>
    00
    20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
    20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
    48 10 10 10 10 10 10 10 10 10 10 10 10 0110 10
    84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
    10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01 01
    01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
    10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
    02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
    10 00 10 02 10 10 10 10 10 10 01 10 01 00 01 00
    00 10 10 10 10 10 10 10 10 10 02 10 02 00 02 01
    48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
    10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
    01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
    01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
    02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
    </地图>
    </ CTYPE>
    
  4. 重启服务器。

  5. 要使用新的排序规则,请将其包含在要使用它的列的定义中:

    MySQL的> DROP TABLE IF EXISTS t1;
    查询OK,0行受影响(0.13秒)
    
    MySQL的> CREATE TABLE t1 (
        a TEXT CHARACTER SET latin1 COLLATE latin1_fulltext_ci,
        FULLTEXT INDEX(a)
        ) ENGINE=InnoDB;
    查询正常,0行受影响(0.47秒)
    
  6. 测试排序规则以验证连字符是否被视为单词字符:

    MySQL的> INSERT INTO t1 VALUEs ('----'),('....'),('abcd');
    查询OK,3行受影响(0.22秒)
    记录:3个重复:0个警告:0
    
    MySQL的> SELECT * FROM t1 WHERE MATCH a AGAINST ('----' IN BOOLEAN MODE);
    + ------ +
    | a |
    + ------ +
    | ---- |
    + ------ +
    1排(0.00秒)
    

12.9.8 ngram全文分析器

内置的MySQL全文解析器使用单词之间的空格作为分隔符来确定单词的开始和结束位置,这在使用不使用单词分隔符的表意语言时是一个限制。 为了解决这个限制,MySQL提供了一个支持中文,日文和韩文(CJK)的ngram全文解析器。 ngram全文解析器支持与 InnoDB 一起使用 MyISAM

注意

MySQL还为日语提供了一个MeCab全文解析器插件,它将文档标记为有意义的单词。 有关更多信息,请参见 第12.9.9节“MeCab全文分析器插件”

ngram是 n 来自给定文本序列的 连续 字符序列。 ngram解析器将一系列文本标记为连续的 n 字符 序列 例如,您可以 使用ngram全文解析器将 abcd 标记 为不同的值 n

n = 1:'a','b','c','d'
n = 2:'ab','bc','cd'
n = 3:'abc','bcd'
n = 4:'abcd'

ngram全文解析器是一个内置的服务器插件。 与其他内置服务器插件一样,它在服务器启动时自动加载。

第12.9节“全文搜索功能”中 描述的全文搜索语法 适用于ngram解析器插件。 本节将介绍解析行为的差异。 全文相关的配置选项,除了最小和最大字长选项( innodb_ft_min_token_size innodb_ft_max_token_size ft_min_word_len ft_max_word_len )也适用。

配置ngram令牌大小

ngram解析器的默认ngram标记大小为2(bigram)。 例如,如果令牌大小为2,则ngram解析器将字符串 abc def 解析 为四个令牌: ab bc de ef

ngram标记大小可使用 ngram_token_size 配置选项 进行 配置,该选项的最小值为1,最大值为10。

通常, ngram_token_size 设置为要搜索的最大标记的大小。 如果您只打算搜索单个字符,请设置 ngram_token_size 为1.较小的令牌大小会产生较小的全文搜索索引和较快的搜索。 如果您需要搜索由多个字符组成的单词,请相应地进行设置 ngram_token_size 例如 , “ 生日快乐 生日快乐 简体中国,在 生日 生日 快乐 翻译为 快乐 要搜索这些双字符单词,请设置 ngram_token_size 为2或更高的值。

作为只读变量, ngram_token_size 只能设置为启动字符串或配置文件的一部分:

  • 启动字符串:

    mysqld --ngram_token_size = 2
  • 配置文件:

    的[mysqld]
    ngram_token_size = 2
注意

下面的最小和最大字长配置选项被忽略的 FULLTEXT 是使用NGRAM解析器指标: innodb_ft_min_token_size innodb_ft_max_token_size ft_min_word_len ,和 ft_max_word_len

创建使用ngram解析器的FULLTEXT索引

要创建 FULLTEXT 一个使用NGRAM解析器指数,指定 WITH PARSER ngram CREATE TABLE ALTER TABLE CREATE INDEX

以下示例演示如何使用 ngram FULLTEXT 索引 创建表 ,插入示例数据(简体中文文本)以及在 INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE 表中 查看标记化数据

mysql> USE测试;

mysql> CREATE TABLE文章(
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      title VARCHAR(200),
      主体,
      FULLTEXT(标题,正文)与PARSER ngram
    )ENGINE = InnoDB CHARACTER SET utf8mb4;

mysql> SET NAMES utf8mb4;

INSERT INTO文章(标题,正文)价值观
    ( '数据库管理', '在本教程中我将向你展示如何管理数据库'),
    ( '数据库应用开发', '学习开发数据库应用程序');
    
mysql> SET GLOBAL innodb_ft_aux_table =“test / articles”;

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE ORDER BY doc_id,position;

要向 FULLTEXT 现有表 添加 索引,可以使用 ALTER TABLE CREATE INDEX 例如:

CREATE TABLE文章(
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      title VARCHAR(200),
      主体
     )ENGINE = InnoDB CHARACTER SET utf8;

ALTER TABLE文章ADD FULLTEXT INDEX ft_index(title,body)WITH PARSER ngram;

# 要么:

CREATE FULLTEXT INDEX ft_index ON PARSER ngram上的文章(标题,正文);

ngram Parser空间处理

ngram解析器在解析时消除了空格。 例如:

  • ab cd 被解析为 ab cd

  • a bc 被解析为 bc

ngram分析器停用词处理

内置的MySQL全文解析器将单词与禁用词列表中的条目进行比较。 如果单词等于禁用词列表中的条目,则该单词将从索引中排除。 对于ngram解析器,以不同方式执行停用词处理。 ngram解析器排除 包含 停用词的 令牌,而不是排除等同于禁用词列表中的条目的令牌 例如,假设 ngram_token_size=2 包含 a,b 的文档 被解析为 a ,b 如果逗号( )被定义为停用词,则两者都是 a ,b 从索引中排除,因为它们包含逗号。

默认情况下,ngram解析器使用默认的停用词列表,其中包含英语停用词列表。 对于适用于中文,日文或韩文的禁用词列表,您必须创建自己的。 有关创建 禁用 词列表的信息,请参见 第12.9.4节“全文 停用词

长度大于 ngram_token_size 被忽略的 停用词

ngram Parser术语搜索

对于 自然语言模式 搜索,搜索项将转换为ngram项的并集。 例如,字符串 abc (假设 ngram_token_size=2 )被转换为 ab bc 给定两个文档,一个包含 ab 而另一个包含 abc ,搜索词 ab bc 匹配两个文档。

对于 布尔模式搜索 ,搜索项将转换为ngram短语搜索。 例如,字符串'abc'(假设 ngram_token_size=2 )将转换为' ab bc '。 给定两个文档,一个包含'ab'而另一个包含'abc',搜索短语' ab bc '仅匹配包含'abc'的文档。

ngram Parser通配符搜索

由于 FULLTEXT ngram索引仅包含 ngrams ,并且不包含有关术语开头的信息,因此通配符搜索可能会返回意外结果。 以下行为适用于使用ngram FULLTEXT 搜索索引的 通配符搜索

  • 如果通配符搜索的前缀术语短于ngram令牌大小,则查询将返回包含以前缀术语开头的ngram令牌的所有索引行。 例如,假设 ngram_token_size=2 搜索 a * 将返回以 a 开头的所有行

  • 如果通配符搜索的前缀术语长于ngram令牌大小,则前缀术语将转换为ngram短语,并忽略通配符运算符。 例如,假定 ngram_token_size=2 ,一个 ABC * ” 通配符搜索被转换为 AB BC

ngram Parser短语搜索

短语搜索转换为ngram短语搜索。 例如,搜索短语 abc 被转换为 ab bc ,其返回包含 abc ab bc ”的 文档

搜索短语 abc def 被转换为 ab bc de ef ,其返回包含 abc def ab bc de ef ”的 文档 不返回 包含 abcdef ”的 文档

12.9.9 MeCab全文分析器插件

内置的MySQL全文解析器使用单词之间的空格作为分隔符来确定单词的开始和结束位置,这在使用不使用单词分隔符的表意语言时是一个限制。 为了解决日语的这种限制,MySQL提供了一个MeCab全文解析器插件。 MeCab全文解析器插件支持与 InnoDB 一起使用 MyISAM

注意

MySQL还提供了一个支持日语的ngram全文解析器插件。 有关更多信息,请参见 第12.9.8节“ngram全文分析器”

MeCab全文解析器插件是日语的全文解析器插件,可将一系列文本标记为有意义的单词。 例如,MeCab将 データベース管理 数据库管理 标记 データベース 数据库 )和 管理 管理 )。 相比之下, ngram 全文解析器将文本标记为连续的 n 字符 序列 ,其中 n 表示1到10之间的数字。

除了将文本标记为有意义的单词之外,MeCab索引通常小于ngram索引,并且MeCab全文搜索通常更快。 一个缺点是,与ngram全文解析器相比,MeCab全文本解析器可能需要更长的时间来标记文档。

第12.9节“全文搜索功能”中 描述的全文搜索语法 适用于MeCab解析器插件。 本节将介绍解析行为的差异。 全文相关的配置选项也适用。

有关MeCab解析器的其他信息,请参阅 Github上 MeCab:Yet Another Speech-of-Speech和Morphological Analyzer 项目。

安装MeCab Parser插件

MeCab解析器插件需要 mecab mecab-ipadic

在受支持的Fedora,Debian和Ubuntu平台上(系统 mecab 版本太旧的 Ubuntu 12.04除外 ), mecab 如果安装到默认位置 ,MySQL会动态链接到系统 安装。 在其他受支持的类Unix平台上, libmecab.so 静态链接 libpluginmecab.so ,位于MySQL插件目录中。 mecab-ipadic 包含在MySQL二进制文件中,位于 MYSQL_HOME\lib\mecab

您可以安装 mecab mecab-ipadic 使用本机包管理实用程序(在Fedora,Debian和Ubuntu上),也可以 从源代码 构建 mecab mecab-ipadic 使用。 有关安装 mecab mecab-ipadic 使用本机程序包管理实用程序的信息,请参阅 从二进制分发安装MeCab(可选) 如果要构建 mecab mecab-ipadic 从源 构建 ,请参阅从源 构建MeCab(可选)

在Windows上, libmecab.dll 可以在MySQL bin 目录中 找到 mecab-ipadic 位于 MYSQL_HOME/lib/mecab

要安装和配置MeCab解析器插件,请执行以下步骤:

  1. 在MySQL配置文件中,将 mecab_rc_file 配置选项 设置为配置文件 的位置,该 mecabrc 文件是MeCab的配置文件。 如果您使用的是随MySQL分发的MeCab软件包,则该 mecabrc 文件位于 MYSQL_HOME/lib/mecab/etc/

    的[mysqld]
    松mecabrc文件= MYSQL_HOME / LIB /仲裁处的/ etc / mecabrc

    loose 前缀是一个 选项修改 mecab_rc_file 安装MeCaB解析器插件之前,MySQL无法识别 选项,但必须在尝试安装MeCaB解析器插件之前设置该选项。 loose 前缀允许你重启MySQL没有遇到错误的,由于无法识别的变量。

    如果您使用自己的MeCab安装,或者从源构建MeCab,则 mecabrc 配置文件 的位置 可能会有所不同。

    有关MySQL配置文件及其位置的信息,请参见 第4.2.2.2节“使用选项文件”

  2. 同样在MySQL配置文件中,将最小令牌大小设置为1或2,这是建议与MeCab解析器一起使用的值。 对于 InnoDB 表,最小令牌大小由 innodb_ft_min_token_size 配置选项 定义 ,其默认值为3.对于 MyISAM 表,最小令牌大小由定义 ft_min_word_len ,其默认值为4。

    的[mysqld]
    innodb_ft_min_token_size = 1
  3. 修改 mecabrc 配置文件以指定要使用的字典。 mecab-ipadic 与MySQL二进制分布包包括三个字典( ipadic_euc-jp ipadic_sjis ,和 ipadic_utf-8 )。 mecabrc 与MySQL一起打包 配置文件包含和输入类似于以下内容:

    dicdir = / path / to / mysql / lib / mecab / lib / mecab / dic / ipadic_euc-jp

    ipadic_utf-8 例如, 要使用 字典,请按如下所示修改条目:

    dicdir = MYSQL_HOME/ lib / mecab / dic / ipadic_utf-8

    如果您使用自己的MeCab安装或从源代码构建了MeCab dicdir ,则 mecabrc 文件中 的默认 条目 将不同,字典及其位置也将不同。

    注意

    安装MeCab解析器插件后,您可以使用 mecab_charset 状态变量来查看与MeCab一起使用的字符集。 MySQL二进制文件提供的三个MeCab词典支持以下字符集。

    • ipadic_euc-jp 词典支持 ujis eucjpms 字符集。

    • ipadic_sjis 词典支持 sjis cp932 字符集。

    • ipadic_utf-8 词典支持 utf8 utf8mb4 字符集。

    mecab_charset 仅报告第一个支持的字符集。 例如, ipadic_utf-8 字典支持 utf8 utf8mb4 mecab_charset 始终报告 utf8 何时使用此词典。

  4. 重启MySQL。

  5. 安装MeCab解析器插件:

    MeCab解析器插件使用 INSTALL PLUGIN 语法 安装 插件名称是 mecab ,共享库名称是 libpluginmecab.so 有关安装插件的其他信息,请参见 第5.6.1节“安装和卸载插件”

    INSTALL PLUGIN mecab SONAME'libpluginmecab.so';
    

    安装完成后,MeCab解析器插件会在每次正常的MySQL重启时加载。

  6. 验证是否使用该 SHOW PLUGINS 语句 加载了MeCab解析器插件

    mysql> SHOW PLUGINS;

    一个 mecab 插件应该出现在插件列表。

创建使用MeCab Parser的FULLTEXT索引

要创建 FULLTEXT 一个使用仲裁处解析器指数,指定 WITH PARSER ngram CREATE TABLE ALTER TABLE CREATE INDEX

此示例演示如何创建带有 mecab FULLTEXT 索引 的表 ,插入示例数据以及在 INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE 表中 查看标记化数据

mysql> USE测试;

mysql> CREATE TABLE文章(
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      title VARCHAR(200),
      主体,
      FULLTEXT(标题,正文)与PARSER mecab
    )ENGINE = InnoDB CHARACTER SET utf8;

mysql> SET NAMES utf8;
    
mysql> INSERT INTO文章(标题,正文)VALUES
    ( 'データベース管理', 'このチュートリアルでは,私はどのようにデータベースを管理する方法を绍介します'),
    ( 'データベースアプリケーション开発', 'データベースアプリケーションを开発することを学ぶ');

mysql> SET GLOBAL innodb_ft_aux_table =“test / articles”;

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE ORDER BY doc_id,position;

要向 FULLTEXT 现有表 添加 索引,可以使用 ALTER TABLE CREATE INDEX 例如:

CREATE TABLE文章(
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      title VARCHAR(200),
      主体
     )ENGINE = InnoDB CHARACTER SET utf8;

ALTER TABLE文章ADD FULLTEXT INDEX ft_index(标题,正文)WITH PARSER mecab;

# 要么:

CREATE FULLTEXT INDEX ft_index ON PARSER mecab上的文章(标题,正文);

MeCab Parser空间处理

MeCab解析器在查询字符串中使用空格作为分隔符。 例如,MeCab解析器将 データベース管理 标记 データベース 管理

MeCab Parser Stopword处理

默认情况下,MeCab解析器使用默认的停用词列表,其中包含一个简短的英语停用词列表。 对于适用于日语的禁用词列表,您必须创建自己的。 有关创建 禁用 词列表的信息,请参见 第12.9.4节“全文 停用词

MeCab Parser术语搜索

对于自然语言模式搜索,搜索项将转换为标记的并集。 例如, データベース管理 被转换为 データベース管理

SELECT COUNT(*)FROM articles WHERE MATCH(title,body)AGAINST('データベース管理'IN NATURAL LANGUAGE MODE);

对于布尔模式搜索,搜索词将转换为搜索词组。 例如, データベース管理 被转换为 データベース管理

SELECT COUNT(*)FROM articles WHERE MATCH(title,body)AGAINST('データベース管理'在BOOLEAN MODE中);

MeCab Parser通配符搜索

通配符搜索词不是标记化的。 搜索 データベース管理* 是在前缀 データベース管理上进行的

SELECT COUNT(*)FROM articles WHERE MATCH(title,body)AGAINST('データベース*'在BOOLEAN MODE中);

MeCab Parser短语搜索

短语被标记化。 例如, データベース管理 被标记为 データベース管理

SELECT COUNT(*)FROM articles WHERE MATCH(title,body)AGAINST('データベース管理''在BOOLEAN MODE中);

从二进制分发安装MeCab(可选)

本节介绍如何 使用本机程序包管理实用程序 安装 mecab mecab-ipadic 使用二进制分发。 例如,在Fedora上,您可以使用Yum来执行安装:

yum mecab-devel

在Debian或Ubuntu上,您可以执行APT安装:

apt-get install mecab
apt-get install mecab-ipadic

从源安装MeCab(可选)

如果你想建立 mecab mecab-ipadic 从源代码,下面提供了基本安装步骤。 有关其他信息,请参阅MeCab文档。

  1. 下载的tar.gz包 mecab ,并 mecab-ipadic http://taku910.github.io/mecab/#download 截至2016年2月,最新的套餐是 mecab-0.996.tar.gz mecab-ipadic-2.7.0-20070801.tar.gz

  2. 安装 mecab

    tar zxfv mecab-0.996.tar
    cd mecab-0.996
    。/配置
    使
    做检查
    make install
  3. 安装 mecab-ipadic

    tar zxfv mecab-ipadic-2.7.0-20070801.tar
    cd mecab-ipadic-2.7.0-20070801
    。/配置
    使
    make install
  4. 使用 WITH_MECAB CMake选项 编译MySQL 如果已安装 则将 WITH_MECAB 选项 设置为 默认位置。 system mecab mecab-ipadic

    -DWITH_MECAB =系统

    如果定义了自定义安装目录,请设置 WITH_MECAB 为自定义目录。 例如:

    -DWITH_MECAB = /路径/到/仲裁处

12.10演员函数和运算符

表12.14强制转换函数和运算符

名称 描述
BINARY 将字符串转换为二进制字符串
CAST() 将值转换为特定类型
CONVERT() 将值转换为特定类型

转换函数和运算符可以将值从一种数据类型转换为另一种数据类型。

CONVERT() with USING 子句提供了一种在不同字符集之间转换数据的方法:

转换(expr使用transcoding_name

在MySQL中,转码名称与相应的字符集名称相同。

例子:

SELECT CONVERT(_latin1'Müller'使用utf8);
INSERT INTO utf8_table(utf8_column)
    SELECT CONVERT(latin1_column USING utf8)FROM latin1_table;

您也可以 CONVERT() 使用 USING CAST() 在不同字符集之间转换字符串:

CONVERT(string,CHAR [(N)] CHARACTER SET charset_name
CAST(stringAS CHAR [(N)] CHARACTER SET charset_name

例子:

SELECT CONVERT('test',CHAR CHARACTER SET utf8);
SELECT CAST('test'AS CHAR CHARACTER SET utf8);

如果指定 刚刚显示,则生成的字符集和排序规则是 默认排序规则 如果省略 ,结果字符集和校对规则由定义 决定默认的连接字符集和校对系统变量(参见 第10.4节,“连接字符集和校对” )。 CHARACTER SET charset_name charset_name charset_name CHARACTER SET charset_name character_set_connection collation_connection

COLLATE a CONVERT() CAST() call中 不允许 使用 子句 ,但可以将其应用于函数结果。 例如,这是合法的:

SELECT CAST('test'AS CHAR CHARACTER SET utf8)COLLATE utf8_bin;

但这是非法的:

SELECT CAST('test'AS CHAR CHARACTER SET utf8 COLLATE utf8_bin);

通常,您不能以不 BLOB 区分大小写的方式 比较 值或其他二进制字符串,因为二进制字符串使用的 binary 字符集 字母集的概念没有排序。 要执行不区分大小写的比较,请使用 CONVERT() CAST() 函数将值转换为非二进制字符串。 比较结果字符串使用其排序规则。 例如,如果转换结果字符集具有不区分大小写的排序规则,则 LIKE 操作不区分大小写:

SELECT'A' LIKE CONVERT(blob_col使用latin1)
  来自tbl_name;

要使用其他字符集,请 latin1 在前面的语句中 替换其名称 要为转换后的字符串指定特定排序规则,请 COLLATE CONVERT() 调用后 使用 子句

选择'A'LIKE CONVERT(blob_col使用latin1)COLLATE latin1_german1_ci
  来自tbl_name;

CONVERT() 并且 CAST() 可以更普遍地用于比较以不同字符集表示的字符串。 例如,这些字符串的比较会导致错误,因为它们具有不同的字符集:

mysql> SET @s1 = _latin1 'abc', @s2 = _latin2 'abc';
mysql>SELECT @s1 = @s2;
ERROR 1267(HY000):非法混合排序(latin1_swedish_ci,IMPLICIT)
和(latin2_general_ci,IMPLICIT)用于操作'='

将其中一个字符串转换为与另一个字符集兼容的字符集可以使比较无错误地发生:

MySQL的> SELECT @s1 = CONVERT(@s2 USING latin1);
+ --------------------------------- +
| @ s1 = CONVERT(@ s2使用latin1)|
+ --------------------------------- +
| 1 |
+ --------------------------------- +

为字符串常量,另一种方式来指定字符集是使用字符集导引器( _latin1 _latin2 前面的例子中是导引器的实例)。 与转换函数(例如 CAST() ,或 CONVERT() 将字符串从一个字符集转换为另一个字符集)不同,介绍人将字符串文字指定为具有特定字符集,不涉及转换。 有关更多信息,请参见 第10.3.8节“字符集介绍”

字符集转换在二进制字符串的字母转换之前也很有用。 LOWER() UPPER() 当直接应用到二进制字符串,因为大小写的概念不适是无效的。 要执行二进制字符串的字母转换,首先将其转换为非二进制字符串:

mysql> SET @str = BINARY 'New York';
mysql>SELECT LOWER(@str), LOWER(CONVERT(@str USING utf8mb4));
+ ------------- + ----------------------------------- -  +
| LOWER(@str)| LOWER(CONVERT(@str使用utf8mb4))|
+ ------------- + ----------------------------------- -  +
| 纽约| 纽约|
+ ------------- + ----------------------------------- -  +

如果使用 BINARY CAST() 转换索引列 CONVERT() ,则MySQL可能无法有效地使用索引。

转换函数对于在 CREATE TABLE ... SELECT 语句中 创建具有特定类型的列非常有用


mysql> CREATE TABLE new_table SELECT CAST('2000-01-01' AS DATE) AS c1;
mysql>SHOW CREATE TABLE new_table\G
*************************** 1。排******************** *******
       表:new_table
创建表:CREATE TABLE`new_table`(
  `c1`日期DEFAULT NULL
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4

强制转换函数可用于按 ENUM 词汇顺序 进行排序 通常, ENUM 使用内部数值 列进行 排序 将值转换 CHAR 为词汇排序的结果:

选择enum_col来自tbl_nameCAST的订单(enum_col作为CHAR);

CAST() 如果您将其用作更复杂表达式的一部分,也会更改结果,例如 CONCAT('Date: ',CAST(NOW() AS DATE))

对于时间值,几乎不需要使用 CAST() 以不同格式提取数据。 相反,使用功能,例如 EXTRACT() DATE_FORMAT() TIME_FORMAT() 请参见 第12.7节“日期和时间函数”

要将字符串转换为数字,除了在数字上下文中使用字符串值之外,通常只需要执行任何操作:

MySQL的> SELECT 1+'1';
       - > 2

对于十六进制和位文字也是如此,默认情况下是二进制字符串:

MySQL的> SELECT X'41', X'41'+0;
        - >'A',65
MySQL的> SELECT b'1100001', b'1100001'+0;
        - >'a',97

算术运算中使用的字符串在表达式求值期间转换为浮点数。

字符串上下文中使用的数字将转换为字符串:

MySQL的> SELECT CONCAT('hello you ',2);
        - >'你好2'

有关将数字隐式转换为字符串的信息,请参见 第12.2节“表达式 求值中的 类型转换”

MySQL支持带有符号和无符号64位值的算术。 对于 其中一个操作数是无符号整数的 数字运算符(例如 + - ),默认情况下结果是无符号的(参见 第12.6.1节“算术运算符” )。 要覆盖它,请使用 SIGNED or UNSIGNED cast运算符分别将值转换为有符号或无符号的64位整数。

MySQL的> SELECT 1 - 2;
        - > -1
MySQL的> SELECT CAST(1 - 2 AS UNSIGNED);
        - > 18446744073709551615
MySQL的> SELECT CAST(CAST(1 - 2 AS UNSIGNED) AS SIGNED);
        - > -1

如果任一操作数是浮点值,则结果为浮点值,并且不受前述规则的影响。 (在此上下文中, DECIMAL 列值被视为浮点值。)

MySQL的> SELECT CAST(1 AS UNSIGNED) - 2.0;
        - > -1.0

SQL模式会影响转换操作的结果(请参见 第5.1.11节“服务器SQL模式” )。 例子:

  • 用于将 日期字符串转换为日期, CONVERT() 启用S​​QL模式 CAST() 返回 NULL 并生成警告 NO_ZERO_DATE

  • 对于整数减法,如果 NO_UNSIGNED_SUBTRACTION 启用 SQL模式,即使任何操作数未签名,也会对减法结果进行签名。

以下列表描述了可用的强制转换函数和运算符:

  • BINARY expr

    BINARY 操作者将所表达为二进制字符串。 一种常见的用法 BINARY 是强制字符串比较逐字节而不是逐字符地完成,实际上变为区分大小写。 BINARY 运营商还导致比较尾随空格是显著。

    MySQL的> SELECT 'a' = 'A';
            - > 1
    MySQL的> SELECT BINARY 'a' = 'A';
            - > 0
    MySQL的> SELECT 'a' = 'a ';
            - > 1
    MySQL的> SELECT BINARY 'a' = 'a ';
            - > 0
    

    相比之下, BINARY 影响整个操作; 它可以在任一操作数之前给出,但结果相同。

    为了将字符串表达式转换为二进制字符串,这些结构是等效的:

    二元expr
    铸造(expr作为二进制)
    CONVERT(expr使用二进制)
    

    如果值是字符串文字,则可以将其指定为二进制字符串,而不使用 _binary 字符集介绍器 执行任何转换

    MySQL的> SELECT 'a' = 'A';
            - > 1
    MySQL的> SELECT _binary 'a' = 'A';
            - > 0
    

    有关介绍人的信息,请参见 第10.3.8节“字符集介绍人”

    BINARY 表达式中 运算符与 BINARY 字符列定义中 属性的 效果不同 使用该 BINARY 属性 定义的字符列将 分配表默认字符集和该字符集的binary( _bin )排序规则。 每个非二进制字符集都有一个 _bin 排序规则。 例如, utf8 字符集 的二进制排序规则 utf8_bin ,因此如果表默认字符集是 utf8 ,则这两个列定义是等效的:

    CHAR(10)二进制
    CHAR(10)CHARACTER SET utf8 COLLATE utf8_bin
    

    使用 CHARACTER SET binary 中的定义 CHAR VARCHAR TEXT 柱导致列与相应的二进制字符串的数据类型进行处理。 例如,以下两对定义是等效的:

    CHAR(10)CHARACTER SET二进制
    BINARY(10)
    
    VARCHAR(10)CHARACTER SET二进制
    VARBINARY(10)
    
    TEXT CHARACTER SET二进制
    BLOB
    
  • CAST(expr AS type)

    CAST() 函数接受任何类型的表达式并生成指定类型的结果值,类似于 CONVERT() 有关更多信息,请参阅的说明 CONVERT()

    CAST() 是标准的SQL语法。

  • CONVERT(expr,type) CONVERT(expr USING transcoding_name)

    CONVERT() 函数采用任何类型的表达式并生成指定类型的结果值。

    这里 语法的 讨论 也适用于 ,这是等价的。 CONVERT(expr, type) CAST(expr AS type)

    CONVERT(... USING ...) 是标准的SQL语法。 ODBC USING 形式的 形式 CONVERT()

    CONVERT() USING 不同的字符集之间转换数据。 在MySQL中,转码名称与相应的字符集名称相同。 例如,此语句将 'abc' 默认字符集中 的字符串转换为 字符集中的相应字符串 utf8

    SELECT CONVERT('abc'使用utf8);
    

    CONVERT() 不带 USING CAST() 使用表达式和 type 指定结果类型 值。 type 允许 这些 值:

    • BINARY[(N)]

      生成具有 BINARY 数据类型 的字符串 有关 如何影响比较的说明, 请参见 第11.4.2节“BINARY和VARBINARY类型” 如果 N 给出 了可选长度 ,则 会使强制转换使用不超过 参数的字节。 短于 字节的 字节 填充 到长度为 BINARY(N) N N 0x00 N

    • CHAR[(N)] [charset_info]

      生成具有 CHAR 数据类型 的字符串 如果 N 给出 了可选长度 ,则 会使强制转换使用不超过 参数的字符。 对于短于 字符的 值,不会出现填充 CHAR(N) N N

      如果没有 charset_info 子句,则 CHAR 生成具有默认字符集的字符串。 要明确指定字符集, charset_info 允许使用 以下 值:

      • CHARACTER SET charset_name :生成具有给定字符集的字符串。

      • ASCII :简写 CHARACTER SET latin1

      • UNICODE :简写 CHARACTER SET ucs2

      在所有情况下,字符串都具有字符集的默认排序规则。

    • DATE

      产生 DATE 价值。

    • DATETIME

      产生 DATETIME 价值。

    • DECIMAL[(M[,D])]

      产生 DECIMAL 价值。 如果给出了可选 M D 值,则它们指定最大位数(精度)和小数点后面的位数(刻度)。

    • DOUBLE

      产生 DOUBLE 结果。 在MySQL 8.0.17中添加。

    • FLOAT [( P )]

      如果 P 未指定 precision ,则生成类型的结果 FLOAT 如果 P 提供并且0 <= << P = 24,则结果为类型 FLOAT 如果25 <= P <= 53,则结果为类型 REAL 如果 P <0或 P > 53,则返回错误。 在MySQL 8.0.17中添加。

    • JSON

      产生 JSON 价值。 有关在 JSON 其他类型 之间转换值的规则的详细信息 ,请参阅 JSON值的比较和排序

    • NCHAR[(N)]

      喜欢 CHAR ,但会产生一个带有国家字符集的字符串。 请参见 第10.3.7节“国家字符集”

      与之 不同 CHAR NCHAR 不允许指定尾随字符集信息。

    • REAL

      生成类型的结果 REAL 这实际上是 FLOAT ,如果 REAL_AS_FLOAT 启用了SQL模式; 否则结果是类型 DOUBLE

    • SIGNED [INTEGER]

      生成有符号整数值。

    • TIME

      产生 TIME 价值。

    • UNSIGNED [INTEGER]

      生成无符号整数值。

12.11 XML函数

表12.15 XML函数

名称 描述
ExtractValue() 使用XPath表示法从XML字符串中提取值
UpdateXML() 返回替换的XML片段

本节讨论MySQL中的XML和相关功能。

注意

通过使用该 选项 调用它们, 可以 mysql mysqldump 客户端中 从MySQL获取XML格式的输出 --xml 请参见 第4.5.1节“ mysql - MySQL命令行客户端” 第4.5.4节“ mysqldump - 数据库备份程序”

提供了两个提供基本XPath 1.0(XML路径语言,版本1.0)功能的函数。 本节稍后将提供有关XPath语法和用法的一些基本信息; 但是,对这些主题的深入讨论超出了本手册的范围,您应该参考 XML Path Language(XPath)1.0标准 来获取确切的信息。 对于那些 刚接触XPath 或希望了解基础知识的人来说,一个有用的资源是 Zvon.org XPath教程 ,它有多种语言版本。

注意

这些功能仍处于开发阶段。 我们将继续改进MySQL 8.0及更高版本中XML和XPath功能的这些和其他方面。 您可以在 MySQL XML用户论坛中 讨论这些内容,询问有关它们的问题,并从中获得其他用户的帮助

与这些函数一起使用的XPath表达式支持用户变量和本地存储的程序变量。 用户变量检查不足; 强烈检查存储程序本地的变量(另见Bug#26518):

  • 用户变量(弱检查)。  不检查 使用语法的变量 (即用户变量)。 如果变量类型错误或之前未分配值,则服务器不会发出警告或错误。 这也意味着用户对任何印刷错误负全部责任,因为如果(例如) 预期的 地方使用, 不会发出警告 $@variable_name $@myvariable $@myvariable

    例:

    MySQL的> SET @xml = '<a><b>X</b><b>Y</b></a>';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SET @i =1, @j = 2;
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @i, ExtractValue(@xml, '//b[$@i]');
    + ------ + -------------------------------- +
    | @i | ExtractValue(@xml,'// b [$ @ i]')|
    + ------ + -------------------------------- +
    | 1 | X |
    + ------ + -------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT @j, ExtractValue(@xml, '//b[$@j]');
    + ------ + -------------------------------- +
    | @j | ExtractValue(@xml,'// b [$ @ j]')|
    + ------ + -------------------------------- +
    | 2 | Y |
    + ------ + -------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT @k, ExtractValue(@xml, '//b[$@k]');
    + ------ + -------------------------------- +
    | @k | ExtractValue(@xml,'// b [$ @ k]')|
    + ------ + -------------------------------- +
    | NULL | |
    + ------ + -------------------------------- +
    1排(0.00秒)
    
  • 存储程序中的变量(强检查)。  使用语法的变量 可以在存储程序中调用时声明并与这些函数一起使用。 这些变量对于定义它们的存储程序是本地的,并且强烈检查类型和值。 $variable_name

    例:

    MySQL的> DELIMITER |
    
    mysql> CREATE PROCEDURE myproc ()
        - > BEGIN
        - >    DECLARE i INT DEFAULT 1;
        - >   DECLARE xml VARCHAR(25) DEFAULT '<a>X</a><a>Y</a><a>Z</a>';
        - >
        - >    WHILE i < 4 DO
        - >      SELECT xml, i, ExtractValue(xml, '//a[$i]');
        - >      SET i = i+1;
        - >    END WHILE;
        - >END |
    查询OK,0行受影响(0.01秒)
    
    MySQL的> DELIMITER ;
    
    MySQL的> CALL myproc();
    + -------------------------- + --- + ------------------ ------------ +
    | xml | 我| ExtractValue(xml,'// a [$ i]')|
    + -------------------------- + --- + ------------------ ------------ +
    | <a> X </a> <a> Y </a> <a> Z </a> | 1 | X |
    + -------------------------- + --- + ------------------ ------------ +
    1排(0.00秒)
    
    + -------------------------- + --- + ------------------ ------------ +
    | xml | 我| ExtractValue(xml,'// a [$ i]')|
    + -------------------------- + --- + ------------------ ------------ +
    | <a> X </a> <a> Y </a> <a> Z </a> | 2 | Y |
    + -------------------------- + --- + ------------------ ------------ +
    1排(0.01秒)
    
    + -------------------------- + --- + ------------------ ------------ +
    | xml | 我| ExtractValue(xml,'// a [$ i]')|
    + -------------------------- + --- + ------------------ ------------ +
    | <a> X </a> <a> Y </a> <a> Z </a> | 3 | Z |
    + -------------------------- + --- + ------------------ ------------ +
    1排(0.01秒)
    

    参数。  在作为参数传入的存储例程中的XPath表达式中使用的变量也需要进行强检查。

包含用户变量或存储程序本地变量的表达式必须另外(符号除外)符合包含XPath 1.0规范中给出的变量的XPath表达式的规则。

注意

用于存储XPath表达式的用户变量被视为空字符串。 因此,无法将XPath表达式存储为用户变量。 (Bug#32911)

  • ExtractValue(xml_frag, xpath_expr)

    ExtractValue() 接受两个字符串参数,一个XML标记片段 xml_frag 和一个XPath表达式 xpath_expr (也称为 定位器 ); 它返回 CDATA 第一个文本节点 的text( ),该节点是XPath表达式匹配的元素的子元素。

    使用此功能相当于使用 xpath_expr 后添加 执行匹配 /text() 换句话说, ExtractValue('<a><b>Sakila</b></a>', '/a/b') ExtractValue('<a><b>Sakila</b></a>', '/a/b/text()') 产生相同的结果。

    如果找到多个匹配,则返回每个匹配元素的第一个子文本节点的内容(按照匹配的顺序)作为单个空格分隔的字符串。

    如果没有为表达式找到匹配的文本节点(包括隐式 /text() ) - 无论 出于 何种原因,只要 xpath_expr 有效,并且 xml_frag 由正确嵌套和关闭的元素组成 - 返回空字符串。 没有区分空元素的匹配和根本没有匹配。 这是设计的。

    如果您需要确定是否未找到匹配元素 xml_frag 找到 此类元素但未包含子文本节点,则应测试使用XPath count() 函数 的表达式的结果 例如,这两个语句都返回一个空字符串,如下所示:

    MySQL的> SELECT ExtractValue('<a><b/></a>', '/a/b');
    + ------------------------------- +
    | ExtractValue('<a> <b /> </a>','/ a / b')|
    + ------------------------------- +
    | |
    + ------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT ExtractValue('<a><c/></a>', '/a/b');
    + ------------------------------- +
    | ExtractValue('<a> <c /> </a>','/ a / b')|
    + ------------------------------- +
    | |
    + ------------------------------- +
    1排(0.00秒)
    

    但是,您可以使用以下内容确定是否确实存在匹配元素:

    MySQL的> SELECT ExtractValue('<a><b/></a>', 'count(/a/b)');
    + ------------------------------- +
    | ExtractValue('<a> <b /> </a>','count(/ a / b)')|
    + ------------------------------- +
    | 1 |
    + ------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT ExtractValue('<a><c/></a>', 'count(/a/b)');
    + ------------------------------- +
    | ExtractValue('<a> <c /> </a>','count(/ a / b)')|
    + ------------------------------- +
    | 0 |
    + ------------------------------- +
    1排(0.01秒)
    
    重要

    ExtractValue() 仅返回 CDATA ,并且不返回可能包含在匹配标记内的任何标记,也不返回任何内容(请参阅 val1 以下示例中 返回的结果 )。

    mysql> SELECT
        - >   ExtractValue('<a>ccc<b>ddd</b></a>', '/a') AS val1,
        - >   ExtractValue('<a>ccc<b>ddd</b></a>', '/a/b') AS val2,
        - >   ExtractValue('<a>ccc<b>ddd</b></a>', '//b') AS val3,
        - >   ExtractValue('<a>ccc<b>ddd</b></a>', '/b') AS val4,
        - >  ExtractValue('<a>ccc<b>ddd</b><b>eee</b></a>', '//b') AS val5;
    
    + ------ + ------ + ------ + ------ + --------- +
    | val1 | val2 | val3 | val4 | val5 |
    + ------ + ------ + ------ + ------ + --------- +
    | ccc | ddd | ddd | | ddd eee |
    + ------ + ------ + ------ + ------ + --------- +
    

    此函数使用当前的SQL排序规则进行比较 contains() ,执行与其他字符串函数(例如 CONCAT() 相同的排序规则聚合 ,同时考虑其参数的排序规则的强制性; 有关此行为的规则的说明, 请参见 第10.8.4节“表达式中的校对强制性”

    (以前,二进制 - 即始终使用区分大小写的比较。)

    NULL 如果 xml_frag 包含未正确嵌套或关闭的元素,则会 返回 ,并生成警告,如下例所示:

    MySQL的> SELECT ExtractValue('<a>c</a><b', '//a');
    + ----------------------------------- +
    | ExtractValue('<a> c </a> <b','// a')|
    + ----------------------------------- +
    | NULL |
    + ----------------------------------- +
    1排,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS\G
    *************************** 1。排******************** *******
      等级:警告
       代码:1525
    消息:XML值不正确:'第1行pos 11处的解析错误:
             END-OF-INPUT意外('>'想要''
    1排(0.00秒)
    
    MySQL的> SELECT ExtractValue('<a>c</a><b/>', '//a');
    + ------------------------------- +
    | ExtractValue('<a> c </a> <b />','// a')|
    + ------------------------------- +
    | c |
    + ------------------------------- +
    1排(0.00秒)
    
  • UpdateXML(xml_target, xpath_expr, new_xml)

    此函数将XML标记的给定片段的单个部分替换为 xml_target 新的XML片段 new_xml ,然后返回更改的XML。 xml_target 替换 的部分 xpath_expr 用户提供 的XPath表达式匹配

    如果未 xpath_expr 找到 表达式匹配 ,或者找到多个匹配项,则该函数返回原始 xml_target XML片段。 所有三个参数都应该是字符串。

    mysql> SELECT
        - >   UpdateXML('<a><b>ccc</b><d></d></a>', '/a', '<e>fff</e>') AS val1,
        - >   UpdateXML('<a><b>ccc</b><d></d></a>', '/b', '<e>fff</e>') AS val2,
        - >   UpdateXML('<a><b>ccc</b><d></d></a>', '//b', '<e>fff</e>') AS val3,
        - >   UpdateXML('<a><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val4,
        - >   UpdateXML('<a><d></d><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val5
        - >\G
    
    *************************** 1。排******************** *******
    val1:<e> fff </ e>
    val2:<a> <b> ccc </ b> <d> </ d> </a>
    val3:<a> <e> fff </ e> <d> </ d> </a>
    val4:<a> <b> ccc </ b> <e> fff </ e> </a>
    val5:<a> <d> </ d> <b> ccc </ b> <d> </ d> </a>
    
注意

深入讨论XPath语法和用法超出了本手册的范围。 有关确切信息, 请参阅 XML Path Language(XPath)1.0规范 对于那些 刚接触XPath 或希望重新学习基础知识的人来说,一个有用的资源是 Zvon.org XPath教程 ,该 教程 有多种语言版本。

一些基本XPath表达式的描述和示例如下:

  • /tag

    匹配 if和仅 匹配 根元素。 <tag/> <tag/>

    示例: /a 匹配, <a><b/></a> 因为它匹配最外层(根)标记。 它与内部 a 元素 不匹配 <b><a/></b> 因为在这个实例中它是另一个元素的子元素。

  • /tag1/tag2

    当且仅当它是子 元素 时才 匹配 ,并且 是根元素。 <tag2/> <tag1/> <tag1/>

    示例: /a/b 匹配 b XML片段 中的 元素, <a><b/></a> 因为它是根元素的子元素 a 它没有匹配, <b><a/></b> 因为在这种情况下, b 是根元素(因此没有其他元素的子元素)。 XPath表达式也没有匹配 <a><c><b/></c></a> ; 在这里, b 是一个后代 a ,但实际上并不是一个孩子 a

    该构造可扩展到三个或更多个元素。 例如,XPath表达式 /a/b/c 匹配 c 片段 中的 元素 <a><b><c/></b></a>

  • //tag

    匹配任何实例 <tag>

    示例: //a 匹配 a 以下任何一项 中的 元素: <a><b><c/></b></a> ; <c><a><b/></a></b> ; <c><b><a/></b></c>

    // 可以结合使用 / 例如, //a/b 匹配 b 任一片段 中的 元素 <a><b/></a> <c><a><b/></a></c>

    注意

    //tag 相当于 一个常见的错误是将此与此混淆 ,尽管后一种表达式实际上可能导致非常不同的结果,如下所示: /descendant-or-self::*/tag /descendant-or-self::tag

    MySQL的> SET @xml = '<a><b><c>w</c><b>x</b><d>y</d>z</b></a>';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @xml;
    + ----------------------------------------- +
    | @xml |
    + ----------------------------------------- +
    | <a> <b> <c> w </ c> <b> x </ b> <d> y </ d> z </ b> </a> |
    + ----------------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT ExtractValue(@xml, '//b[1]');
    + ------------------------------ +
    | ExtractValue(@xml,'// b [1]')|
    + ------------------------------ +
    | xz |
    + ------------------------------ +
    1排(0.00秒)
    
    MySQL的> SELECT ExtractValue(@xml, '//b[2]');
    + ------------------------------ +
    | ExtractValue(@xml,'// b [2]')|
    + ------------------------------ +
    | |
    + ------------------------------ +
    1排(0.01秒)
    
    MySQL的> SELECT ExtractValue(@xml, '/descendant-or-self::*/b[1]');
    + ------------------------------------------------- -  +
    | ExtractValue(@xml,'/ descendant-or-self :: * / b [1]')|
    + ------------------------------------------------- -  +
    | xz |
    + ------------------------------------------------- -  +
    1排(0.06秒)
    
    MySQL的> SELECT ExtractValue(@xml, '/descendant-or-self::*/b[2]');
    + ------------------------------------------------- -  +
    | ExtractValue(@xml,'/ descendant-or-self :: * / b [2]')|
    + ------------------------------------------------- -  +
    | |
    + ------------------------------------------------- -  +
    1排(0.00秒)
    
    
    MySQL的> SELECT ExtractValue(@xml, '/descendant-or-self::b[1]');
    + ------------------------------------------------- +
    | ExtractValue(@xml,'/ descendant-or-self :: b [1]')|
    + ------------------------------------------------- +
    | z |
    + ------------------------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT ExtractValue(@xml, '/descendant-or-self::b[2]');
    + ------------------------------------------------- +
    | ExtractValue(@xml,'/ descendant-or-self :: b [2]')|
    + ------------------------------------------------- +
    | x |
    + ------------------------------------------------- +
    1排(0.00秒)
    
  • * 操作者充当 通配符 的任何元素相匹配。 例如,表达式 /*/b 匹配 b 任一XML片段 中的 元素 <a><b/></a> <c><b/></c> 但是,表达式不会在片段中产生匹配, <b><a/></b> 因为它 b 必须是某个其他元素的子元素。 通配符可以在任何位置使用:表达式 /*/b/* 将匹配 b 本身不是根元素 元素的 任何子 元素。

  • 您可以使用 | UNION )运算符 匹配任何几个定位器 例如,表达式 //b|//c 匹配 XML目标 中的所有 元素 b c 元素。

  • 还可以基于其一个或多个属性的值来匹配元素。 这是使用语法完成的 例如,表达式 匹配 片段 中的第二个 元素 要匹配 任何 元素 ,请使用XPath表达式 tag[@attribute="value"] //b[@id="idB"] b <a><b id="idA"/><c/><b id="idB"/></a> attribute="value" //*[attribute="value"]

    要过滤多个属性值,只需连续使用多个属性比较子句。 例如,表达式 //b[@c="x"][@d="y"] 匹配 <b c="x" d="y"/> 给定XML片段中任何位置出现 的元素

    要查找相同属性与多个值中的任何一个匹配的元素,可以使用 | 运算 符连接的多个定位 符。 例如,要匹配 b c 属性具有值23或17的 所有 元素 ,请使用表达式 //b[@c="23"]|//b[@c="17"] 您也可以使用逻辑 or 运算符来实现此目的: //b[@c="23" or @c="17"]

    注意

    or 和/ 之间的区别 | or 连接条件,同时 | 连接结果集。

XPath限制。  这些函数支持的XPath语法目前受到以下限制:

  • '/a/b[@c=@d]' 不支持 节点集到节点集的比较(例如 )。

  • 支持所有标准XPath比较运算符。 (缺陷号22823)

  • 相对定位符表达式在根节点的上下文中解析。 例如,请考虑以下查询和结果:

    mysql> SELECT ExtractValue(
        - >    '<a><b c="1">X</b><b c="2">Y</b></a>',
        - >     'a/b'
        - >) AS result;
    + -------- +
    | 结果|
    + -------- +
    | XY |
    + -------- +
    1排(0.03秒)
    

    在这种情况下,定位器 a/b 解析为 /a/b

    谓词中也支持相对定位器。 在以下示例中, d[../@c="1"] 解析为 /a/b[@c="1"]/d

    mysql> SELECT ExtractValue(
        - >       '<a>
        - >         <b c="1"><d>X</d></b>
        - >         <b c="2"><d>X</d></b>
        - >       </a>',
        - >       'a/b/d[../@c="1"]')
        - >AS result;
    + -------- +
    | 结果|
    + -------- +
    | X |
    + -------- +
    1排(0.00秒)
    
  • 不允许使用以表达式为前缀的定位符作为标量值(包括变量引用,文字,数字和标量函数调用),并且它们的使用会导致错误。

  • :: 不支持 运算符与节点类型结合使用,例如:

    • axis::comment()

    • axis::text()

    • axis::processing-instructions()

    • axis::node()

    但是,支持名称测试(例如 ),如以下示例所示: axis::name axis::*

    MySQL的> SELECT ExtractValue('<a><b>x</b><c>y</c></a>','/a/child::b');
    + ------------------------------------------------- ------ +
    | ExtractValue('<a> <b> x </ b> <c> y </ c> </a>','/ a / child :: b')|
    + ------------------------------------------------- ------ +
    | x |
    + ------------------------------------------------- ------ +
    1排(0.02秒)
    
    MySQL的> SELECT ExtractValue('<a><b>x</b><c>y</c></a>','/a/child::*');
    + ------------------------------------------------- ------ +
    | ExtractValue('<a> <b> x </ b> <c> y </ c> </a>','/ a / child :: *')|
    + ------------------------------------------------- ------ +
    | xy |
    + ------------------------------------------------- ------ +
    1排(0.01秒)
    
  • 向上和向下 导航是不是在情况下,路径会导致支持 上面 的根元素。 也就是说,您不能使用与给定元素的祖先的后代匹配的表达式,其中当前元素的一个或多个祖先也是根元素的祖先(参见Bug#16321)。

  • 不支持以下XPath函数,或者已指出已知问题:

    • id()

    • lang()

    • local-name()

    • name()

    • namespace-uri()

    • normalize-space()

    • starts-with()

    • string()

    • substring-after()

    • substring-before()

    • translate()

  • 不支持以下轴:

    • following-sibling

    • following

    • preceding-sibling

    • preceding

XPath表达式作为参数传递, ExtractValue() 并且 UpdateXML() 可能 : 在元素选择器中 包含冒号字符( ),这使得它们可以使用带有XML命名空间符号的标记。 例如:

MySQL的> SET @xml = '<a>111<b:c>222<d>333</d><e:f>444</e:f></b:c></a>';
查询正常,0行受影响(0.00秒)

MySQL的> SELECT ExtractValue(@xml, '//e:f');
+ ----------------------------- +
| ExtractValue(@xml,'// e:f')|
+ ----------------------------- +
| 444 |
+ ----------------------------- +
1排(0.00秒)

MySQL的> SELECT UpdateXML(@xml, '//b:c', '<g:h>555</g:h>');
+ -------------------------------------------- +
| UpdateXML(@xml,'// b:c','<g:h> 555 </ g:h>')|
+ -------------------------------------------- +
| <a> 111 <g:h> 555 </ g:h> </a> |
+ -------------------------------------------- +
1排(0.00秒)

这在某些方面类似于 Apache Xalan 和其他一些解析器 所允许的 ,并且比要求命名空间声明或使用 namespace-uri() local-name() 函数 要简单得多

错误处理。  对于这两个 ExtractValue() UpdateXML() ,使用的XPath定位器必须有效和要搜索的XML必须由被正确地嵌套和关闭元件。 如果定位器无效,则会生成错误:

mysql> ERROR 1105(HY000):XPATH语法错误:'&a'SELECT ExtractValue('<a>c</a><b/>', '/&a');

如果 xml_frag 不包含正确嵌套和关闭的元素, NULL 则返回并生成警告,如下例所示:

MySQL的> SELECT ExtractValue('<a>c</a><b', '//a');
+ ----------------------------------- +
| ExtractValue('<a> c </a> <b','// a')|
+ ----------------------------------- +
| NULL |
+ ----------------------------------- +
1排,1警告(0.00秒)

MySQL的> SHOW WARNINGS\G
*************************** 1。排******************** *******
  等级:警告
   代码:1525
消息:XML值不正确:'第1行pos 11处的解析错误:
         END-OF-INPUT意外('>'想要''
1排(0.00秒)

MySQL的> SELECT ExtractValue('<a>c</a><b/>', '//a');
+ ------------------------------- +
| ExtractValue('<a> c </a> <b />','// a')|
+ ------------------------------- +
| c |
+ ------------------------------- +
1排(0.00秒)
重要

用作第三个参数替换XML到 UpdateXML() 检查,以确定是否它仅由被正确地嵌套和关闭元件。

XPath注入。  当恶意代码被引入系统以获得对特权和数据的未授权访问时,就会发生 代码注入 它基于利用开发人员对用户输入数据的类型和内容所做的假设。 XPath在这方面也不例外。

可能发生这种情况的常见情况是应用程序通过将登录名和密码的组合与XML文件中的组合进行匹配来处理授权,使用类似这样的XPath表达式:

// user [login / text()='neapolitan'和password / text()='1c3cr34m'] / attribute :: id

这是与此类似的SQL语句的XPath:

SELECT id FROM users WHERE login ='neapolitan'AND password''1c3cr34m';

使用XPath的PHP应用程序可能会像这样处理登录过程:

<?PHP

  $ file =“users.xml”;

  $ login = $ POST [“login”];
  $ password = $ POST [“password”];

  $ xpath =“// user [login / text()= $ login and password / text()= $ password] / attribute :: id”;

  if(file_exists($ file))
  {
    $ xml = simplexml_load_file($ file);

    if($ result = $ xml-> xpath($ xpath))
      echo“您现在以用户$ result [0]身份登录。”;
    其他
      echo“登录名或密码无效。”;
  }
  其他
    退出(“无法打开$ file。”);

?>

不对输入执行检查。 这意味着恶意用户可以 通过输入 登录名和密码 短路 测试 ' or 1=1 ,从而得到 $xpath 如下所示的评估:

// user [login / text()=''或1 = 1和password / text()=''或1 = 1] / attribute :: id

由于方括号内的表达式始终求值为 true ,因此它实际上与此对应,它与 XML文档 id 中每个 user 元素 属性 相匹配

//用户/属性:: ID

可以绕过这种特定攻击的一种方法是简单地引用要在插值中插入的变量名 $xpath ,强制将从Web表单传递的值转换为字符串:

$ xpath =“// user [login / text()='$ login'和password / text()='$ password'] / attribute :: id”;

这与通常建议用于防止SQL注入攻击的策略相同。 通常,您应该遵循的用于防止XPath注入攻击的实践与防止SQL注入相同:

  • 从未接受过应用程序中用户的未经测试的数据。

  • 检查所有用户提交的数据类型; 拒绝或转换错误类型的数据

  • 测试超出范围值的数值数据; 截断,舍入或拒绝超出范围的值。 测试非法字符的字符串,并将其删除或拒绝包含它们的输入。

  • 请勿输出可能为未经授权的用户提供可用于危害系统的线索的显式错误消息; 请将这些记录到文件或数据库表中。

正如SQL注入攻击可用于获取有关数据库模式的信息一样,XPath注入也可用于遍历XML文件以揭示其结构,如Amit Klein的论文 Blind XPath Injection (PDF文件,46KB)中所述。

检查发送回客户端的输出也很重要。 考虑一下当我们使用MySQL ExtractValue() 函数 时会发生什么

mysql> SELECT ExtractValue(
    - >      LOAD_FILE('users.xml'),
    - >      '//user[login/text()="" or 1=1 and password/text()="" or 1=1]/attribute::id'
    - >) AS id;
+ ------------------------------- +
| id |
+ ------------------------------- +
| 00327 13579 02403 42354 28570 |
+ ------------------------------- +
1排(0.01秒)

因为 ExtractValue() 将多个匹配作为单个空格分隔的字符串返回,所以此注入攻击将包含在 users.xml 用户 内的每个有效ID 作为单行输出提供。 作为额外的安全措施,您还应该在将输出返回给用户之前对其进行测试。 这是一个简单的例子:

mysql> SELECT @id = ExtractValue(
    - >      LOAD_FILE('users.xml'),
    - >      '//user[login/text()="" or 1=1 and password/text()="" or 1=1]/attribute::id'
    - >);
查询正常,0行受影响(0.00秒)

mysql> SELECT IF(
    - >      INSTR(@id, ' ') = 0,
    - >      @id,
    - >      'Unable to retrieve user ID')
    - >AS singleID;
+ ---------------------------- +
| singleID |
+ ---------------------------- +
| 无法检索用户ID |
+ ---------------------------- +
1排(0.00秒)

通常,安全地向用户返回数据的准则与接受用户输入的准则相同。 这些可以概括为:

  • 始终测试输出数据的类型和允许值。

  • 永远不允许未经授权的用户查看可能提供有关可能用于利用它的应用程序的信息的错误消息。

12.12位功能和操作符

表12.16位功能和操作符

名称 描述
BIT_COUNT() 返回设置的位数
& 按位AND
~ 按位反转
| 按位OR
^ 按位异或
<< 左移
>> 右转

位的函数和操作包括 BIT_COUNT() BIT_AND() BIT_OR() BIT_XOR() & | ^ ~ << ,和 >> (该 BIT_AND() BIT_OR() BIT_XOR() 聚集函数描述在 第12.20.1,“集合(GROUP BY)函数描述” 。)在此之前的MySQL 8.0,所需的比特的函数和操作 BIGINT (64位整数)的参数和返回的 BIGINT 值,因此他们有最大范围为64位。 BIGINT 参数 BIGINT 在执行操作之前 被转换为 可能发生截断。

在MySQL 8.0中,位函数和运算符允许二进制字符串类型参数( BINARY VARBINARY BLOB 类型)并返回类似的值,这使它们能够获取参数并生成大于64位的返回值。 非二进制字符串参数将 BIGINT 像以前一样 转换为 并进行处理。

这种行为改变的含义是二进制字符串参数的位操作可能在MySQL 8.0中产生与5.7中不同的结果。 有关如何准备在MySQL 5.7为MySQL 5.7和8.0之间的潜在的不兼容信息,请参见 位函数和操作符 ,在 MySQL的5.7参考手册

MySQL 8.0之前的位操作

MySQL 8.0之前的位操作只处理无符号的64位整数参数和结果值(即无符号 BIGINT 值)。 BIGINT 必要时 转换其他类型的参数 例子:

  • 此语句对数字文字进行操作,视为无符号64位整数:

    MySQL的> SELECT 127 | 128, 128 << 2, BIT_COUNT(15);
    + ----------- + ---------- + --------------- +
    | 127 | 128 | 128 << 2 | BIT_COUNT(15)|
    + ----------- + ---------- + --------------- +
    | 255 | 512 | 4 |
    + ----------- + ---------- + --------------- +
    
  • 在执行与第一个语句相同的操作并生成相同的结果之前, 此语句对字符串参数( '127' to 127 ,等等) 执行to-number转换

    MySQL的> SELECT '127' | '128', '128' << 2, BIT_COUNT('15');
    + --------------- + ------------ + ----------------- +
    | '127'| '128'| '128'<< 2 | BIT_COUNT('15')|
    + --------------- + ------------ + ----------------- +
    | 255 | 512 | 4 |
    + --------------- + ------------ + ----------------- +
    
  • 此语句将十六进制文字用于位操作参数。 默认情况下,MySQL将十六进制文字视为二进制字符串,但在数字上下文中将它们计算为数字(请参见 第9.1.4节“十六进制文字” )。 在MySQL 8.0之前,数字上下文包括位操作。 例子:

    MySQL的> SELECT X'7F' | X'80', X'80' << 2, BIT_COUNT(X'0F');
    + --------------- + ------------ + ------------------ +
    | X'7F'| X'80'| X'80'<< 2 | BIT_COUNT(X'0F')|
    + --------------- + ------------ + ------------------ +
    | 255 | 512 | 4 |
    + --------------- + ------------ + ------------------ +
    

    位操作中位值文字的处理类似于十六进制文字(即数字)。

MySQL 8.0中的位操作

MySQL 8.0扩展位操作以直接处理二进制字符串参数(无需转换)并生成二进制字符串结果。 (非整数或二进制字符串的参数仍然像以前一样转换为整数。)此扩展通过以下方式增强位操作:

  • 在长于64位的值上可以进行位操作。

  • 对更自然地表示为二进制字符串而不是整数的值执行位操作更容易。

例如,考虑UUID值和IPv6地址,它们具有如下所示的人类可读文本格式:

UUID:6ccd780c-baba-1026-9564-5b8c656024db
IPv6:fe80 :: 219:d1ff:fe91:1a72

以这些格式操作文本字符串是很麻烦的。 另一种方法是将它们转换为没有分隔符的固定长度的二进制字符串。 UUID_TO_BIN() 并且 INET6_ATON() 每个产生一个数据类型的值 BINARY(16) ,一个16字节(128位)长的二进制字符串。 以下语句说明了这一点( HEX() 用于生成可显示的值):

MySQL的> SELECT HEX(UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db'));
+ ------------------------------------------------- --------- +
| HEX(UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db'))|
+ ------------------------------------------------- --------- +
| 6CCD780CBABA102695645B8C656024DB |
+ ------------------------------------------------- --------- +
MySQL的> SELECT HEX(INET6_ATON('fe80::219:d1ff:fe91:1a72'));
+ --------------------------------------------- +
| HEX(INET6_ATON('fe80 :: 219:d1ff:fe91:1a72'))|
+ --------------------------------------------- +
| FE800000000000000219D1FFFE911A72 |
+ --------------------------------------------- +

这些二进制值可以通过位操作轻松操作,以执行诸如从UUID值中提取时间戳或提取IPv6地址的网络和主机部分等操作。 (例如,请参阅本讨论的后面部分。)

该计为二进制字符串参数包括列值,例程参数,局部变量和用户定义的变量具有一个二进制串类型: BINARY VARBINARY ,或的一个 BLOB 类型。

那么十六进制文字和位文字呢? 回想一下,默认情况下这些是MySQL中的二进制字符串,但是数字上下文中的数字。 它们如何处理MySQL 8.0中的位操作? MySQL是否继续在数字上下文中评估它们,就像MySQL 8.0之前一样? 或做位操作评估它们作为二进制字符串,现在二进制字符串可以办理 本地 ,无需转换?

答:通常使用十六进制文字或位文字指定位操作的参数,意图表示数字,因此当所有位参数都是十六进制或位文字时,MySQL继续在数值上下文中评估位操作,以实现向后兼容性。 如果您需要将评估作为二进制字符串,那么很容易实现:使用 _binary 至少一个文字 介绍人。

  • 这些位操作将十六进制文字和位文字计算为整数:

    MySQL的> SELECT X'40' | X'01', b'11110001' & b'01001111';
    + --------------- + --------------------------- +
    | X'40'| X'01'| b'11110001'&b'01001111'|
    + --------------- + --------------------------- +
    | 65 | 65 |
    + --------------- + --------------------------- +
    
  • 由于 _binary 介绍人的 原因,这些位操作将十六进制文字和位文字评估为二进制字符串

    MySQL的> SELECT _binary X'40' | X'01', b'11110001' & _binary b'01001111';
    + ----------------------- + ------------------------- ---------- +
    | _binary X'40'| X'01'| b'11110001'&_binary b'01001111'|
    + ----------------------- + ------------------------- ---------- +
    | A | A |
    + ----------------------- + ------------------------- ---------- +
    

尽管两个语句中的位操作产生的数值为65,但第二个语句在二进制字符串上下文中运行,其中65为ASCII A

在数值计算上下文中,十六进制文字和位文字参数的允许值最多为64位,结果也是如此。 相反,在二进制字符串评估上下文中,允许的参数(和结果)可以超过64位:

MySQL的> SELECT _binary X'4040404040404040' | X'0102030405060708';
+ ------------------------------------------------- -  +
| _binary X'4040404040404040'| X'0102030405060708'|
+ ------------------------------------------------- -  +
| ABCDEFGH |
+ ------------------------------------------------- -  +

有几种方法可以在位操作中引用十六进制文字或位文字来引起二进制字符串评估:

_binary literal
BINARY literal
CAST(literal作为二进制)

生成十六进制文字或位文字的二进制字符串评估的另一种方法是将它们分配给用户定义的变量,这会导致变量具有二进制字符串类型:

mysql> SET @v1 = X'40', @v2 = X'01', @v3 = b'11110001', @v4 = b'01001111';
mysql>SELECT @v1 | @v2, @v3 & @v4;
+ ----------- ----------- + +
| @ v1 | @ v2 | @ v3&@ v4 |
+ ----------- ----------- + +
| A | A |
+ ----------- ----------- + +

在二进制字符串上下文中,按位操作参数必须具有相同的长度或发生 ER_INVALID_BITWISE_OPERANDS_SIZE 错误:

MySQL的> SELECT _binary X'40' | X'0001';
ERROR 3513(HY000):按位的二进制操作数
运营商必须具有相同的长度

要满足等长要求,请使用前导零位填充较短的值,或者如果较长的值以前导零位开头并且可接受较短的结果值,请将它们剥离:

MySQL的> SELECT _binary X'0040' | X'0001';
+ --------------------------- +
| _binary X'0040'| X'0001'|
+ --------------------------- +
| A |
+ --------------------------- +
MySQL的> SELECT _binary X'40' | X'01';
+ ----------------------- +
| _binary X'40'| X'01'|
+ ----------------------- +
| A |
+ ----------------------- +

填充或汽提也可以使用的功能,例如来实现 LPAD() RPAD() SUBSTR() ,或 CAST() 在这种情况下,表达式参数不再是所有文字而 _binary 变得不必要。 例子:

MySQL的> SELECT LPAD(X'40', 2, X'00') | X'0001';
+ --------------------------------- +
| LPAD(X'40',2,X'00')| X'0001'|
+ --------------------------------- +
| A |
+ --------------------------------- +
MySQL的> SELECT X'40' | SUBSTR(X'0001', 2, 1);
+ ------------------------------- +
| X'40'| SUBSTR(X'0001',2,1)|
+ ------------------------------- +
| A |
+ ------------------------------- +

二进制字符串位操作示例

以下示例说明如何使用位操作来提取UUID值的一部分,在本例中为时间戳和IEEE 802节点号。 该技术需要每个提取部分的位掩码。

将文本UUID转换为相应的16字节二进制值,以便可以使用二进制字符串上下文中的位操作来操作它:

mysql> SET @uuid = UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db');
mysql>SELECT HEX(@uuid);
+ ---------------------------------- +
| HEX(@uuid)|
+ ---------------------------------- +
| 6CCD780CBABA102695645B8C656024DB |
+ ---------------------------------- +

构造值的时间戳和节点号部分的位掩码。 时间戳包括前三个部分(64位,位0到63),节点号是最后一部分(48位,位80到127):

mysql> SET @ts_mask = CAST(X'FFFFFFFFFFFFFFFF' AS BINARY(16));
mysql> SET @node_mask = CAST(X'FFFFFFFFFFFF' AS BINARY(16)) >> 80;
mysql>SELECT HEX(@ts_mask);
+ ---------------------------------- +
| HEX(@ts_mask)|
+ ---------------------------------- +
| FFFFFFFFFFFFFFFF0000000000000000 |
+ ---------------------------------- +
MySQL的> SELECT HEX(@node_mask);
+ ---------------------------------- +
| HEX(@node_mask)|
+ ---------------------------------- +
| 00000000000000000000FFFFFFFFFFFF |
+ ---------------------------------- +

CAST(... AS BINARY(16)) 功能用在这里,因为掩模必须是相同的长度作为对它们所施加的UUID值。 使用其他函数将掩码填充到所需长度可以产生相同的结果:

SET @ ts_mask = RPAD(X'FFFFFFFFFFFFFFFF',16,X'00');
SET @node_mask = LPAD(X'FFFFFFFFFFFF',16,X'00');

使用掩码来提取时间戳和节点号部分:

MySQL的> SELECT HEX(@uuid & @ts_mask) AS 'timestamp part';
+ ---------------------------------- +
| 时间戳部分|
+ ---------------------------------- +
| 6CCD780CBABA10260000000000000000 |
+ ---------------------------------- +
MySQL的> SELECT HEX(@uuid & @node_mask) AS 'node part';
+ ---------------------------------- +
| 节点部分|
+ ---------------------------------- +
| 000000000000000000005B8C656024DB |
+ ---------------------------------- +

前面的示例使用这些位操作:right shift( >> )和按位AND( & )。

注意

UUID_TO_BIN() 获取一个标志,导致在生成的二进制UUID值中进行一些位重新排列。 如果使用该标志,请相应地修改提取掩码。

下一个示例使用位操作来提取IPv6地址的网络和主机部分。 假设网络部分的长度为80位。 然后主机部分的长度为128-80 = 48位。 要提取地址的网络和主机部分,将其转换为二进制字符串,然后在二进制字符串上下文中使用位操作。

将文本IPv6地址转换为相应的二进制字符串:

MySQL的> SET @ip = INET6_ATON('fe80::219:d1ff:fe91:1a72');

以位为单位定义网络长度:

MySQL的> SET @net_len = 80;

通过向左或向右移动全1地址来构造网络和主机掩码。 要做到这一点,请从地址开始 :: ,这是所有零的简写,正如您可以通过将其转换为二进制字符串所示:

MySQL的> SELECT HEX(INET6_ATON('::')) AS 'all zeros';
+ ---------------------------------- +
| 全零|
+ ---------------------------------- +
| 00000000000000000000000000000000 |
+ ---------------------------------- +

要生成互补值(全1),请使用 ~ 运算符反转位:

MySQL的> SELECT HEX(~INET6_ATON('::')) AS 'all ones';
+ ---------------------------------- +
| 所有的|
+ ---------------------------------- +
| FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
+ ---------------------------------- +

向左或向右移动全1值以生成网络和主机掩码:

mysql> SET @net_mask = ~INET6_ATON('::') << (128 - @net_len);
mysql>SET @host_mask = ~INET6_ATON('::') >> @net_len;

显示掩码以验证它们是否覆盖了地址的正确部分:

MySQL的> SELECT INET6_NTOA(@net_mask) AS 'network mask';
+ ---------------------------- +
| 网络掩码|
+ ---------------------------- +
| ffff:ffff:ffff:ffff:ffff :: |
+ ---------------------------- +
MySQL的> SELECT INET6_NTOA(@host_mask) AS 'host mask';
+ ------------------------ +
| 主机面具|
+ ------------------------ +
| :: ffff:255.255.255.255 |
+ ------------------------ +

提取并显示地址的网络和主机部分:

mysql> SET @net_part = @ip & @net_mask;
mysql> SET @host_part = @ip & @host_mask;
mysql>SELECT INET6_NTOA(@net_part) AS 'network part';
+ ----------------- +
| 网络部分|
+ ----------------- +
| fe80 :: 219:0:0:0 |
+ ----------------- +
MySQL的> SELECT INET6_NTOA(@host_part) AS 'host part';
+ ------------------ +
| 主持人部分|
+ ------------------ +
| :: d1ff:fe91:1a72 |
+ ------------------ +

前面的示例使用这些位操作:Complement( ~ ),left shift( << )和按位AND( & )。

其余的讨论提供了有关每组位操作的参数处理的详细信息,有关位操作中字面值处理的更多信息,以及MySQL 8.0和旧MySQL版本之间潜在的不兼容性。

按位AND,OR和XOR运算

对于 & | ^ 位操作,结果类型取决于参数是作为二进制字符串还是数字计算:

  • 当参数具有二进制字符串类型时,会发生二进制字符串评估,并且其中至少有一个不是十六进制文字,位字面值或 NULL 文字。 否则进行数值计算,必要时将参数转换为无符号64位整数。

  • 二进制字符串求值会生成与参数长度相同的二进制字符串。 如果参数长度不等, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

数值评估的例子:

MySQL的> SELECT 64 | 1, X'40' | X'01';
+ -------- + -------- +
| 64 | 1 | X'40'| X'01'|
+ -------- + -------- +
| 65 | 65 |
+ -------- + -------- +

二进制字符串评估的示例:

MySQL的> SELECT _binary X'40' | X'01';
+ ----------------------- +
| _binary X'40'| X'01'|
+ ----------------------- +
| A |
+ ----------------------- +
mysql> SET @var1 = X'40', @var2 = X'01';
mysql>SELECT @var1 | @var2;
+ --------------- +
| @ var1 | @ var2 |
+ --------------- +
| A |
+ --------------- +

按位补充和移位操作

对于 ~ << >> 位操作,结果类型取决于bit参数是否被计算为二进制字符串或数字:

  • 当bit参数具有二进制字符串类型且不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数转换为无符号的64位整数。

  • 二进制字符串评估生成与bit参数长度相同的二进制字符串。 数值计算生成无符号的64位整数。

对于移位操作,无论参数类型如何,在值结束时移位的位都会在没有警告的情况下丢失。 特别是,如果移位计数大于或等于位参数中的位数,则结果中的所有位都为0。

数值评估的例子:

MySQL的> SELECT ~0, 64 << 2, X'40' << 2;
+ ---------------------- + --------- + ------------ +
| 〜0 | 64 << 2 | X'40'<< 2 |
+ ---------------------- + --------- + ------------ +
| 18446744073709551615 | 256 | 256 |
+ ---------------------- + --------- + ------------ +

二进制字符串评估的示例:

MySQL的> SELECT HEX(_binary X'1111000022220000' >> 16);
+ ---------------------------------------- +
| HEX(_binary X'1111000022220000'>> 16)|
+ ---------------------------------------- +
| 0000111100002222 |
+ ---------------------------------------- +
MySQL的> SELECT HEX(_binary X'1111000022220000' << 16);
+ ---------------------------------------- +
| HEX(_binary X'1111000022220000'<< 16)|
+ ---------------------------------------- +
| 0000222200000000 |
+ ---------------------------------------- +
mysql> SET @var1 = X'F0F0F0F0';
mysql>SELECT HEX(~@var1);
+ ------------- +
| HEX(〜@ var1)|
+ ------------- +
| 0F0F0F0F |
+ ------------- +

BIT_COUNT()操作

BIT_COUNT() 函数始终返回无符号的64位整数,或者 NULL 如果参数为 NULL

MySQL的> SELECT BIT_COUNT(127);
+ ---------------- +
| BIT_COUNT(127)|
+ ---------------- +
| 7 |
+ ---------------- +
MySQL的> SELECT BIT_COUNT(b'010101'), BIT_COUNT(_binary b'010101');
+ ---------------------- + -------------------------- ---- +
| BIT_COUNT(b'010101')| BIT_COUNT(_binary b'010101')|
+ ---------------------- + -------------------------- ---- +
| 3 | 3 |
+ ---------------------- + -------------------------- ---- +

BIT_AND(),BIT_OR()和BIT_XOR()操作

对于 BIT_AND() BIT_OR() BIT_XOR() 位的功能,结果类型取决于该函数的参数值是否被评价为二进制字符串或数字:

  • 当参数值具有二进制字符串类型且参数不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数值转换为无符号64位整数。

  • 二进制字符串评估生成与参数值长度相同的二进制字符串。 如果参数值具有不相等的长度, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 如果参数大小超过511个字节, ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

NULL 除非所有值都是,否则值不会影响结果 NULL 在这种情况下,结果是一个中性值,其长度与参数值的长度相同(所有位1表示 BIT_AND() ,所有位0表示 BIT_OR() ,和 BIT_XOR() )。

例:


mysql> CREATE TABLE t (group_id INT, a VARBINARY(6));
mysql> INSERT INTO t VALUES (1, NULL);
mysql> INSERT INTO t VALUES (1, NULL);
mysql> INSERT INTO t VALUES (2, NULL);
mysql> INSERT INTO t VALUES (2, X'1234');
mysql> INSERT INTO t VALUES (2, X'FF34');
mysql>SELECT HEX(BIT_AND(a)), HEX(BIT_OR(a)), HEX(BIT_XOR(a))
       FROM t GROUP BY group_id;
+ ----------------- + ---------------- -------------- + --- +
| HEX(BIT_AND(a))| HEX(BIT_OR(a))| HEX(BIT_XOR(a))|
+ ----------------- + ---------------- -------------- + --- +
| FFFFFFFFFFFF | 000000000000 | 000000000000 |
| 1234 | FF34 | ED00 |
+ ----------------- + ---------------- -------------- + --- +

十六进制文字,位文字和NULL文字的特殊处理

为了向后兼容,当所有位参数都是十六进制文字,位文字或 NULL 文字 时,MySQL 8.0会在数值上下文中评估位操作 也就是说,如果所有位参数都是非简化的十六进制文字,位文字或 NULL 文字 ,则对二进制字符串位参数的位操作不使用二进制字符串求值 (如果这些文字是使用 _binary 介绍人, BINARY 操作符或其他明确指定为二进制字符串的方式 编写的,则不适用于此类文字 。)

刚刚描述的文字处理与MySQL 8.0之前的处理相同。 例子:

  • 这些位操作在数值上下文中计算文字并生成 BIGINT 结果:

    b'0001'| b'0010'
    X'0008'<< 8
    
  • 这些位操作 NULL 在数值上下文中计算并生成 BIGINT 具有 NULL 结果

    NULL和NULL
    NULL >> 4
    

在MySQL 8.0中,您可以通过明确指示至少一个参数是二进制字符串,使这些操作评估二进制字符串上下文中的参数:

_binary b'0001'| b'0010'
_binary X'0008'<< 8
BINARY NULL&NULL
BINARY NULL >> 4

最后两个表达式的结果 NULL 与没有 BINARY 运算符一样,但结果的数据类型是二进制字符串类型而不是整数类型。

与MySQL 5.7的位操作不兼容

因为位操作可以在MySQL 8.0中本地处理二进制字符串参数,所以某些表达式在MySQL 8.0中产生的结果与在5.7中不同。 需要注意的五个有问题的表达类型是:

nonliteral_binary{&| ^}   {&| ^} {<< >>} binary
binarynonliteral_binary
nonliteral_binaryanythingnonliteral_binary
AGGR_BIT_FUNCnonliteral_binary

这些表达式 BIGINT 在MySQL 5.7中 返回 ,在8.0中 返回 二进制字符串。

符号说明:

  • { op1 op2 ... } :适用于给定表达式类型的运算符列表。

  • binary :任何类型的二进制字符串参数,包括十六进制文字,位文字或 NULL 文字。

  • nonliteral_binary :一个参数,它是二进制字符串值,而不是十六进制文字,位字面值或 NULL 文字。

  • AGGR_BIT_FUNC :一个聚集函数,它位值参数: BIT_AND() BIT_OR() BIT_XOR()

有关如何准备在MySQL 5.7为MySQL 5.7和8.0之间的潜在的不兼容信息,请参见 位函数和操作符 ,在 MySQL的5.7参考手册

以下列表描述了可用的位功能和运算符:

  • |

    按位OR。

    结果类型取决于参数是作为二进制字符串还是数字计算:

    • 当参数具有二进制字符串类型时,会发生二进制字符串评估,并且其中至少有一个不是十六进制文字,位字面值或 NULL 文字。 否则进行数值计算,必要时将参数转换为无符号64位整数。

    • 二进制字符串求值会生成与参数长度相同的二进制字符串。 如果参数长度不等, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

    有关更多信息,请参阅本节中的介绍性讨论。

    MySQL的> SELECT 29 | 15;
            - > 31
    MySQL的> SELECT _binary X'40404040' | X'01020304';
            - >'ABCD'
    
  • &

    按位AND。

    结果类型取决于参数是作为二进制字符串还是数字计算:

    • 当参数具有二进制字符串类型时,会发生二进制字符串评估,并且其中至少有一个不是十六进制文字,位字面值或 NULL 文字。 否则进行数值计算,必要时将参数转换为无符号64位整数。

    • 二进制字符串求值会生成与参数长度相同的二进制字符串。 如果参数长度不等, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

    有关更多信息,请参阅本节中的介绍性讨论。

    MySQL的> SELECT 29 & 15;
            - > 13
    MySQL的> SELECT HEX(_binary X'FF' & b'11110000');
            - >'F0'
    
  • ^

    按位异或。

    结果类型取决于参数是作为二进制字符串还是数字计算:

    • 当参数具有二进制字符串类型时,会发生二进制字符串评估,并且其中至少有一个不是十六进制文字,位字面值或 NULL 文字。 否则进行数值计算,必要时将参数转换为无符号64位整数。

    • 二进制字符串求值会生成与参数长度相同的二进制字符串。 如果参数长度不等, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

    有关更多信息,请参阅本节中的介绍性讨论。

    MySQL的> SELECT 1 ^ 1;
            - > 0
    MySQL的> SELECT 1 ^ 0;
            - > 1
    MySQL的> SELECT 11 ^ 3;
            - > 8
    MySQL的> SELECT HEX(_binary X'FEDC' ^ X'1111');
            - >'EFCD'
    
  • <<

    将longlong( BIGINT )数字或二进制字符串向左 移位

    结果类型取决于bit参数是否被计算为二进制字符串或数字:

    • 当bit参数具有二进制字符串类型且不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估生成与bit参数长度相同的二进制字符串。 数值计算生成无符号的64位整数。

    无论参数类型如何,在没有警告的情况下,在值结束时移位的位都会丢失。 特别是,如果移位计数大于或等于位参数中的位数,则结果中的所有位都为0。

    有关更多信息,请参阅本节中的介绍性讨论。

    MySQL的> SELECT 1 << 2;
            - > 4
    MySQL的> SELECT HEX(_binary X'00FF00FF00FF' << 8);
            - >'FF00FF00FF00'
    
  • >>

    将longlong( BIGINT )数字或二进制字符串向右 移位

    结果类型取决于bit参数是否被计算为二进制字符串或数字:

    • 当bit参数具有二进制字符串类型且不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估生成与bit参数长度相同的二进制字符串。 数值计算生成无符号的64位整数。

    无论参数类型如何,在没有警告的情况下,在值结束时移位的位都会丢失。 特别是,如果移位计数大于或等于位参数中的位数,则结果中的所有位都为0。

    有关更多信息,请参阅本节中的介绍性讨论。

    MySQL的> SELECT 4 >> 2;
            - > 1
    MySQL的> SELECT HEX(_binary X'00FF00FF00FF' >> 8);
            - >'0000FF00FF00'
    
  • ~

    反转所有位。

    结果类型取决于bit参数是否被计算为二进制字符串或数字:

    • 当bit参数具有二进制字符串类型且不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估生成与bit参数长度相同的二进制字符串。 数值计算生成无符号的64位整数。

    有关更多信息,请参阅本节中的介绍性讨论。

    MySQL的> SELECT 5 & ~1;
            - > 4
    MySQL的> SELECT HEX(~X'0000FFFF1111EEEE');
            - >'FFFF0000EEEE1111'
    
  • BIT_COUNT(N)

    返回参数中设置的位数, N 作为无符号的64位整数,或者 NULL 参数是否为 NULL

    MySQL的> SELECT BIT_COUNT(64), BIT_COUNT(BINARY 64);
            - > 1,7
    MySQL的> SELECT BIT_COUNT('64'), BIT_COUNT(_binary '64');
            - > 1,7
    MySQL的> SELECT BIT_COUNT(X'40'), BIT_COUNT(_binary X'40');
            - > 1,1
    

12.13加密和压缩功能

表12.17加密功能

名称 描述
AES_DECRYPT() 使用AES解密
AES_ENCRYPT() 使用AES加密
ASYMMETRIC_DECRYPT() 使用私钥或公钥解密密文
ASYMMETRIC_DERIVE() 从非对称密钥导出对称密钥
ASYMMETRIC_ENCRYPT() 使用私钥或公钥加密明文
ASYMMETRIC_SIGN() 从摘要生成签名
ASYMMETRIC_VERIFY() 验证签名是否与摘要匹配
COMPRESS() 将结果作为二进制字符串返回
CREATE_ASYMMETRIC_PRIV_KEY() 创建私钥
CREATE_ASYMMETRIC_PUB_KEY() 创建公钥
CREATE_DH_PARAMETERS() 生成共享DH密钥
CREATE_DIGEST() 从字符串生成摘要
DECODE() 解码使用ENCODE()加密的字符串
DES_DECRYPT() 解密一个字符串
DES_ENCRYPT() 加密字符串
ENCODE() 编码一个字符串
ENCRYPT() 加密字符串
MD5() 计算MD5校验和
PASSWORD() 计算并返回密码字符串
RANDOM_BYTES() 返回一个随机字节向量
SHA1() SHA() 计算SHA-1 160位校验和
SHA2() 计算SHA-2校验和
STATEMENT_DIGEST() 计算语句摘要哈希值
STATEMENT_DIGEST_TEXT() 计算规范化语句摘要
UNCOMPRESS() 解压缩压缩的字符串
UNCOMPRESSED_LENGTH() 压缩前返回字符串的长度
VALIDATE_PASSWORD_STRENGTH() 确定密码的强度

许多加密和压缩函数返回结果可能包含任意字节值的字符串。 如果你想存储这些结果,使用与一列 VARBINARY BLOB 二进制字符串数据类型。 这将避免可能会更改数据值的尾随空格删除或字符集转换的潜在问题,例如,如果使用非二进制字符串数据类型( CHAR 则可能会出现此问题 VARCHAR TEXT

一些加密函数返回ASCII字符的字符串: MD5() SHA() SHA1() SHA2() STATEMENT_DIGEST() STATEMENT_DIGEST_TEXT() 它们的返回值是一个字符串,它具有由 系统变量 character_set_connection collation_connection 系统变量 确定的字符集和排序规则 除非字符集是,否则这是非二进制字符串 binary

如果应用程序存储来自诸如 MD5() SHA1() 返回十六进制数字字符串的 函数的值, 则可以通过将十六进制表示转换为二进制 UNHEX() 使用 将结果存储在 列中 来获得更有效的存储和比较 每对十六进制数字需要二进制形式的一个字节,因此值 取决于十六进制字符串的长度。 值为16, 值为20 对于 范围从28到32,具体取决于指定结果的所需位长度的参数。 BINARY(N) N N MD5() SHA1() SHA2() N

将十六进制字符串存储在 CHAR 列中 的大小惩罚 至少为两次,如果该值存储在使用该 utf8 字符集 的列中 (每个字符使用4个字节) ,则最多为八次 存储字符串还会导致比较较慢,因为值较大且需要考虑字符集排序规则。

假设应用程序将 MD5() 字符串值 存储 CHAR(32) 列中:

CREATE TABLE md5_tbl(md5_val CHAR(32),...);
INSERT INTO md5_tbl(md5_val,...)VALUES(MD5('abcdef'),...);

以十六进制字符串转换为更紧凑的形式,修改使用应用程序 UNHEX() ,并 BINARY(16) 改为如下:

CREATE TABLE md5_tbl(md5_val BINARY(16),...);
INSERT INTO md5_tbl(md5_val,...)VALUES(UNHEX(MD5('abcdef')),...);

应该准备应用程序来处理非常罕见的情况,即散列函数为两个不同的输入值产生相同的值。 使冲突可检测的一种方法是使哈希列成为主键。

注意

已知对MD5和SHA-1算法的利用。 您可能希望考虑使用本节中描述的另一种单向加密函数,例如 SHA2()

警告

除非使用SSL连接,否则作为加密函数参数提供的密码或其他敏感值将以明文形式发送到MySQL服务器。 此外,这些值将出现在它们所写的任何MySQL日志中。 为避免这些类型的暴露,应用程序可以在将敏感值发送到服务器之前加密客户端上的敏感值。 相同的考虑因素适用于加密密钥。 为了避免暴露这些,应用程序可以使用存储过程来加密和解密服务器端的值。

  • AES_DECRYPT(crypt_str,key_str[,init_vector])

    此功能使用官方AES(高级加密标准)算法解密数据。 有关更多信息,请参阅的说明 AES_ENCRYPT()

    可选的初始化向量参数, init_vector 使用 AES_DECRYPT() 的语句对于基于语句的复制不安全。

  • AES_ENCRYPT(str,key_str[,init_vector])

    AES_ENCRYPT() AES_DECRYPT() 使用官方的AES(高级加密标准)算法实现数据的加密和解密,该算法以前称为 Rijndael”。 AES标准允许各种密钥长度。 默认情况下,这些函数实现具有128位密钥长度的AES。 可以使用196或256位的密钥长度,如稍后所述。 密钥长度是性能和安全性之间的权衡。

    AES_ENCRYPT() str 使用密钥字符串 加密 字符串 key_str 并返回包含加密输出的二进制字符串。 使用密钥字符串 AES_DECRYPT() 解密加密 crypt_str 的字符串 key_str 并返回原始明文字符串。 如果任一函数参数是 NULL ,则函数返回 NULL

    str crypt_str 参数可以是任何长度,并且填充被自动添加到 str 所以它是所要求的基于块的算法,如AES的块的倍数。 AES_DECRYPT() 功能 将自动删除此填充 crypt_str 可以使用以下公式计算 长度

    16 *(trunc(string_length/ 16)+ 1)
    

    对于128位密钥长度,将密钥传递给 key_str 参数 的最安全方法 是创建一个真正随机的128位值并将其作为二进制值传递。 例如:

    插入到t
    VALUES(1,AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));
    

    密码短语可用于通过对密码短语进行散列来生成AES密钥。 例如:

    插入到t
    VALUES(1,AES_ENCRYPT('text',UNHEX(SHA2('我的秘密密码',512))));
    

    不要直接传递密码或密码 crypt_str ,先将其哈希。 此文档的早期版本建议使用前一种方法,但不再推荐使用此方法,因为此处显示的示例更安全。

    如果 AES_DECRYPT() 检测到无效数据或填充不正确,则返回 NULL 但是, 如果输入数据或密钥无效 ,则可能 AES_DECRYPT() 返回非 NULL 值(可能是垃圾)。

    AES_ENCRYPT() AES_DECRYPT() 允许控制块加密模式并采用可选的 init_vector 初始化向量参数:

    • 所述 block_encryption_mode 系统变量控制用于基于块的加密算法的模式。 其默认值为 aes-128-ecb ,表示使用密钥长度128位和ECB模式进行加密。 有关此变量的允许值的说明,请参见 第5.1.8节“服务器系统变量”

    • 可选 init_vector 参数为需要它的块加密模式提供初始化向量。

    对于需要可选 init_vector 参数的 模式 ,它必须是16个字节或更长(忽略超过16个字节)。 如果 init_vector 缺少 则会发生错误

    对于不需要的模式 init_vector ,将忽略该 模式, 并在指定时生成警告。

    可以通过调用生成用于初始化向量的随机字节串 RANDOM_BYTES(16) 对于需要初始化向量的加密模式,必须使用相同的向量进行加密和解密。

    mysql> SET block_encryption_mode = 'aes-256-cbc';
    mysql> SET @key_str = SHA2('My secret passphrase',512);
    mysql> SET @init_vector = RANDOM_BYTES(16);
    mysql> SET @crypt_str = AES_ENCRYPT('text',@key_str,@init_vector);
    mysql>SELECT AES_DECRYPT(@crypt_str,@key_str,@init_vector);
    + ----------------------------------------------- +
    | AES_DECRYPT(@ crypt_str,@ key_str,@ init_vector)|
    + ----------------------------------------------- +
    | 文字|
    + ----------------------------------------------- +
    

    下表列出了每种允许的块加密模式,支持它的SSL库以及是否需要初始化向量参数。

    块加密模式 支持模式的SSL库 初始化向量必需
    欧洲央行 OpenSSL,wolfSSL 没有
    CBC OpenSSL,wolfSSL
    CFB1 OpenSSL的
    CFB8 OpenSSL的
    CFB128 OpenSSL的
    OFB OpenSSL的

    对基于语句的复制 使用 AES_ENCRYPT() AES_DECRYPT() 不安全的语句。

  • COMPRESS(string_to_compress)

    压缩字符串并将结果作为二进制字符串返回。 这个函数要求MySQL已经用压缩库编译,如 zlib 否则,返回值始终为 NULL 压缩后的字符串可以解压缩 UNCOMPRESS()

    MySQL的> SELECT LENGTH(COMPRESS(REPEAT('a',1000)));
            - > 21
    MySQL的> SELECT LENGTH(COMPRESS(''));
            - > 0
    MySQL的> SELECT LENGTH(COMPRESS('a'));
            - > 13
    MySQL的> SELECT LENGTH(COMPRESS(REPEAT('a',16)));
            - > 15
    

    压缩的字符串内容按以下方式存储:

    • 空字符串存储为空字符串。

    • 非空字符串存储为未压缩字符串的4字节长度(低字节优先),后跟压缩字符串。 如果字符串以空格结尾, . 则会添加 一个额外的 字符,以避免在结果存储在 CHAR VARCHAR 列中时 对端空间 修剪的问题 (然而,使用非二进制字符串数据类型如 CHAR VARCHAR 不建议存储压缩字符串无论如何,因为可能会发生字符集转换。使用 VARBINARY BLOB 二进制字符串列来代替。)

  • DECODE(crypt_str,pass_str)

    在MySQL 8.0.3中删除了此功能。

    考虑使用 AES_ENCRYPT() AES_DECRYPT() 不是。

  • DES_DECRYPT(crypt_str[,key_str])

    在MySQL 8.0.3中删除了此功能。

    考虑使用 AES_ENCRYPT() AES_DECRYPT() 不是。

  • DES_ENCRYPT(str[,{key_num|key_str}])

    在MySQL 8.0.3中删除了此功能。

    考虑使用 AES_ENCRYPT() AES_DECRYPT() 不是。

  • ENCODE(str,pass_str)

    在MySQL 8.0.3中删除了此功能。

    考虑使用 AES_ENCRYPT() AES_DECRYPT() 不是。

  • ENCRYPT(str[,salt])

    在MySQL 8.0.3中删除了此功能。 对于单向散列,请考虑使用 SHA2()

  • MD5(str)

    计算字符串的MD5 128位校验和。 该值以32个十六进制数字的字符串形式返回,或者 NULL 如果参数为 NULL 例如,返回值可以用作散列键。 请参阅本节开头的有关有效存储哈希值的说明。

    返回值是连接字符集中的字符串。

    如果启用了FIPS模式,则 MD5() 返回 NULL 请参见 第6.5节“FIPS支持”

    MySQL的> SELECT MD5('testing');
            - >'ae2b1fca515949e5d54fb22b8ed95575'
    

    这是 RSA Data Security,Inc。MD5消息摘要算法”。

    请参阅本节开头的有关MD5算法的说明。

  • PASSWORD(str)

    在MySQL 8.0.11中删除了此功能。

  • RANDOM_BYTES(len)

    此函数返回 len 使用SSL库的随机数生成器生成 随机字节 的二进制字符串 允许的值 len 范围为1到1024.对于该范围之外的值,将 RANDOM_BYTES() 生成警告并返回 NULL

    RANDOM_BYTES() 可用于为 AES_DECRYPT() AES_ENCRYPT() 函数 提供初始化向量 要在该上下文中使用, len 必须至少为16.允许更大的值,但忽略超过16的字节。

    RANDOM_BYTES() 生成一个随机值,使其结果不确定。 因此,使用此函数的语句对于基于语句的复制是不安全的。

  • SHA1(str) SHA(str)

    计算字符串的SHA-1 160位校验和,如RFC 3174(安全散列算法)中所述。 该值以40个十六进制数字的字符串形式返回,或者 NULL 如果参数为 NULL 此函数的一种可能用途是作为哈希键。 请参阅本节开头的有关有效存储哈希值的说明。 SHA() 是的同义词 SHA1()

    返回值是连接字符集中的字符串。

    MySQL的> SELECT SHA1('abc');
            - >'a9993e364706816aba3e25717850c26c9cd0d89d'
    

    SHA1() 可以认为是加密更安全的等价物 MD5() 但是,请参阅本节开头的有关MD5和SHA-1算法的说明。

  • SHA2(str, hash_length)

    计算SHA-2系列散列函数(SHA-224,SHA-256,SHA-384和SHA-512)。 第一个参数是要散列的明文字符串。 第二个参数表示结果的所需位长度,其值必须为224,256,384,512或0(相当于256)。 如果任一参数是 NULL 或者哈希长度不是允许值之一,则返回值为 NULL 否则,函数结果是包含所需位数的散列值。 请参阅本节开头的有关有效存储哈希值的说明。

    返回值是连接字符集中的字符串。

    MySQL的> SELECT SHA2('abc', 224);
            - >'23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'
    

    仅当MySQL已配置SSL支持时,此功能才有效。 请参见 第6.3节“使用加密连接”

    SHA2() 可以认为加密比 MD5() 更安全 SHA1()

  • STATEMENT_DIGEST(statement)

    将SQL语句作为字符串,将语句摘要哈希值作为连接字符集中的字符串返回,或者 NULL 如果参数为 NULL 相关 STATEMENT_DIGEST_TEXT() 函数返回规范化语句摘要。 有关 语句摘要的 信息,请参见 第26.10节“性能模式语句摘要和采样”

    这两个函数都使用MySQL解析器来解析语句。 如果解析失败,则会发生错误。 仅当语句作为文字字符串提供时,错误消息才包含解析错误。

    max_digest_length 系统变量决定用于计算归一化的语句消化提供给这些功能的最大字节数。

    mysql> SET @stmt = 'SELECT * FROM mytable WHERE cola = 10 AND colb = 20';
    mysql>SELECT STATEMENT_DIGEST(@stmt);
    + ------------------------------------------------- ----------------- +
    | STATEMENT_DIGEST(@stmt)|
    + ------------------------------------------------- ----------------- +
    | 3bb95eeade896657c4526e74ff2a2862039d0a0fe8a9e7155b5fe492cbd78387 |
    + ------------------------------------------------- ----------------- +
    MySQL的> SELECT STATEMENT_DIGEST_TEXT(@stmt);
    + ------------------------------------------------- --------- +
    | STATEMENT_DIGEST_TEXT(@stmt)|
    + ------------------------------------------------- --------- +
    | SELECT * FROM`mytable` WHERE`cola` =?AND`colb` =?|
    + ------------------------------------------------- --------- +
    
  • STATEMENT_DIGEST_TEXT(statement)

    将SQL语句作为字符串给出,将规范化的语句摘要作为连接字符集中的字符串返回,或者 NULL 如果参数为 NULL 有关其他讨论和示例,请参阅相关 STATEMENT_DIGEST() 功能 的说明

  • UNCOMPRESS(string_to_uncompress)

    解压缩由 COMPRESS() 函数 压缩的字符串 如果参数不是压缩值,则结果为 NULL 这个函数要求MySQL已经用压缩库编译,如 zlib 否则,返回值始终为 NULL

    MySQL的> SELECT UNCOMPRESS(COMPRESS('any string'));
            - >'任何字符串'
    MySQL的> SELECT UNCOMPRESS('any string');
            - > NULL
    
  • UNCOMPRESSED_LENGTH(compressed_string)

    返回压缩字符串压缩之前的长度。

    MySQL的> SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));
            - > 30
    
  • VALIDATE_PASSWORD_STRENGTH(str)

    给定表示明文密码的参数,此函数返回一个整数以指示密码的强度。 返回值的范围从0(弱)到100(强)。

    密码评估由 组件 VALIDATE_PASSWORD_STRENGTH() 完成 validate_password 如果未安装该组件,则该函数始终返回0.有关安装的信息 validate_password ,请参见 第6.4.3节“密码验证组件” 要检查或配置影响密码测试的参数,请检查或设置由其实现的系统变量 validate_password 请参见 第6.4.3.2节“密码验证选项和变量”

    密码经过越来越严格的测试,返回值反映了满足哪些测试,如下表所示。 此外,如果 validate_password.check_user_name 启用 系统变量且密码与用户名匹配,则 VALIDATE_PASSWORD_STRENGTH() 无论如何 validate_password 设置 其他 系统变量,都 返回0

    密码测试 回报价值
    长度<4 0
    长度≥4且< validate_password.length 25
    满足政策1( LOW 50
    满足政策2( MEDIUM 75
    满足政策3( STRONG 100

12.14锁定功能

本节介绍用于操作用户级锁的函数。

表12.18锁定功能

名称 描述
GET_LOCK() 获取命名锁
IS_FREE_LOCK() 命名锁是否免费
IS_USED_LOCK() 命名锁是否正在使用; 返回连接标识符,如果为true
RELEASE_ALL_LOCKS() 释放所有当前命名的锁
RELEASE_LOCK() 释放命名锁

  • GET_LOCK(str,timeout)

    尝试 str 使用超时 timeout 获取具有字符串给定名称的锁 负值 timeout 表示无限超时。 锁是独家的。 由一个会话持有,其他会话无法获得同名的锁。

    返回 1 如果成功获得锁, 0 如果尝试超时(例如,由于另一个客户端已先前锁定的名称),或者 NULL 如果发生错误(比如内存溢出或线程与被杀 中mysqladmin杀 )。

    GET_LOCK() 通过执行 RELEASE_LOCK() 或隐式地在会话终止时(正常或异常), 显式释放 获得的锁 GET_LOCK() 在事务提交或回滚时 不会释放 获得的锁

    GET_LOCK() 使用元数据锁定(MDL)子系统实现。 可以获取多个同时锁定, GET_LOCK() 并且不释放任何现有锁定。 例如,假设您执行以下语句:

    SELECT GET_LOCK('lock1',10);
    SELECT GET_LOCK('lock2',10);
    SELECT RELEASE_LOCK('lock2');
    SELECT RELEASE_LOCK('lock1');
    

    第二个 GET_LOCK() 获取第二个锁,两个 RELEASE_LOCK() 调用返回1(成功)。

    甚至可以为给定会话获取同名的多个锁。 在获取会话释放其名称的所有锁之前,其他会话无法获取具有该名称的锁。

    获取的唯一命名锁定 GET_LOCK() 出现在Performance Schema metadata_locks 表中。 OBJECT_TYPE 柱说, USER LEVEL LOCK OBJECT_NAME 列表示锁名。 在为 同一 名称 获取多个锁的情况下 ,只有名称的第一个锁在 metadata_locks 表中 注册一行 名称的后续锁定会增加锁定中的计数器,但不会获取其他元数据锁定。 metadata_locks 释放名称上的最后一个锁实例时,将删除锁 行。

    获取多个锁的能力意味着客户端之间可能存在死锁。 发生这种情况时,服务器会选择一个调用者并终止其锁定获取请求并显示 ER_USER_LOCK_DEADLOCK 错误。 此错误不会导致事务回滚。

    MySQL对64个字符的锁名称强制执行最大长度。

    GET_LOCK() 可用于实现应用程序锁定或模拟记录锁定。 名称在服务器范围内被锁定。 如果名称已在一个会话中锁定, GET_LOCK() 阻止另一个会话请求具有相同名称的锁。 这使得同意给定锁定名称的客户端能够使用该名称执行协作建议锁定。 但请注意,它还使不在合作客户端集合中的客户端能够无意或有意地锁定名称,从而阻止任何合作客户端锁定该名称。 降低这种可能性的一种方法是使用特定于数据库或特定于应用程序的锁名称。 例如,使用表单 db_name.str 或的 锁名称 app_name.str

    如果多个客户端正在等待锁定,则它们将获取它的顺序是未定义的。 应用程序不应假设客户端将按照发出锁定请求的顺序获取锁定。

    GET_LOCK() 对于基于语句的复制是不安全的。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

    警告

    由于能够获取多个命名锁,因此单个语句可以获取大量锁。 例如:

    INSERT INTO ...从G1中选择GET_LOCK(t1.col_name);
    

    这些类型的陈述可能会产生某些不利影响。 例如,如果语句部分失败并回滚,则仍然存在获取到失败点的锁。 如果意图是在插入的行和获取的锁之间存在对应关系,则不会满足该意图。 此外,如果按特定顺序授予锁定很重要,请注意结果集顺序可能会有所不同,具体取决于优化程序选择的执行计划。 由于这些原因,最好将应用程序限制为每个语句的单个锁定获取调用。

    不同的锁定接口可用作插件服务或一组用户定义的函数。 与由 GET_LOCK() 相关函数 提供的接口不同,此接口提供锁名称空间和不同的读写锁 有关详细信息,请参见 第29.3.1节“锁定服务”

  • IS_FREE_LOCK(str)

    检查命名的锁是否 str 可以自由使用(即未锁定)。 返回 1 如果锁是免费的(没有人正在使用的锁), 0 如果锁处于使用中,并且 NULL 如果发生错误(例如,一个不正确的参数)。

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • IS_USED_LOCK(str)

    检查命名的锁是否 str 正在使用(即锁定)。 如果是,则返回持有锁的客户端会话的连接标识符。 否则,它返回 NULL

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • RELEASE_ALL_LOCKS()

    释放当前会话持有的所有命名锁,并返回释放的锁数(如果没有则返回0)

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • RELEASE_LOCK(str)

    释放由 str 获得 的字符串命名的锁 GET_LOCK() 返回 1 如果锁被释放, 0 如果锁不是由该线程(在这种情况下,锁定不会被释放)成立, NULL 如果不存在命名的锁。 如果从未通过调用获得锁定 GET_LOCK() 或者之前已经释放 锁定,则锁定不存在

    DO 声明使用方便 RELEASE_LOCK() 请参见 第13.2.3节“DO语法”

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

12.15信息功能

表12.19信息功能

名称 描述
BENCHMARK() 反复执行表达式
CHARSET() 返回参数的字符集
COERCIBILITY() 返回字符串参数的归类强制性值
COLLATION() 返回字符串参数的排序规则
CONNECTION_ID() 返回连接的连接ID(线程ID)
CURRENT_ROLE() 返回当前活动角色
CURRENT_USER() CURRENT_USER 经过身份验证的用户名和主机名
DATABASE() 返回默认(当前)数据库名称
FOUND_ROWS() 对于带有LIMIT子句的SELECT,返回的行数没有LIMIT子句
ICU_VERSION() ICU库版本
LAST_INSERT_ID() 最后一次INSERT的AUTOINCREMENT列的值
ROLES_GRAPHML() 返回表示内存角色子图的GraphML文档
ROW_COUNT() 行数已更新
SCHEMA() DATABASE()的同义词
SESSION_USER() USER()的同义词
SYSTEM_USER() USER()的同义词
USER() 客户端提供的用户名和主机名
VERSION() 返回表示MySQL服务器版本的字符串

  • BENCHMARK(count,expr)

    BENCHMARK() 函数 expr 重复 执行表达式 count 次数。 它可用于计算MySQL处理表达式的速度。 结果值始终为 0 预期用途来自 mysql 客户端,它报告查询执行时间:

    MySQL的> SELECT BENCHMARK(1000000,AES_ENCRYPT('hello','goodbye'));
    + ------------------------------------------------- -  +
    | BENCHMARK(1000000,AES_ENCRYPT('你好','再见'))|
    + ------------------------------------------------- -  +
    | 0 |
    + ------------------------------------------------- -  +
    1排(4.74秒)
    

    报告的时间是客户端的已用时间,而不是服务器端的CPU时间。 建议 BENCHMARK() 多次 执行 ,并根据服务器计算机的负载程度来解释结果。

    BENCHMARK() 用于测量标量表达式的运行时性能,这对您使用它和解释结果的方式有一些重要的影响:

    • 只能使用标量表达式。 虽然表达式可以是子查询,但它必须返回单个列,最多只返回一行。 例如, BENCHMARK(10, (SELECT * FROM t)) 如果表 t 具有多个列或多个行 则会失败

    • 执行 语句 时间与执行所 涉及的开销量不同。 这两个具有非常不同的执行配置文件,您不应期望它们花费相同的时间。 前者涉及解析器,优化器,表锁定和运行时评估 时间。 后者仅涉及运行时评估 SELECT expr N SELECT BENCHMARK(N, expr) N N 次,和所有其他组件只有一次。 已经分配的内存结构被重用,并且运行时优化(例如已经针对聚合函数评估的结果的本地缓存)可以改变结果。 BENCHMARK() 因此, 使用 通过给予该组件更多权重并消除 由网络,解析器,优化器等引入 噪声 来测量运行时组件的性能

  • CHARSET(str)

    返回字符串参数的字符集。

    MySQL的> SELECT CHARSET('abc');
            - >'utf8'
    MySQL的> SELECT CHARSET(CONVERT('abc' USING latin1));
            - >'latin1'
    MySQL的> SELECT CHARSET(USER());
            - >'utf8'
    
  • COERCIBILITY(str)

    返回字符串参数的排序规则强制性值。

    MySQL的> SELECT COERCIBILITY('abc' COLLATE utf8_swedish_ci);
            - > 0
    MySQL的> SELECT COERCIBILITY(USER());
            - > 3
    MySQL的> SELECT COERCIBILITY('abc');
            - > 4
    MySQL的> SELECT COERCIBILITY(1000);
            - > 5
    

    返回值具有下表中显示的含义。 较低的值具有较高的优先级。

    可压缩性 含义
    0 明确的整理 值与 COLLATE 条款
    1 没有整理 具有不同排序规则的字符串的连接
    2 隐式整理 列值,存储的例程参数或局部变量
    3 系统常数 USER() 回报价值
    4 COERCIBLE 文字字符串
    5 数字 数值或时间价值
    5 可忽略的 NULL 或者来自的表达式 NULL

    有关更多信息,请参见 第10.8.4节“表达式中的校对强制性”

  • COLLATION(str)

    返回字符串参数的排序规则。

    MySQL的> SELECT COLLATION('abc');
            - >'utf8_general_ci'
    MySQL的> SELECT COLLATION(_utf8mb4'abc');
            - >'utf8mb4_0900_ai_ci'
    MySQL的> SELECT COLLATION(_latin1'abc');
            - >'latin1_swedish_ci'
    
  • CONNECTION_ID()

    返回连接的连接ID(线程ID)。 每个连接都具有在当前连接的客户端集中唯一的ID。

    返回 CONNECTION_ID() 的值 ID INFORMATION_SCHEMA.PROCESSLIST 表中的 Id 列, SHOW PROCESSLIST 输出 PROCESSLIST_ID 列和Performance Schema threads 列中 显示的值类型相同

    MySQL的> SELECT CONNECTION_ID();
            - > 23786
    
  • CURRENT_ROLE()

    返回一个 utf8 字符串,其中包含当前会话的当前活动角色,以逗号分隔,或者 NONE 如果没有。 该值反映了 sql_quote_show_create 系统变量 的设置

    假设帐户被授予如下角色:

    GRANT'r1','r2'到'u1'@'localhost';
    将DEFAULT ROLE ALL设置为'u1'@'localhost';
    

    在会话中 u1 ,初始 CURRENT_ROLE() 值指定默认帐户角色。 使用以下 SET ROLE 更改:

    MySQL的> SELECT CURRENT_ROLE();
    + ------------------- +
    | CURRENT_ROLE()|
    + ------------------- +
    | `r1` @`%`,`r2` @`%`|
    + ------------------- +
    MySQL的> SET ROLE 'r1'; SELECT CURRENT_ROLE();
    + ---------------- +
    | CURRENT_ROLE()|
    + ---------------- +
    | `r1` @`%`|
    + ---------------- +
    
  • CURRENT_USER CURRENT_USER()

    返回服务器用于验证当前客户端的MySQL帐户的用户名和主机名组合。 此帐户确定您的访问权限。 返回值是 utf8 字符集中 的字符串

    值的值 CURRENT_USER() 可以与值不同 USER()

    MySQL的> SELECT USER();
            - >'davida @ localhost'
    MySQL的> SELECT * FROM mysql.user;
    错误1044:用户''@ localhost'拒绝访问
    数据库'mysql'
    MySQL的> SELECT CURRENT_USER();
            - >'@localhost'
    

    该示例说明尽管客户端指定了用户名 davida (由 USER() 函数 的值指示 ),但服务器使用匿名用户帐户对客户端进行身份验证(如 CURRENT_USER() 的空用户名部分所示 )。 可能出现的一种方式是授权表中没有列出帐户 davida

    在存储的程序或视图中, CURRENT_USER() 返回定义对象的用户的帐户(由其 DEFINER 值指定),除非使用该 SQL SECURITY INVOKER 特征进行 定义 在后一种情况下, CURRENT_USER() 返回对象的调用者。

    触发器和事件没有选项来定义 SQL SECURITY 特征,因此对于这些对象, CURRENT_USER() 返回定义对象的用户的帐户。 要返回调用者,请使用 USER() SESSION_USER()

    以下语句支持使用该 CURRENT_USER() 函数代替受影响的用户或定义者的名称(以及可能的主机); 在这种情况下, CURRENT_USER() 根据需要扩展:

    有关此扩展 CURRENT_USER() 对复制 的影响的信息 ,请参见 第17.4.1.8节“CURRENT_USER()的复制”

  • DATABASE()

    utf8 字符集中 的字符串形式返回默认(当前)数据库名称 如果没有默认数据库,则 DATABASE() 返回 NULL 在存储例程中,默认数据库是与例程关联的数据库,该数据库不一定与调用上下文中的默认数据库相同。

    MySQL的> SELECT DATABASE();
            - >'测试'
    

    如果没有默认数据库,则 DATABASE() 返回 NULL

  • FOUND_ROWS()

    注意

    SQL_CALC_FOUND_ROWS 查询修改和相应的 FOUND_ROWS() 功能已被弃用例如MySQL 8.0.17,并会在将来的MySQL版本中删除。 作为替代,考虑执行您的查询 LIMIT ,然后使用 COUNT(*) 和不 使用第二个查询 LIMIT 来确定是否有其他行。 例如,而不是这些查询:

    SELECT SQL_CALC_FOUND_ROWS * FROM tbl_nameWHERE id> 100 LIMIT 10;
    SELECT FOUND_ROWS();
    

    改为使用这些查询:

    SELECT * FROM tbl_nameWHERE id> 100 LIMIT 10;
    SELECT COUNT(*)WHERE id> 100;
    

    COUNT(*) 受到某些优化。 SQL_CALC_FOUND_ROWS 导致某些优化被禁用。

    一个 SELECT 语句可能包括一个 LIMIT 条款,限制服务器返回给客户端的行数。 在某些情况下,需要知道语句在没有的 LIMIT 情况下 返回了多少行 ,但是没有再次运行语句。 要获取此行计数,请 SQL_CALC_FOUND_ROWS SELECT 语句中 包含一个 选项 ,然后 以后调用 FOUND_ROWS()

    mysql> 
        - > 
    mysql>SELECT SQL_CALC_FOUND_ROWS * FROM tbl_nameWHERE id > 100 LIMIT 10;SELECT FOUND_ROWS();
    

    第二个 SELECT 返回一个数字,表示如果 SELECT 没有该 LIMIT 子句 ,第一个 将返回的 行数

    如果 SQL_CALC_FOUND_ROWS 最近成功的 SELECT 语句中 没有该 选项,则 FOUND_ROWS() 返回该 语句 返回的结果集中的行数。 如果语句包含 LIMIT 子句,则 FOUND_ROWS() 返回最多行数。 例如, FOUND_ROWS() 如果语句包含 LIMIT 10 ,则分别返回10或60 LIMIT 50, 10

    可用的行计数 FOUND_ROWS() 是暂时的,并且不会在语句后面的 SELECT SQL_CALC_FOUND_ROWS 语句 之后可用 如果您需要稍后参考该值,请将其保存:

    mysql> SELECT SQL_CALC_FOUND_ROWS * FROM ... ;
    mysql>SET @rows = FOUND_ROWS();
    

    如果您正在使用 SELECT SQL_CALC_FOUND_ROWS ,MySQL必须计算完整结果集中的行数。 但是,这比没有再次运行查询要快 LIMIT ,因为结果集不需要发送到客户端。

    SQL_CALC_FOUND_ROWS 并且 FOUND_ROWS() 在您想要限制查询返回的行数的情况下非常有用,但是在不再次运行查询的情况下也可以确定完整结果集中的行数。 一个示例是一个Web脚本,它显示一个分页显示,其中包含指向显示搜索结果其他部分的页面的链接。 使用 FOUND_ROWS() 可以确定结果的其余部分需要多少其他页面。

    语句 的使用 SQL_CALC_FOUND_ROWS FOUND_ROWS() 复杂性 UNION 比简单 SELECT 语句 更复杂 ,因为 LIMIT 可能出现在多个地方 UNION 它可以应用于 整个结果 SELECT 中的 单个 语句, 也可以应用于 UNION 全局 UNION 结果。

    SQL_CALC_FOUND_ROWS for 的意图 UNION 是它应该返回没有全局返回的行计数 LIMIT 使用的条件 SQL_CALC_FOUND_ROWS UNION 如下:

    • SQL_CALC_FOUND_ROWS 关键字必须出现在第一个 SELECT UNION

    • FOUND_ROWS() 仅当 UNION ALL 使用时 ,值 才是精确的 如果 UNION ALL 使用,则会发生重复删除,其值 FOUND_ROWS() 仅为近似值。

    • 如果no LIMIT 中存在 no UNION SQL_CALC_FOUND_ROWS 则忽略 函数并返回创建的临时表中的行数以进行处理 UNION

    除了此处描述的情况之外,行为 FOUND_ROWS() 是未定义的(例如,其值在 SELECT 语句失败后出现错误)。

    重要

    FOUND_ROWS() 使用基于语句的复制不能可靠地复制。 使用基于行的复制自动复制此功能。

  • ICU_VERSION()

    用于支持正则表达式操作的Unicode国际组件(ICU)库的版本(请参见 第12.5.2节“正则表达式” )。 此功能主要用于测试用例。

  • LAST_INSERT_ID() LAST_INSERT_ID(expr)

    如果没有参数,则 LAST_INSERT_ID() 返回一个 BIGINT UNSIGNED (64位)值,表示 AUTO_INCREMENT 由于最近执行的 INSERT 语句 成功为 列添加 的第一个自动生成的值 LAST_INSERT_ID() 如果没有成功插入行,则 保持不变。

    使用参数, LAST_INSERT_ID() 返回无符号整数。

    例如,在插入生成 AUTO_INCREMENT 的行之后 ,您可以获得如下值:

    MySQL的> SELECT LAST_INSERT_ID();
            - > 195
    

    当前正在执行的语句不会影响其值 LAST_INSERT_ID() 假设您 AUTO_INCREMENT 使用一个语句 生成一个 值,然后 LAST_INSERT_ID() 在多行 INSERT 语句中 引用 ,该行将行 插入到具有自己 AUTO_INCREMENT 的表中 LAST_INSERT_ID() 第二个陈述中 的价值 将保持稳定; 它的第二行和后一行的值不受先前行插入的影响。 (但是,如果将参考混合到 LAST_INSERT_ID() ,则效果未定义。) LAST_INSERT_ID(expr)

    如果前一个语句返回错误,则值为 LAST_INSERT_ID() undefined。 对于事务表,如果语句由于错误而回滚,则值为 LAST_INSERT_ID() undefined。 对于手动 ROLLBACK ,其值 LAST_INSERT_ID() 不会恢复到事务之前的值; 它仍然保持原样 ROLLBACK

    在存储例程(过程或函数)或触发器 LAST_INSERT_ID() 的主体内 更改的 值与 在这些对象的主体外执行的语句 更改方式相同。 LAST_INSERT_ID() 以下语句可以看出 存储的例程或触发器对其值的影响 取决于例程的类型:

    • 如果存储过程执行更改值的语句,则更改的值 LAST_INSERT_ID() 将由过程调用之后的语句看到。

    • 对于更改值的存储函数和触发器,当函数或触发器结束时,将恢复该值,因此后续语句将不会看到更改的值。

    生成的ID在 每个连接的基础上 在服务器中维护 这意味着函数返回给定客户端的 AUTO_INCREMENT 是为该客户端 影响 AUTO_INCREMENT 最新语句生成 的第一个 此值不受其他客户端的影响,即使它们生成 AUTO_INCREMENT 自己的值。 此行为可确保每个客户端都可以检索自己的ID,而无需关心其他客户端的活动,也无需锁定或事务。

    LAST_INSERT_ID() 如果将 AUTO_INCREMENT 设置 为非 魔术 值(即,不是 NULL 和不是 的值), 则不会更改 0

    重要

    如果您将使用一个多行 INSERT 的语句, LAST_INSERT_ID() 返回所产生的价值 第一次 插入的行 这样做的原因是可以轻松地重现 INSERT 与其他服务器 相同的 语句。

    例如:

    MySQL的> USE test;
    
    MySQL的> CREATE TABLE t (
           id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
           name VARCHAR(10) NOT NULL
           );
    
    MySQL的> INSERT INTO t VALUES (NULL, 'Bob');
    
    MySQL的> SELECT * FROM t;
    + ---- + ------ +
    | id | 名字|
    + ---- + ------ +
    | 1 | 鲍勃|
    + ---- + ------ +
    
    MySQL的> SELECT LAST_INSERT_ID();
    + ------------------ +
    | LAST_INSERT_ID()|
    + ------------------ +
    | 1 |
    + ------------------ +
    
    MySQL的> INSERT INTO t VALUES
           (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
    
    MySQL的> SELECT * FROM t;
    + ---- + ------ +
    | id | 名字|
    + ---- + ------ +
    | 1 | 鲍勃|
    | 2 | 玛丽|
    | 3 | 简|
    | 4 | 丽莎|
    + ---- + ------ +
    
    MySQL的> SELECT LAST_INSERT_ID();
    + ------------------ +
    | LAST_INSERT_ID()|
    + ------------------ +
    | 2 |
    + ------------------ +
    

    虽然第二个 INSERT 语句插入了三个新行 t ,但是为这些行中的第一行生成的ID是 2 ,并且这个值是由 LAST_INSERT_ID() 以下 SELECT 语句 返回的

    如果使用 INSERT IGNORE 并且忽略该行,则 LAST_INSERT_ID() 保持与当前值保持不变(如果连接尚未成功 INSERT 则返回0 ),对于非事务表, AUTO_INCREMENT 计数器不会递增。 对于 InnoDB 表, AUTO_INCREMENT 如果 innodb_autoinc_lock_mode 设置为 1 ,则 计数器会递增 2 ,如以下示例所示:

    MySQL的> USE test;
    
    MySQL的> SELECT @@innodb_autoinc_lock_mode;
    + ---------------------------- +
    | @@ innodb_autoinc_lock_mode |
    + ---------------------------- +
    | 1 |
    + ---------------------------- +
    
    MySQL的> CREATE TABLE `t` (
           `id` INT(11) NOT NULL AUTO_INCREMENT,
           `val` INT(11) DEFAULT NULL,
           PRIMARY KEY (`id`),
           UNIQUE KEY `i1` (`val`)
           ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    #插入两行
    
    MySQL的> INSERT INTO t (val) VALUES (1),(2);
    
    #with auto_increment_offset = 1,插入行
    #结果AUTO_INCREMENT值为3
    
    MySQL的> SHOW CREATE TABLE t\G
    *************************** 1。排******************** *******
           表:t
    创建表:CREATE TABLE`t`(
      `id` int(11)NOT NULL AUTO_INCREMENT,
      `val` int(11)DEFAULT NULL,
      PRIMARY KEY(`id`),
      独特的钥匙`i1`(`val`)
    )ENGINE = InnoDB AUTO_INCREMENT = 3 DEFAULT CHARSET = latin1
    
    #LAST_INSERT_ID()返回第一个自动生成的
    为AUTO_INCREMENT列成功插入的#value
    
    MySQL的> SELECT LAST_INSERT_ID();
    + ------------------ +
    | LAST_INSERT_ID()|
    + ------------------ +
    | 1 |
    + ------------------ +
    
    #尝试插入重复行失败但忽略错误   
    
    MySQL的> INSERT IGNORE INTO t (val) VALUES (1),(2);
    查询正常,0行受影响(0.00秒)
    记录:2个重复:2个警告:0
    
    #with innodb_autoinc_lock_mode = 1,AUTO_INCREMENT计数器
    对于忽略的行,#递增
    
    MySQL的> SHOW CREATE TABLE t\G
    *************************** 1。排******************** *******
           表:t
    创建表:CREATE TABLE`t`(
      `id` int(11)NOT NULL AUTO_INCREMENT,
      `val` int(11)DEFAULT NULL,
      PRIMARY KEY(`id`),
      独特的钥匙`i1`(`val`)
    )ENGINE = InnoDB AUTO_INCREMENT = 5 DEFAULT CHARSET = latin1
    
    #LAST_INSERT_ID未更改,因为前一个插入不成功
    
    MySQL的> SELECT LAST_INSERT_ID();
    + ------------------ +
    | LAST_INSERT_ID()|
    + ------------------ +
    | 1 |
    + ------------------ +
    

    有关更多信息,请参见 第15.6.1.4节“InnoDB中的AUTO_INCREMENT处理”

    如果 expr 作为参数给出,则参数 LAST_INSERT_ID() 的值由函数返回,并记住作为要返回的下一个值 LAST_INSERT_ID() 这可以用来模拟序列:

    1. 创建一个表来保存序列计数器并初始化它:

      mysql> CREATE TABLE sequence (id INT NOT NULL);
      mysql>INSERT INTO sequence VALUES (0);
      
    2. 使用该表生成如下序列号:

      mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
      mysql>SELECT LAST_INSERT_ID();
      

      UPDATE 语句递增序列计数器并使下一次调用 LAST_INSERT_ID() 返回更新的值。 SELECT 语句检索该值。 mysql_insert_id() C API函数也可以用于获取价值。 请参见 第28.7.7.38节“mysql_insert_id()”

    您可以在不调用的情况下生成序列 LAST_INSERT_ID() ,但以这种方式使用函数的实用程序是ID值在服务器中作为最后自动生成的值进行维护。 它是多用户安全的,因为多个客户端可以发出 UPDATE 语句并使用 SELECT 语句(或 mysql_insert_id() 获取自己的序列值 ,而不会影响或受到生成其自己的序列值的其他客户端的影响。

    请注意, mysql_insert_id() 仅在 语句 INSERT UPDATE 语句 之后更新 ,因此 在执行其他SQL语句(如 或) 之后, 无法使用C API函数来检索值 LAST_INSERT_ID(expr) SELECT SET

  • ROLES_GRAPHML()

    返回 utf8 包含表示内存角色子图的GraphML文档 字符串。 ROLE_ADMIN SUPER 特权才能看到的内容 <graphml> 元素。 否则,结果只显示一个空元素:

    MySQL的> SELECT ROLES_GRAPHML();
    + ------------------------------------------------- -  +
    | ROLES_GRAPHML()|
    + ------------------------------------------------- -  +
    | <?xml version =“1.0”encoding =“UTF-8”?> <graphml /> |
    + ------------------------------------------------- -  +
    
  • ROW_COUNT()

    ROW_COUNT() 返回一个值,如下所示:

    • DDL语句:0。这适用于诸如 CREATE TABLE 或的 语句 DROP TABLE

    • SELECT 以下之外的 DML语句 :受影响的行数。 这适用于报表等 UPDATE INSERT DELETE (如前),但现在还声明,如 ALTER TABLE LOAD DATA

    • SELECT :如果语句返回结果集,则返回-1;如果不返回,则返回 受影响 的行数 例如,for SELECT * FROM t1 ROW_COUNT() 返回-1。 For 返回写入文件的行数。 SELECT * FROM t1 INTO OUTFILE 'file_name' ROW_COUNT()

    • SIGNAL 陈述:0。

    对于 UPDATE 语句,默认情况下受影响的行值是实际更改的行数。 如果 在连接到 mysqld 指定了 CLIENT_FOUND_ROWS 标志 ,则受影响的行值是 找到 的行数 ; 也就是说,与 条款 相匹配 mysql_real_connect() WHERE

    对于 REPLACE 语句,如果新行替换旧行,则affected-rows值为2,因为在这种情况下,在删除副本后插入了一行。

    对于 INSERT ... ON DUPLICATE KEY UPDATE 语句,如果将行作为新行插入,则每行的受影响行值为1;如果更新现有行,则为2,如果现有行设置为其当前值,则为0。 如果指定 CLIENT_FOUND_ROWS 标志,则如果将现有行设置为其当前值,则affected-rows值为1(不为0)。

    ROW_COUNT() 值类似于 mysql_affected_rows() C API函数中 的值 以及 mysql 客户端在语句执行后显示 的行计数

    MySQL的> INSERT INTO t VALUES(1),(2),(3);
    查询OK,3行受影响(0.00秒)
    记录:3个重复:0个警告:0
    
    MySQL的> SELECT ROW_COUNT();
    + ------------- +
    | ROW_COUNT()|
    + ------------- +
    | 3 |
    + ------------- +
    1排(0.00秒)
    
    MySQL的> DELETE FROM t WHERE i IN(1,2);
    查询正常,2行受影响(0.00秒)
    
    MySQL的> SELECT ROW_COUNT();
    + ------------- +
    | ROW_COUNT()|
    + ------------- +
    | 2 |
    + ------------- +
    1排(0.00秒)
    
    重要

    ROW_COUNT() 使用基于语句的复制不能可靠地复制。 使用基于行的复制自动复制此功能。

  • SCHEMA()

    此功能是其同义词 DATABASE()

  • SESSION_USER()

    SESSION_USER() 是...的同义词 USER()

  • SYSTEM_USER()

    SYSTEM_USER() 是...的同义词 USER()

    注意

    SYSTEM_USER() 功能与 SYSTEM_USER 特权不同。 前者返回当前的MySQL帐户名。 后者区分系统用户和常规用户帐户类别(请参见 第6.2.11节“帐户类别” )。

  • USER()

    utf8 字符集中 的字符串形式返回当前MySQL用户名和主机名

    MySQL的> SELECT USER();
            - >'davida @ localhost'
    

    该值表示您在连接到服务器时指定的用户名,以及您连接的客户端主机。 该值可以不同于 CURRENT_USER()

  • VERSION()

    返回表示MySQL服务器版本的字符串。 该字符串使用 utf8 字符集。 除版本号外,该值可能还有一个后缀。 见的描述 version 在系统变量 第5.1.8节,“服务器系统变量”

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

    MySQL的> SELECT VERSION();
            - >'8.0.18-standard'
    

12.16空间分析功能

MySQL提供了对空间数据执行各种操作的功能。 这些功能可以根据它们执行的操作类型分为几个主要类别:

  • 以各种格式创建几何的函数(WKT,WKB,内部)

  • 在格式之间转换几何的函数

  • 访问几何的定性或定量属性的函数

  • 描述两个几何之间关系的函数

  • 从现有几何创建新几何的函数

有关MySQL支持使用空间数据的一般背景,请参见 第11.5节“空间数据类型”

12.16.1空间函数参考

下表列出了每个空间函数,并提供了每个空间函数的简短描述。

表12.20空间函数

名称 描述
GeomCollection() 从几何构造几何集合
GeometryCollection() 从几何构造几何集合
LineString() 从Point值构造LineString
MBRContains() 一个几何的MBR是否包含另一个几何的MBR
MBRCoveredBy() 一个MBR是否被另一个MBR覆盖
MBRCovers() 一个MBR是否涵盖另一个MBR
MBRDisjoint() 两个几何形状的MBR是否不相交
MBREquals() 两个几何的MBR是否相等
MBRIntersects() 两个几何的MBR是否相交
MBROverlaps() 两个几何的MBR是否重叠
MBRTouches() 两种几何形状的MBR是否接触
MBRWithin() 一个几何的MBR是否在另一个几何的MBR内
MultiLineString() 从LineString值构造MultiLineString
MultiPoint() 从Point值构造MultiPoint
MultiPolygon() 从Polygon值构造MultiPolygon
Point() 从坐标构造点
Polygon() 从LineString参数构造多边形
ST_Area() 返回Polygon或MultiPolygon区域
ST_AsBinary() ST_AsWKB() 从内部几何格式转换为WKB
ST_AsGeoJSON() 从几何体生成GeoJSON对象
ST_AsText() ST_AsWKT() 从内部几何格式转换为WKT
ST_Buffer() 返回距离几何体的给定距离内的点的几何
ST_Buffer_Strategy() 为ST_Buffer()生成策略选项
ST_Centroid() 返回质心作为一个点
ST_Contains() 一个几何是否包含另一个
ST_ConvexHull() 返回几何体的凸包
ST_Crosses() 一个几何是否与另一个几何相交
ST_Difference() 两个几何的返回点集差异
ST_Dimension() 几何尺寸
ST_Disjoint() 一个几何是否与另一个几何脱节
ST_Distance() 一个几何与另一个几何的距离
ST_Distance_Sphere() 两个几何形状之间的最小地球距离
ST_EndPoint() LineString的终点
ST_Envelope() 返回几何的MBR
ST_Equals() 一个几何是否与另一个几何相等
ST_ExteriorRing() 返回Polygon的外环
ST_GeoHash() 产生geohash值
ST_GeomCollFromText() ST_GeometryCollectionFromText() ST_GeomCollFromTxt() 从WKT返回几何集合
ST_GeomCollFromWKB() ST_GeometryCollectionFromWKB() 从WKB返回几何集合
ST_GeometryN() 从几何集合中返回第N个几何
ST_GeometryType() 返回几何类型的名称
ST_GeomFromGeoJSON() 从GeoJSON对象生成几何
ST_GeomFromText() ST_GeometryFromText() 从WKT返回几何
ST_GeomFromWKB() ST_GeometryFromWKB() 从WKB返回几何
ST_InteriorRingN() 返回Polygon的第N个内环
ST_Intersection() 返回点设置两个几何的交集
ST_Intersects() 一个几何是否与另一个相交
ST_IsClosed() 几何是否封闭且简单
ST_IsEmpty() 占位符功能
ST_IsSimple() 几何是否简单
ST_IsValid() 几何是否有效
ST_LatFromGeoHash() 从geohash值返回纬度
ST_Latitude() 返回Point的纬度
ST_Length() 返回LineString的长度
ST_LineFromText() ST_LineStringFromText() 从WKT构造LineString
ST_LineFromWKB() ST_LineStringFromWKB() 从WKB构造LineString
ST_LongFromGeoHash() 从geohash值返回经度
ST_Longitude() 返回Point的经度
ST_MakeEnvelope() 两点左右的矩形
ST_MLineFromText() ST_MultiLineStringFromText() 从WKT构造MultiLineString
ST_MLineFromWKB() ST_MultiLineStringFromWKB() 从WKB构造MultiLineString
ST_MPointFromText() ST_MultiPointFromText() 从WKT构造MultiPoint
ST_MPointFromWKB() ST_MultiPointFromWKB() 从WKB构造MultiPoint
ST_MPolyFromText() ST_MultiPolygonFromText() 从WKT构造MultiPolygon
ST_MPolyFromWKB() ST_MultiPolygonFromWKB() 从WKB构造MultiPolygon
ST_NumGeometries() 返回几何集合中的几何数量
ST_NumInteriorRing() ST_NumInteriorRings() 返回多边形内圈的数量
ST_NumPoints() 返回LineString中的点数
ST_Overlaps() 一个几何是否与另一个重叠
ST_PointFromGeoHash() 将geohash值转换为POINT值
ST_PointFromText() 从WKT构建点
ST_PointFromWKB() 从WKB构造点
ST_PointN() 从LineString返回第N个点
ST_PolyFromText() ST_PolygonFromText() 从WKT构造多边形
ST_PolyFromWKB() ST_PolygonFromWKB() 从WKB构造多边形
ST_Simplify() 返回简化几何
ST_SRID() 返回几何的空间参考系统ID
ST_StartPoint() LineString的起始点
ST_SwapXY() 交换X / Y坐标的返回参数
ST_SymDifference() 返回点设置两个几何的对称差异
ST_Touches() 一个几何是否接触另一个
ST_Transform() 变换几何的坐标
ST_Union() 返回点集两个几何的并集
ST_Validate() 返回验证的几何体
ST_Within() 一个几何是否在另一个之内
ST_X() 返回Point的X坐标
ST_Y() 返回Point的Y坐标

12.16.2空间函数的参数处理

空间值或几何具有 第11.5.2.2节“几何类”中 描述的属性 以下讨论列出了一般空间函数参数处理特征。 特定函数或函数组可能具有其他参数处理特性,如发生这些函数描述的部分所述。

空间函数仅针对有效几何值定义。

几何的空间参考标识符(SRID)标识定义几何的坐标空间。 在MySQL中,SRID值是与几何值关联的整数。 最大可用SRID值为2 32 -1。 如果给出更大的值,则仅使用低32位。

SRID 0表示无限平坦的笛卡尔平面,其轴没有单位。 要确保SRID 0行为,请使用SRID 0创建几何值。如果未指定SRID,则SRID 0是新几何值的默认值。

任何空间函数生成的几何值都会继承几何参数的SRID。

采用多个几何参数的空间函数要求这些参数具有相同的SRID值(即,低32位中的相同值)。 假设相等的SRID,空间函数在执行相等检查后不对它们执行任何操作; 使用笛卡尔坐标(SRID 0)隐式处理几何值。 如果空间函数返回 ER_GIS_DIFFERENT_SRIDS ,则意味着几何参数并非都具有相同的SRID。 您必须修改它们以具有相同的SRID。

开放地理空间联盟 准则要求输入多边形已经被关闭,因此未闭合的多边形拒绝为无效,而不是被关闭。

空几何集合处理如下:可以将空WKT输入几何集合指定为 'GEOMETRYCOLLECTION()' 这也是由生成空几何集合的空间操作产生的输出WKT。

在解析嵌套几何集合期间,集合被展平,其基本组件用于各种GIS操作以计算结果。 这为用户提供了额外的灵活性,因为不必担心几何数据的唯一性。 嵌套几何集合可以从嵌套的GIS函数调用生成,而不必首先显式展平。

12.16.3从WKT值创建几何值的函数

这些函数将知名文本(WKT)表示和可选的空间参考系统标识符(SRID)作为参数。 它们返回相应的几何体。 有关WKT格式的说明,请参阅 熟知文本(WKT)格式

本节中的函数检测笛卡尔或地理空间参照系(SRS)中的参数,并返回适合SRS的结果。

ST_GeomFromText() 接受任何几何类型的WKT值作为其第一个参数。 其他函数提供特定于类型的构造函数,用于构造每种几何类型的几何值。

诸如 ST_MPointFromText() ST_GeomFromText() 接受WKT格式的 MultiPoint 表示的 函数允许值内的各个点被括号括起来。 例如,以下两个函数调用都是有效的:

ST_MPointFromText('MULTIPOINT(1 1,2 2,3 3)')
ST_MPointFromText('MULTIPOINT((1 1),(2 2),(3 3))')

比如函数 ST_GeomFromText() 接受WKT几何集合参数了解双方开放地理信息系统 'GEOMETRYCOLLECTION EMPTY' 标准语法和MySQL的 'GEOMETRYCOLLECTION()' 非标准语法。 如函数 ST_AsWKT() 产生WKT值产生 'GEOMETRYCOLLECTION EMPTY' 标准语法:

mysql> SET @s1 = ST_GeomFromText('GEOMETRYCOLLECTION()');
mysql> SET @s2 = ST_GeomFromText('GEOMETRYCOLLECTION EMPTY');
mysql>SELECT ST_AsWKT(@s1), ST_AsWKT(@s2);
+ -------------------------- + ---------------------- ---- +
| ST_AsWKT(@ s1)| ST_AsWKT(@ s2)|
+ -------------------------- + ---------------------- ---- +
| GEOMETRYCOLLECTION EMPTY | GEOMETRYCOLLECTION EMPTY |
+ -------------------------- + ---------------------- ---- +

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果任何几何参数是 NULL 或者不是语法上格式良好的几何,或者如果SRID参数是 NULL ,则返回值为 NULL

  • 默认情况下,地理坐标(纬度,经度)按几何参数的空间参考系统指定的顺序进行解释。 options 可以给出 可选 参数来覆盖默认轴顺序。 options 由逗号分隔列表组成 唯一 允许的值 ,允许值为 (默认值)。 key=value key axis-order lat-long long-lat srid-defined

    如果 options 参数是 NULL ,则返回值为 NULL 如果 options 参数无效,则会发生错误以指示原因。

  • 如果SRID参数引用未定义的空间参考系统(SRS), ER_SRS_NOT_FOUND 则会发生错误。

  • 对于地理SRS几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

这些函数可用于从WKT值创建几何:

12.16.4从WKB值创建几何值的函数

这些函数将参数a作为 BLOB 包含已知二进制(WKB)表示的参数,并且可选地包含空间参考系统标识符(SRID)。 它们返回相应的几何体。 有关WKB格式的说明,请参见 熟知二进制(WKB)格式

本节中的函数检测笛卡尔或地理空间参照系(SRS)中的参数,并返回适合SRS的结果。

ST_GeomFromWKB() 接受任何几何类型的WKB值作为其第一个参数。 其他函数提供特定于类型的构造函数,用于构造每种几何类型的几何值。

在MySQL 8.0之前,这些函数还接受了 第12.16.5节“创建几何值的MySQL特定函数”中 的函数返回的几何对象 不再允许使用几何参数并产生错误。 要将调用从使用几何参数迁移到使用WKB参数,请遵循以下准则:

  • 重写结构,如 ST_GeomFromWKB(Point(0, 0)) 作为 Point(0, 0)

  • 重写诸如 ST_GeomFromWKB(Point(0, 0), 4326) as ST_SRID(Point(0, 0), 4326) ST_GeomFromWKB(ST_AsWKB(Point(0, 0)), 4326) 。之类的 结构

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果是WKB或SRID参数 NULL ,则返回值为 NULL

  • 默认情况下,地理坐标(纬度,经度)按几何参数的空间参考系统指定的顺序进行解释。 options 可以给出 可选 参数来覆盖默认轴顺序。 options 由逗号分隔列表组成 唯一 允许的值 ,允许值为 (默认值)。 key=value key axis-order lat-long long-lat srid-defined

    如果 options 参数是 NULL ,则返回值为 NULL 如果 options 参数无效,则会发生错误以指示原因。

  • 如果SRID参数引用未定义的空间参考系统(SRS), ER_SRS_NOT_FOUND 则会发生错误。

  • 对于地理SRS几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

这些函数可用于从WKB值创建几何:

12.16.5创建几何值的特定于MySQL的函数

MySQL提供了一组有用的非标准函数来创建几何值。 本节中描述的函数是OpenGIS规范的MySQL扩展。

这些函数从WKB值或几何对象作为参数生成几何对象。 如果任何参数不是正确对象类型的正确WKB或几何表示,则返回值为 NULL

例如,您可以将几何返回值 Point() 直接插入到 POINT 列中:

INSERT INTO t1(pt_col)VALUES(Point(1,2));

12.16.6几何格式转换函数

MySQL支持本节中列出的函数,用于将几何值从内部几何格式转换为WKT或WKB格式,或者用于交换X和Y坐标的顺序。

还有将字符串从WKT或WKB格式转换为内部几何格式的函数。 请参见 第12.16.3节“从WKT值创建几何值的函数” 第12.16.4节“从WKB值创建几何值的函数”

比如函数 ST_GeomFromText() 接受WKT几何集合参数了解双方开放地理信息系统 'GEOMETRYCOLLECTION EMPTY' 标准语法和MySQL的 'GEOMETRYCOLLECTION()' 非标准语法。 生成空几何集合的另一种方法是通过 GeometryCollection() 不带参数 调用 如函数 ST_AsWKT() 产生WKT值产生 'GEOMETRYCOLLECTION EMPTY' 标准语法:

mysql> SET @s1 = ST_GeomFromText('GEOMETRYCOLLECTION()');
mysql> SET @s2 = ST_GeomFromText('GEOMETRYCOLLECTION EMPTY');
mysql>SELECT ST_AsWKT(@s1), ST_AsWKT(@s2);
+ -------------------------- + ---------------------- ---- +
| ST_AsWKT(@ s1)| ST_AsWKT(@ s2)|
+ -------------------------- + ---------------------- ---- +
| GEOMETRYCOLLECTION EMPTY | GEOMETRYCOLLECTION EMPTY |
+ -------------------------- + ---------------------- ---- +
MySQL的> SELECT ST_AsWKT(GeomCollection());
+ ---------------------------- +
| ST_AsWKT(GeomCollection())|
+ ---------------------------- +
| GEOMETRYCOLLECTION EMPTY |
+ ---------------------------- +

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL ,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数位于未定义的空间参照系中,则轴将按照它们在几何图形中出现的顺序输出,并发出 ER_WARN_SRS_NOT_FOUND_AXIS_ORDER 警告。

  • 默认情况下,地理坐标(纬度,经度)按几何参数的空间参考系统指定的顺序进行解释。 options 可以给出 可选 参数来覆盖默认轴顺序。 options 由逗号分隔列表组成 唯一 允许的值 ,允许值为 (默认值)。 key=value key axis-order lat-long long-lat srid-defined

    如果 options 参数是 NULL ,则返回值为 NULL 如果 options 参数无效,则会发生错误以指示原因。

  • 否则,返回值为非 NULL

这些函数可用于格式转换或坐标交换:

  • ST_AsBinary(g [, options]) ST_AsWKB(g [, options])

    将内部几何格式的值转换为其WKB表示并返回二进制结果。

    函数返回值具有应用于几何参数的空间参考系统指定的顺序的地理坐标(纬度,经度)。 options 可以给出 可选 参数来覆盖默认轴顺序。

    ST_AsBinary() ST_AsWKB() 按照本节的介绍中的描述处理它们的参数。

    mysql> SET @g = ST_LineFromText('LINESTRING(0 5,5 10,10 15)', 4326);
    mysql>SELECT ST_AsText(ST_GeomFromWKB(ST_AsWKB(@g)));
    + ----------------------------------------- +
    | ST_AsText(ST_GeomFromWKB(ST_AsWKB(@g)))|
    + ----------------------------------------- +
    | LINESTRING(5 0,10 5,15 10)|
    + ----------------------------------------- +
    MySQL的> SELECT ST_AsText(ST_GeomFromWKB(ST_AsWKB(@g, 'axis-order=long-lat')));
    + ------------------------------------------------- --------------- +
    | ST_AsText(ST_GeomFromWKB(ST_AsWKB(@ g,'axis-order = long-lat')))|
    + ------------------------------------------------- --------------- +
    | LINESTRING(0 5,5 10,10 15)|
    + ------------------------------------------------- --------------- +
    MySQL的> SELECT ST_AsText(ST_GeomFromWKB(ST_AsWKB(@g, 'axis-order=lat-long')));
    + ------------------------------------------------- --------------- +
    | ST_AsText(ST_GeomFromWKB(ST_AsWKB(@ g,'axis-order = lat-long')))|
    + ------------------------------------------------- --------------- +
    | LINESTRING(5 0,10 5,15 10)|
    + ------------------------------------------------- --------------- +
    
  • ST_AsText(g [, options]) ST_AsWKT(g [, options])

    将内部几何格式的值转换为其WKT表示形式并返回字符串结果。

    函数返回值具有应用于几何参数的空间参考系统指定的顺序的地理坐标(纬度,经度)。 options 可以给出 可选 参数来覆盖默认轴顺序。

    ST_AsText() ST_AsWKT() 按照本节的介绍中的描述处理它们的参数。

    mysql> SET @g = 'LineString(1 1,2 2,3 3)';
    mysql>SELECT ST_AsText(ST_GeomFromText(@g));
    + -------------------------------- +
    | ST_AsText(ST_GeomFromText(@g))|
    + -------------------------------- +
    | LINESTRING(1 1,2 2,3 3)|
    + -------------------------------- +
    

    输出为 MultiPoint 值的 包括每个点周围的括号。 例如:

    
    MySQL的> SELECT ST_AsText(ST_GeomFromText(@mp));
    + --------------------------------- +
    | ST_AsText(ST_GeomFromText(@mp))|
    + --------------------------------- +
    | MULTIPOINT((1 1),(2 2),(3 3))|
    + --------------------------------- +
    
  • ST_SwapXY(g)

    接受内部几何格式的参数,交换几何中每个坐标对的X和Y值,并返回结果。

    ST_SwapXY() 处理其参数,如本节的介绍中所述。

    mysql> SET @g = ST_LineFromText('LINESTRING(0 5,5 10,10 15)');
    mysql>SELECT ST_AsText(@g);
    + ---------------------------- +
    | ST_AsText(@g)|
    + ---------------------------- +
    | LINESTRING(0 5,5 10,10 15)|
    + ---------------------------- +
    MySQL的> SELECT ST_AsText(ST_SwapXY(@g));
    + ---------------------------- +
    | ST_AsText(ST_SwapXY(@g))|
    + ---------------------------- +
    | LINESTRING(5 0,10 5,15 10)|
    + ---------------------------- +
    

12.16.7几何属性函数

属于该组的每个函数都将几何值作为其参数,并返回几何的一些定量或定性属性。 某些函数限制其参数类型。 NULL 如果参数的几何类型不正确,则 返回此类函数 例如, 如果对象类型既不是 也不 ,则 ST_Area() 返回polygon函数 NULL Polygon MultiPolygon

12.16.7.1一般几何属性函数

本节中列出的函数不限制其参数并接受任何类型的几何值。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL ,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 如果任何SRID参数不在32位无符号整数的范围内, ER_DATA_OUT_OF_RANGE 则会发生错误。

  • 如果任何SRID参数引用未定义的SRS, ER_SRS_NOT_FOUND 则会发生错误。

  • 否则,返回值为非 NULL

这些函数可用于获取几何属性:

  • ST_Dimension(g)

    返回几何值的固有尺寸 g 尺寸可以是-1,0,1或2.这些值的含义在 第11.5.2.2节“几何类”中给出

    ST_Dimension() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_Dimension(ST_GeomFromText('LineString(1 1,2 2)'));
    + ------------------------------------------------- ----- +
    | ST_Dimension(ST_GeomFromText('LineString(1 1,2 2)'))|
    + ------------------------------------------------- ----- +
    | 1 |
    + ------------------------------------------------- ----- +
    
  • ST_Envelope(g)

    返回几何值的最小边界矩形(MBR) g 结果将返回 Polygon 为由边界框的角点定义 值:

    POLYGON((MINX MINY,MAXX MINY,MAXX MAXY,MINX MAXY,MINX MINY))
    
    MySQL的> SELECT ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,2 2)')));
    + ------------------------------------------------- --------------- +
    | ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,2 2)')))|
    + ------------------------------------------------- --------------- +
    | POLYGON((1 1,2 1,2 2,1 2,1 1))|
    + ------------------------------------------------- --------------- +
    

    如果参数是点或垂直或水平线段, ST_Envelope() 返回点或线段作为其MBR,而不是返回无效多边形:

    MySQL的> SELECT ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,1 2)')));
    + ------------------------------------------------- --------------- +
    | ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,1 2)')))|
    + ------------------------------------------------- --------------- +
    | LINESTRING(1 1,1 2)|
    + ------------------------------------------------- --------------- +
    

    ST_Envelope() 处理其参数,如本节的介绍中所述,但有以下例外:

  • ST_GeometryType(g)

    返回二进制字符串,指示几何实例所属的几何类型的名称 g 该名称对应于一个可实例化的 Geometry 子类。

    ST_GeometryType() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_GeometryType(ST_GeomFromText('POINT(1 1)'));
    + ------------------------------------------------ +
    | ST_GeometryType(ST_GeomFromText('POINT(1 1)'))|
    + ------------------------------------------------ +
    | 要点|
    + ------------------------------------------------ +
    
  • ST_IsEmpty(g)

    此函数是占位符,对于空几何集合值返回1,否则返回0。

    唯一有效的空几何体以空几何集合值的形式表示。 MySQL不支持GIS EMPTY POINT EMPTY

    ST_IsEmpty() 处理其参数,如本节的介绍中所述。

  • ST_IsSimple(g)

    如果 g 根据ISO SQL / MM第3部分:空间 标准 ,几何值 很简单, 则返回1 ST_IsSimple() 如果参数不简单,则返回0。

    第11.5.2节“OpenGIS几何模型”中 给出的可实例化几何类的描述 包括导致类实例被分类为不简单的特定条件。

    ST_IsSimple() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 如果几何体具有经度或纬度超出范围的地理SRS,则会发生错误:

      显示的范围以度为单位。 由于浮点运算,精确的范围限制略有偏差。

  • ST_SRID(g[, srid])

    使用表示有效几何对象的单个参数 g ST_SRID() 返回一个整数,指示与之关联的空间参考系统(SRS)的ID g

    使用表示有效SRID值的可选第二个参数, ST_SRID() 返回与其第一个参数具有相同类型的对象,其SRID值等于第二个参数。 这只设置对象的SRID值; 它不执行任何坐标值的转换。

    ST_SRID() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 对于单参数语法, ST_SRID() 即使它引用未定义的SRS,也会返回几何SRID。 一个 ER_SRS_NOT_FOUND 不会发生错误。

    ST_SRID(g, target_srid) 并且 不同如下: ST_Transform(g, target_srid)

    • ST_SRID() 更改几何SRID值而不转换其坐标。

    • ST_Transform() 除了更改其SRID值之外,还会转换几何坐标。

    mysql> SET @g = ST_GeomFromText('LineString(1 1,2 2)', 0);
    mysql>SELECT ST_SRID(@g);
    + ------------- +
    | ST_SRID(@g)|
    + ------------- +
    | 0 |
    + ------------- +
    mysql> SET @g = ST_SRID(@g, 4326);
    mysql>SELECT ST_SRID(@g);
    + ------------- +
    | ST_SRID(@g)|
    + ------------- +
    | 4326 |
    + ------------- +
    

    通过传递 ST_SRID() 用于创建空间值的MySQL特定函数之一的结果以及SRID值, 可以在特定SRID中创建几何 例如:

    SET @ g1 = ST_SRID(Point(1,1),4326);
    

    但是,该方法在SRID 0中创建几何,然后将其强制转换为SRID 4326(WGS 84)。 一个更好的选择是使用正确的空间参考系统创建几何体。 例如:

    SET @ g1 = ST_PointFromText('POINT(1 1)',4326);
    SET @ g1 = ST_GeomFromText('POINT(1 1)',4326);
    

    双参数形式 ST_SRID() 对于纠正或更改具有不正确SRID的几何的SRS等任务非常有用。

12.16.7.2点属性函数

A Point 由X和Y坐标组成,可以分别使用 ST_X() ST_Y() 函数获得。 这些函数还允许使用可选的第二个参数来指定X或Y坐标值,在这种情况下,函数结果是 Point 来自第一个参数 对象,其中相应的坐标被修改为等于第二个参数。

对于 Point 具有地理空间参考系统(SRS)的对象,可以分别使用 ST_Longitude() ST_Latitude() 函数 获得经度和纬度 这些函数还允许指定经度或纬度值的可选第二个参数,在这种情况下,函数结果是 Point 第一个参数中 对象,其经度或纬度被修改为等于第二个参数。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL ,则返回值为 NULL

  • 如果任何几何参数是有效几何但不是 Point 对象, ER_UNEXPECTED_GEOMETRY_TYPE 则会发生错误。

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 如果提供了一种X或Y坐标的参数和值是 -inf +inf ,或 NaN ,一个 ER_DATA_OUT_OF_RANGE 发生错误。

  • 如果经度或纬度参数超出范围,则会发生错误:

    显示的范围以度为单位。 由于浮点运算,精确的范围限制略有偏差。

  • 否则,返回值为非 NULL

这些函数可用于获取点属性:

  • ST_Latitude(p [, new_latitude_val])

    使用表示 具有地理空间参照系(SRS) 的有效 Point 对象 的单个参数 p ST_Latitude() 将纬度值 p 作为双精度数返回。

    使用表示有效纬度值的可选第二个参数, ST_Latitude() 返回一个 Point 对象,如第一个参数,其纬度等于第二个参数。

    ST_Latitude() 处理其参数,如本节的介绍中所述,另外如果 Point 对象有效但没有地理SRS, ER_SRS_NOT_GEOGRAPHIC 则会发生错误。

    mysql> SET @pt = ST_GeomFromText('POINT(45 90)', 4326);
    mysql>SELECT ST_Latitude(@pt);
    + ------------------ +
    | ST_Latitude(@pt)|
    + ------------------ +
    | 45 |
    + ------------------ +
    MySQL的> SELECT ST_AsText(ST_Latitude(@pt, 10));
    + --------------------------------- +
    | ST_AsText(ST_Latitude(@ ct,10))|
    + --------------------------------- +
    | 要点(10 90)|
    + --------------------------------- +
    

    此功能已在MySQL 8.0.12中添加。

  • ST_Longitude(p [, new_longitude_val])

    使用表示 具有地理空间参照系(SRS) 的有效 Point 对象 的单个参数 p ST_Longitude() 将经度值 p 作为双精度数返回。

    使用表示有效经度值的可选第二个参数, ST_Longitude() 返回一个 Point 对象,如第一个参数,其经度等于第二个参数。

    ST_Longitude() 处理其参数,如本节的介绍中所述,另外如果 Point 对象有效但没有地理SRS, ER_SRS_NOT_GEOGRAPHIC 则会发生错误。

    mysql> SET @pt = ST_GeomFromText('POINT(45 90)', 4326);
    mysql>SELECT ST_Longitude(@pt);
    + ------------------- +
    | ST_Longitude(@pt)|
    + ------------------- +
    | 90 |
    + ------------------- +
    MySQL的> SELECT ST_AsText(ST_Longitude(@pt, 10));
    + ---------------------------------- +
    | ST_AsText(ST_Longitude(@pt,10))|
    + ---------------------------------- +
    | 要点(45 10)|
    + ---------------------------------- +
    

    此功能已在MySQL 8.0.12中添加。

  • ST_X(p[, new_x_val])

    使用表示有效 Point 对象 的单个参数 p ST_X() 将X坐标值 p 作为双精度数返回。 从MySQL 8.0.12开始,X坐标被认为是指 Point 空间参照系(SRS)定义 中首先出现的轴

    使用可选的第二个参数, ST_X() 返回一个 Point 对象,如第一个参数,其X坐标等于第二个参数。 从MySQL 8.0.12开始,如果 Point 对象具有地理SRS,则第二个参数必须在经度或纬度值的适当范围内。

    ST_X() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_X(Point(56.7, 53.34));
    + -------------------------- +
    | ST_X(Point(56.7,53.34))|
    + -------------------------- +
    | 56.7 |
    + -------------------------- +
    MySQL的> SELECT ST_AsText(ST_X(Point(56.7, 53.34), 10.5));
    + ------------------------------------------- +
    | ST_AsText(ST_X(Point(56.7,53.34),10.5))|
    + ------------------------------------------- +
    | 要点(10.5 53.34)|
    + ------------------------------------------- +
    
  • ST_Y(p[, new_y_val])

    使用表示有效 Point 对象 的单个参数 p ST_Y() 将Y坐标值 p 作为双精度数返回。 从MySQL 8.0.12开始,Y坐标被认为是指 Point 空间参照系(SRS)定义 中第二个出现的轴

    使用可选的第二个参数, ST_Y() 返回一个 Point 对象,如第一个参数,其Y坐标等于第二个参数。 从MySQL 8.0.12开始,如果 Point 对象具有地理SRS,则第二个参数必须在经度或纬度值的适当范围内。

    ST_Y() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_Y(Point(56.7, 53.34));
    + -------------------------- +
    | ST_Y(Point(56.7,53.34))|
    + -------------------------- +
    | 53.34 |
    + -------------------------- +
    MySQL的> SELECT ST_AsText(ST_Y(Point(56.7, 53.34), 10.5));
    + ------------------------------------------- +
    | ST_AsText(ST_Y(Point(56.7,53.34),10.5))|
    + ------------------------------------------- +
    | 要点(56.7 10.5)|
    + ------------------------------------------- +
    

12.16.7.3 LineString和MultiLineString属性函数

A LineString Point 组成 您可以提取a的特定点 LineString ,计算它包含的点数或获取其长度。

本节中的某些功能也适用于 MultiLineString 值。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果任何参数是 NULL 或任何几何参数是空几何,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 否则,返回值为非 NULL

这些函数可用于获取线串属性:

  • ST_EndPoint(ls)

    返回 Point LineString 的端点 ls

    ST_EndPoint() 处理其参数,如本节的介绍中所述。

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql>SELECT ST_AsText(ST_EndPoint(ST_GeomFromText(@ls)));
    + ---------------------------------------------- +
    | ST_AsText(ST_EndPoint(ST_GeomFromText(@ls)))|
    + ---------------------------------------------- +
    | 要点(3 3)|
    + ---------------------------------------------- +
    
  • ST_IsClosed(ls)

    对于 LineString ls ST_IsClosed() 如果 ls 关闭 则返回1 (即,它 ST_StartPoint() ST_EndPoint() 值相同)。

    对于一个 MultiLineString ls ST_IsClosed() 则返回1,如果 ls 是封闭的(即, ST_StartPoint() ST_EndPoint() 值是彼此相同 LineString ls )。

    ST_IsClosed() 如果返回0 ls 是不封闭的,而 NULL 如果 ls NULL

    ST_IsClosed() 处理其参数,如本节的介绍中所述,但有以下例外:

    mysql> SET @ls1 = 'LineString(1 1,2 2,3 3,2 2)';
    mysql>SET @ls2 = 'LineString(1 1,2 2,3 3,1 1)';
    
    MySQL的> SELECT ST_IsClosed(ST_GeomFromText(@ls1));
    + ------------------------------------ +
    | ST_IsClosed(ST_GeomFromText(@ ls1))|
    + ------------------------------------ +
    | 0 |
    + ------------------------------------ +
    
    MySQL的> SELECT ST_IsClosed(ST_GeomFromText(@ls2));
    + ------------------------------------ +
    | ST_IsClosed(ST_GeomFromText(@ ls2))|
    + ------------------------------------ +
    | 1 |
    + ------------------------------------ +
    
    MySQL的> SET @ls3 = 'MultiLineString((1 1,2 2,3 3),(4 4,5 5))';
    
    MySQL的> SELECT ST_IsClosed(ST_GeomFromText(@ls3));
    + ------------------------------------ +
    | ST_IsClosed(ST_GeomFromText(@ ls3))|
    + ------------------------------------ +
    | 0 |
    + ------------------------------------ +
    
  • ST_Length(ls [, unit])

    返回一个双精度数字,表示 其关联空间参照系 中的 LineString MultiLineString 的长度 ls MultiLineString 的长度 等于其元素长度的总和。

    ST_Length() 计算结果如下:

    • 如果几何 LineString 在笛卡尔SRS中 有效 ,则返回值是几何的笛卡尔长度。

    • 如果几何 MultiLineString 在笛卡尔SRS 中是有效的 ,则返回值是其元素的笛卡尔长度的总和。

    • 如果几何 LineString 在地理SRS中 有效 ,则返回值是该SRS中几何的大地长度(以米为单位)。

    • 如果几何 MultiLineString 在地理SRS中 有效 ,则返回值是该SRS中其元素的大地长度之和(以米为单位)。

    ST_Length() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 如果几何不是 LineString 或者 MultiLineString ,返回值是 NULL

    • 如果几何在几何上无效,则结果是未定义的长度(即,它可以是任何数字),或者发生错误。

    • 如果长度计算结果是 +inf ,则发生 ER_DATA_OUT_OF_RANGE 错误。

    • 如果几何体具有经度或纬度超出范围的地理SRS,则会发生错误:

      显示的范围以度为单位。 由于浮点运算,精确的范围限制略有偏差。

    从MySQL 8.0.16开始, ST_Length() 允许使用可选 unit 参数来指定返回长度值的线性单位。 这些规则适用于:

    • 如果指定了单元但MySQL不支持, ER_UNIT_NOT_FOUND 则会发生错误。

    • 如果指定了支持的线性单位且SRID为0, ER_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT 则会发生错误。

    • 如果指定了受支持的线性单位且SRID不为0,则结果为该单位。

    • 如果未指定单位,则结果以几何的SRS为单位,无论是笛卡尔坐标还是地理坐标。 目前,所有MySQL SRS都以米为单位表示。

    如果在 INFORMATION_SCHEMA ST_UNITS_OF_MEASURE 表中 找到,则支持单位 请参见 第25.29节“INFORMATION_SCHEMA ST_UNITS_OF_MEASURE表”

    mysql> SET @ls = ST_GeomFromText('LineString(1 1,2 2,3 3)');
    mysql>SELECT ST_Length(@ls);
    + -------------------- +
    | ST_Length(@ls)|
    + -------------------- +
    | 2.8284271247461903 |
    + -------------------- +
    
    mysql> SET @mls = ST_GeomFromText('MultiLineString((1 1,2 2,3 3),(4 4,5 5))');
    mysql>SELECT ST_Length(@mls);
    + ------------------- +
    | ST_Length(@mls)|
    + ------------------- +
    | 4.242640687119286 |
    + ------------------- +
    
    mysql> SET @ls = ST_GeomFromText('LineString(1 1,2 2,3 3)', 4326);
    mysql>SELECT ST_Length(@ls);
    + ------------------- +
    | ST_Length(@ls)|
    + ------------------- +
    | 313701.9623204328 |
    + ------------------- +
    MySQL的> SELECT ST_Length(@ls, 'metre');
    + ------------------------- +
    | ST_Length(@ls,'meter')|
    + ------------------------- +
    | 313701.9623204328 |
    + ------------------------- +
    MySQL的> SELECT ST_Length(@ls, 'foot');
    + ------------------------ +
    | ST_Length(@ls,'foot')|
    + ------------------------ +
    | 1029205.9131247795 |
    + ------------------------ +
    
  • ST_NumPoints(ls)

    返回的数量 Point 中的对象 LineString ls

    ST_NumPoints() 处理其参数,如本节的介绍中所述。

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql>SELECT ST_NumPoints(ST_GeomFromText(@ls));
    + ------------------------------------ +
    | ST_NumPoints(ST_GeomFromText(@ls))|
    + ------------------------------------ +
    | 3 |
    + ------------------------------------ +
    
  • ST_PointN(ls, N)

    返回 N Point Linestring ls 点数从1开始编号。

    ST_PointN() 处理其参数,如本节的介绍中所述。

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql>SELECT ST_AsText(ST_PointN(ST_GeomFromText(@ls),2));
    + ---------------------------------------------- +
    | ST_AsText(ST_PointN(ST_GeomFromText(@ls),2))|
    + ---------------------------------------------- +
    | 要点(2 2)|
    + ---------------------------------------------- +
    
  • ST_StartPoint(ls)

    返回 Point 那是的起点 LineString ls

    ST_StartPoint() 处理其参数,如本节的介绍中所述。

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql>SELECT ST_AsText(ST_StartPoint(ST_GeomFromText(@ls)));
    + ------------------------------------------------ +
    | ST_AsText(ST_StartPoint(ST_GeomFromText(@ls)))|
    + ------------------------------------------------ +
    | 要点(1 1)|
    + ------------------------------------------------ +
    

12.16.7.4多边形和多边形属性函数

本节中的函数返回属性 Polygon MultiPolygon 值。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果任何参数是 NULL 或任何几何参数是空几何,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 对于采用多个几何参数的函数,如果这些参数不具有相同的SRID, ER_GIS_DIFFERENT_SRIDS 则会发生错误。

  • 否则,返回值为非 NULL

这些函数可用于获取多边形属性:

  • ST_Area({poly|mpoly})

    返回一个双精度数字,表示 在其空间参照系中测量 Polygon MultiPolygon 参数 的区域

    从MySQL 8.0.13开始, ST_Area() 按照本节的介绍中的描述处理其参数,但有以下例外:

    • 如果几何在几何上无效,则结果是未定义区域(即,它可以是任何数字),或者发生错误。

    • 如果几何有效但不是 Polygon MultiPolygon 对象, ER_UNEXPECTED_GEOMETRY_TYPE 则会发生错误。

    • 如果几何 Polygon 在笛卡尔SRS 中是有效的 ,则结果是多边形的笛卡尔区域。

    • 如果几何 MultiPolygon 在笛卡尔SRS 中是有效的 ,则结果是多边形的笛卡尔面积的总和。

    • 如果几何 Polygon 在地理SRS中 有效 ,则结果是该SRS中多边形的大地测量区域,以平方米为单位。

    • 如果几何 MultiPolygon 在地理SRS中 有效 ,则结果是该SRS中多边形的大地面积总和,以平方米为单位。

    • 如果导致区域计算 +inf ,则发生 ER_DATA_OUT_OF_RANGE 错误。

    • 如果几何体具有经度或纬度超出范围的地理SRS,则会发生错误:

      显示的范围以度为单位。 由于浮点运算,精确的范围限制略有偏差。

    在MySQL 8.0.13之前, ST_Area() 按照本节的介绍中的描述处理其参数,但有以下例外:

    • 对于维度0或1的参数,结果为0。

    • 如果几何为空,则返回值为0而不是 NULL

    • 对于几何集合,结果是所有组件的面积值的总和。 如果几何集合为空,则其区域返回为0。

    • 如果几何具有地理空间参考系统(SRS)的SRID值, ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS 则会发生错误。

    mysql> 
    mysql>SET @poly =
           'Polygon((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))';SELECT ST_Area(ST_GeomFromText(@poly));
    + --------------------------------- +
    | ST_Area(ST_GeomFromText(@poly))|
    + --------------------------------- +
    | 4 |
    + --------------------------------- +
    
    mysql> 
    mysql>SET @mpoly =
           'MultiPolygon(((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1)))';SELECT ST_Area(ST_GeomFromText(@mpoly));
    + ---------------------------------- +
    | ST_Area(ST_GeomFromText(@mpoly))|
    + ---------------------------------- +
    | 8 |
    + ---------------------------------- +
    
  • ST_Centroid({poly|mpoly})

    返回 Polygon MultiPolygon 参数 的数学质心 作为 Point 结果不能保证在 MultiPolygon

    此函数通过计算集合中最高维度的组件的质心点来处理几何集合。 这样的成分被提取并制作成单个 MultiPolygon MultiLineString MultiPoint 为质心计算。

    ST_Centroid() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 返回值是 NULL 参数为空几何集合的附加条件。

    • 如果几何具有地理空间参考系统(SRS)的SRID值, ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS 则会发生错误。

    mysql> 
    mysql>SET @poly =
           ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))');SELECT ST_GeometryType(@poly),ST_AsText(ST_Centroid(@poly));
    + ------------------------ + ------------------------ -------------------- +
    | ST_GeometryType(@poly)| ST_AsText(ST_Centroid(@poly))|
    + ------------------------ + ------------------------ -------------------- +
    | POLYGON | 要点(4.958333333333333 4.958333333333333)|
    + ------------------------ + ------------------------ -------------------- +
    
  • ST_ExteriorRing(poly)

    返回 Polygon 值的 外环 poly 作为a LineString

    ST_ExteriorRing() 处理其参数,如本节的介绍中所述。

    mysql> 
    mysql>SET @poly =
           'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';SELECT ST_AsText(ST_ExteriorRing(ST_GeomFromText(@poly)));
    + ------------------------------------------------- --- +
    | ST_AsText(ST_ExteriorRing(ST_GeomFromText(@ poly)))|
    + ------------------------------------------------- --- +
    | LINESTRING(0 0,0 3,3 3,3 0,0 0)|
    + ------------------------------------------------- --- +
    
  • ST_InteriorRingN(poly, N)

    返回 N 了个内环 Polygon poly 作为 LineString 戒指从1开始编号。

    ST_InteriorRingN() 处理其参数,如本节的介绍中所述。

    mysql> 
    mysql>SET @poly =
           'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';SELECT ST_AsText(ST_InteriorRingN(ST_GeomFromText(@poly),1));
    + ------------------------------------------------- ------ +
    | ST_AsText(ST_InteriorRingN(ST_GeomFromText(@ poly),1))|
    + ------------------------------------------------- ------ +
    | LINESTRING(1 1,1 2,2 2,2 1,1 1)|
    + ------------------------------------------------- ------ +
    
  • ST_NumInteriorRing(poly) ST_NumInteriorRings(poly)

    返回内部环的数量 Polygon poly

    ST_NumInteriorRing() ST_NuminteriorRings() 按照本节的介绍中的描述处理它们的参数。

    mysql> 
    mysql>SET @poly =
           'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';SELECT ST_NumInteriorRings(ST_GeomFromText(@poly));
    + --------------------------------------------- +
    | ST_NumInteriorRings(ST_GeomFromText(@poly))|
    + --------------------------------------------- +
    | 1 |
    + --------------------------------------------- +
    

12.16.7.5 GeometryCollection属性函数

这些函数返回 GeometryCollection 值的 属性

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果任何参数是 NULL 或任何几何参数是空几何,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 否则,返回值为非 NULL

这些函数可用于获取几何集合属性:

  • ST_GeometryN(gc, N)

    返回 中的 N 第th个几何 几何图形从1开始编号。 GeometryCollection gc

    ST_GeometryN() 处理其参数,如本节的介绍中所述。

    mysql> SET @gc = 'GeometryCollection(Point(1 1),LineString(2 2, 3 3))';
    mysql>SELECT ST_AsText(ST_GeometryN(ST_GeomFromText(@gc),1));
    + ------------------------------------------------- +
    | ST_AsText(ST_GeometryN(ST_GeomFromText(@gc),1))|
    + ------------------------------------------------- +
    | 要点(1 1)|
    + ------------------------------------------------- +
    
  • ST_NumGeometries(gc)

    返回几何数量 GeometryCollection gc

    ST_NumGeometries() 处理其参数,如本节的介绍中所述。

    mysql> SET @gc = 'GeometryCollection(Point(1 1),LineString(2 2, 3 3))';
    mysql>SELECT ST_NumGeometries(ST_GeomFromText(@gc));
    + ---------------------------------------- +
    | ST_NumGeometries(ST_GeomFromText(@gc))|
    + ---------------------------------------- +
    | 2 |
    + ---------------------------------------- +
    

12.16.8空间算子函数

OpenGIS提出了许多可以生成几何的函数。 它们旨在实现空间运算符。

这些函数支持所有参数类型组合,但根据 Open Geospatial Consortium 规范 不适用的参数类型组合除外

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL ,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 对于采用多个几何参数的函数,如果这些参数不具有相同的SRID, ER_GIS_DIFFERENT_SRIDS 则会发生错误。

  • 如果任何geometry参数具有地理SRS的SRID值, ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS 则会发生错误。

  • 否则,返回值为非 NULL

这些空间操作员功能可用:

  • ST_Buffer(g, d[, strategy1[, strategy2[, strategy3]]])

    返回一个几何图形,表示距几何体值的距离 g 小于或等于距离的 所有点 d

    如果geometry参数为空,则 ST_Buffer() 返回空几何。

    如果距离为0,则 ST_Buffer() 返回几何参数不变:

    mysql> SET @pt = ST_GeomFromText('POINT(0 0)');
    mysql>SELECT ST_AsText(ST_Buffer(@pt, 0));
    + ------------------------------ +
    | ST_AsText(ST_Buffer(@pt,0))|
    + ------------------------------ +
    | POINT(0 0)|
    + ------------------------------ +
    

    ST_Buffer() 支持负距离 Polygon MultiPolygon 值,以及包含 Polygon MultiPolygon 值的 几何集合 结果可能是空几何。

    ST_Buffer() 在distance参数后最多允许三个可选的策略参数。 策略影响缓冲计算。 这些参数是 ST_Buffer_Strategy() 函数 生成的字节字符串值 ,用于点,连接和结束策略:

    可以指定每种类型的最多一种策略,并且可以以任何顺序给出它们。

    ST_Buffer() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 用于为负的距离 Point MultiPoint LineString ,和 MultiLineString 的值,而对于不包含任何几何形状的集合 Polygon MultiPolygon 值时, ER_WRONG_ARGUMENTS 会出现误差。

    • 如果指定了给定类型的多个策略, ER_WRONG_ARGUMENTS 则会发生错误。

    mysql> SET @pt = ST_GeomFromText('POINT(0 0)');
    mysql> SET @pt_strategy = ST_Buffer_Strategy('point_square');
    mysql>SELECT ST_AsText(ST_Buffer(@pt, 2, @pt_strategy));
    + -------------------------------------------- +
    | ST_AsText(ST_Buffer(@pt,2,@ ts_strategy))|
    + -------------------------------------------- +
    | POLYGON(( -  2 -2,2 -2,2 2,-2 2,-2 -2))|
    + -------------------------------------------- +
    
    mysql> SET @ls = ST_GeomFromText('LINESTRING(0 0,0 5,5 5)');
    mysql> SET @end_strategy = ST_Buffer_Strategy('end_flat');
    mysql> SET @join_strategy = ST_Buffer_Strategy('join_round', 10);
    mysql>SELECT ST_AsText(ST_Buffer(@ls, 5, @end_strategy, @join_strategy))
    + ------------------------------------------------- -------------- +
    | ST_AsText(ST_Buffer(@ls,5,@ end_strategy,@ join_strategy))|
    + ------------------------------------------------- -------------- +
    | POLYGON((5 5,5 10,0 10,-3.5355339059327373 8.535533905932738,|
    | -5 5,-5 0,0 0,5 0,5 5))|
    + ------------------------------------------------- -------------- +
    
  • ST_Buffer_Strategy(strategy[, points_per_circle])

    此函数返回一个策略字节字符串,用于 ST_Buffer() 影响缓冲区计算。

    有关策略的信息,请访问 Boost.org

    第一个参数必须是指示策略选项的字符串:

    • 对于点策略,允许的值是 'point_circle' 'point_square'

    • 对于连接策略,允许的值是 'join_round' 'join_miter'

    • 对于最终策略,允许的值是 'end_round' 'end_flat'

    如果第一个参数是 'point_circle' 'join_round' 'join_miter' ,或 'end_round' ,该 points_per_circle 参数必须被给定为正的数值。 最大值 points_per_circle max_points_in_geometry 系统变量 的值

    有关示例,请参阅说明 ST_Buffer()

    ST_Buffer_Strategy() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 如果任何参数无效, ER_WRONG_ARGUMENTS 则会发生错误。

    • 如果第一个参数是 'point_square' 'end_flat' ,则 points_per_circle 不能给出参数或发生 ER_WRONG_ARGUMENTS 错误。

  • ST_ConvexHull(g)

    返回表示几何值的凸包的几何 g

    此函数通过首先检查其顶点是否为共线来计算几何体的凸包。 如果是这样,该函数返回一个线性外壳,否则返回一个多边形外壳。 此函数通过提取集合的所有组件的所有顶点, MultiPoint 从中 创建 值以及计算其凸包来 处理几何集合

    ST_ConvexHull() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 返回值是 NULL 参数为空几何集合的附加条件。

    mysql> SET @g = 'MULTIPOINT(5 0,25 0,15 10,15 25)';
    mysql>SELECT ST_AsText(ST_ConvexHull(ST_GeomFromText(@g)));
    + ----------------------------------------------- +
    | ST_AsText(ST_ConvexHull(ST_GeomFromText(@g)))|
    + ----------------------------------------------- +
    | POLYGON((5 0,25 0,15 25,5 0))|
    + ----------------------------------------------- +
    
  • ST_Difference(g1, g2)

    返回表示几何值的点集差异的几何形状 g1 g2

    ST_Difference() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = Point(1,1), @g2 = Point(2,2);
    mysql>SELECT ST_AsText(ST_Difference(@g1, @g2));
    + ------------------------------------ +
    | ST_AsText(ST_Difference(@ g1,@ g2))|
    + ------------------------------------ +
    | 要点(1 1)|
    + ------------------------------------ +
    
  • ST_Intersection(g1, g2)

    返回表示几何值的点交集的几何形状 g1 g2

    ST_Intersection() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = ST_GeomFromText('LineString(1 1, 3 3)');
    mysql> SET @g2 = ST_GeomFromText('LineString(1 3, 3 1)');
    mysql>SELECT ST_AsText(ST_Intersection(@g1, @g2));
    + -------------------------------------- +
    | ST_AsText(ST_Intersection(@ g1,@ g2))|
    + -------------------------------------- +
    | 要点(2 2)|
    + -------------------------------------- +
    
  • ST_SymDifference(g1, g2)

    返回表示设置的几何值的对称差的点的几何形状 g1 g2 ,其被定义为:

    g1symdifference g2:=(g1联合g2)差异(g1交集g2

    或者,在函数调用表示法中:

    ST_SymDifference(g1g2)= ST_Difference(ST_Union(g1g2),ST_Intersection(g1g2))
    

    ST_SymDifference() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = Point(1,1), @g2 = Point(2,2);
    mysql>SELECT ST_AsText(ST_SymDifference(@g1, @g2));
    + --------------------------------------- +
    | ST_AsText(ST_SymDifference(@ g1,@ g2))|
    + --------------------------------------- +
    | MULTIPOINT((1 1),(2 2))|
    + --------------------------------------- +
    
  • ST_Transform(g, target_srid)

    将几何体从一个空间参照系(SRS)转换为另一个。 返回值是与输入几何体相同类型的几何体,所有坐标都转换为目标SRID , target_srid . 转换支持仅限于地理SRS,除非geometry参数的SRID与目标SRID值相同,在这种情况下,返回值是任何有效SRS的输入几何。

    ST_Transform() 处理其参数,如本节的介绍中所述,但有以下例外:

    ST_SRID(g, target_srid) 并且 不同如下: ST_Transform(g, target_srid)

    • ST_SRID() 更改几何SRID值而不转换其坐标。

    • ST_Transform() 除了更改其SRID值之外,还会转换几何坐标。

    mysql> SET @p = ST_GeomFromText('POINT(52.381389 13.064444)', 4326);
    mysql>SELECT ST_AsText(@p);
    + ---------------------------- +
    | ST_AsText(@p)|
    + ---------------------------- +
    | 要点(52.381389 13.064444)|
    + ---------------------------- +
    mysql> SET @p = ST_Transform(@p, 4230);
    mysql>SELECT ST_AsText(@p);
    + --------------------------------------------- +
    | ST_AsText(@p)|
    + --------------------------------------------- +
    | 要点(52.38208611407426 13.065520672345304)|
    + --------------------------------------------- +
    
  • ST_Union(g1, g2)

    返回表示几何值的点集联合的几何形状 g1 g2

    ST_Union() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = ST_GeomFromText('LineString(1 1, 3 3)');
    mysql> SET @g2 = ST_GeomFromText('LineString(1 3, 3 1)');
    mysql>SELECT ST_AsText(ST_Union(@g1, @g2));
    + -------------------------------------- +
    | ST_AsText(ST_Union(@ g1,@ g2))|
    + -------------------------------------- +
    | MULTILINESTRING((1 1,3 3),(1 3,3 1))|
    + -------------------------------------- +
    

此外, 第12.16.7节“几何属性函数” 讨论了从现有几何构造新几何的几个函数。 有关这些功能的说明,请参阅该部分:

12.16.9测试几何对象之间空间关系的函数

本节中描述的函数将两个几何作为参数,并返回它们之间的定性或定量关系。

MySQL使用OpenGIS规范定义的函数名实现两组函数。 一组使用精确的对象形状测试两个几何值之间的关系,另一组使用对象最小边界矩形(MBR)。

12.16.9.1使用对象形状的空间关系函数

OpenGIS规范定义了以下函数来测试两个几何值之间的关系, g1 g2 使用精确的对象形状。 返回值1和0分别表示true和false,除了 ST_Distance() 返回距离值。

本节中的函数检测笛卡尔或地理空间参照系(SRS)中的参数,并返回适合SRS的结果。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果任何参数是 NULL 或任何几何参数是空几何,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数引用未定义的空间参考系统(SRS), ER_SRS_NOT_FOUND 则会发生错误。

  • 对于采用多个几何参数的函数,如果这些参数不具有相同的SRID, ER_GIS_DIFFERENT_SRIDS 则会发生错误。

  • 如果任何几何参数在几何上无效,则结果为true或false(未定义哪个),或者发生错误。

  • 对于地理SRS几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

  • 否则,返回值为非 NULL

这些对象形状函数可用于测试几何关系:

  • ST_Contains(g1, g2)

    返回1或0以指示是否 g1 完全包含 g2 这测试了相反的关系 ST_Within()

    ST_Contains() 处理其参数,如本节的介绍中所述。

  • ST_Crosses(g1, g2)

    如果空间关系具有以下属性,则 两个几何在 空间上交叉

    • 除非 g1 并且 g2 都是尺寸1: 如果内部的内部 具有与内部相同 不覆盖整个内部的 g1 十字形 g2 g2 g1 g2 g1

    • 如果两个 g1 g2 是尺寸1的:如果线彼此交叉在一个有限数目的点(即,没有共同的线段,仅在普通的单点)。

    此函数返回1或0以指示是否在 g1 空间上交叉 g2

    ST_Crosses() 处理其参数,如本节前言中所述,但返回值是 NULL 针对以下附加条件:

    • g1 是2( Polygon MultiPolygon 维度

    • g2 是维度1( Point MultiPoint )。

  • ST_Disjoint(g1, g2)

    返回1或0以指示是否 g1 在空间上不相交(不相交) g2

    ST_Disjoint() 处理其参数,如本节的介绍中所述。

  • ST_Distance(g1, g2 [, unit])

    返回 几何参数的空间参照系(SRS)的长度单位 g1 之间的距离 g2 unit 如果指定 ,则以可选 参数 为单位

    此函数通过返回两个几何参数的所有组件组合中的最短距离来处理几何集合。

    ST_Distance() 处理其几何参数,如本节前言中所述,但有以下例外:

    • ST_Distance() 检测地理(椭圆体)空间参照系中的参数,并返回椭圆体上的测地距离。 唯一允许的地理参数类型是 Point Point ,或 Point MultiPoint (在任何参数顺序)。 如果在地理SRS中使用其他几何类型参数组合调用, ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS 则会发生错误。

    • 如果任何参数在几何上无效,则结果是未定义的距离(即,它可以是任何数字),或者发生错误。

    • 如果中间或最终结果产生 NaN 或为负数, ER_GIS_INVALID_DATA 则会发生错误。

    从MySQL 8.0.14开始, ST_Distance() 允许使用可选 unit 参数来指定返回距离值的线性单位。 这些规则适用于:

    • 如果指定了单元但MySQL不支持, ER_UNIT_NOT_FOUND 则会发生错误。

    • 如果指定了支持的线性单位且SRID为0, ER_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT 则会发生错误。

    • 如果指定了受支持的线性单位且SRID不为0,则结果为该单位。

    • 如果未指定单位,则结果以几何的SRS为单位,无论是笛卡尔坐标还是地理坐标。 目前,所有MySQL SRS都以米为单位表示。

    如果在 INFORMATION_SCHEMA ST_UNITS_OF_MEASURE 表中 找到,则支持单位 请参见 第25.29节“INFORMATION_SCHEMA ST_UNITS_OF_MEASURE表”

    mysql> SET @g1 = Point(1,1);
    mysql> SET @g2 = Point(2,2);
    mysql>SELECT ST_Distance(@g1, @g2);
    + ----------------------- +
    | ST_Distance(@ g1,@ g2)|
    + ----------------------- +
    | 1.4142135623730951 |
    + ----------------------- +
    
    mysql> SET @g1 = ST_GeomFromText('POINT(1 1)', 4326);
    mysql> SET @g2 = ST_GeomFromText('POINT(2 2)', 4326);
    mysql>SELECT ST_Distance(@g1, @g2);
    + ----------------------- +
    | ST_Distance(@ g1,@ g2)|
    + ----------------------- +
    | 156874.3859490455 |
    + ----------------------- +
    MySQL的> SELECT ST_Distance(@g1, @g2, 'metre');
    + -------------------------------- +
    | ST_Distance(@ g1,@ g2,'meter')|
    + -------------------------------- +
    | 156874.3859490455 |
    + -------------------------------- +
    MySQL的> SELECT ST_Distance(@g1, @g2, 'foot');
    + ------------------------------- +
    | ST_Distance(@ g1,@ g2,'foot')|
    + ------------------------------- +
    | 514679.7439273146 |
    + ------------------------------- +
    

    有关球体上距离计算的特殊情况,请参阅该 ST_Distance_Sphere() 函数。

  • ST_Equals(g1, g2)

    返回1或0以指示是否 g1 在空间上等于 g2

    ST_Equals() 处理其参数,如本节的介绍中所述,除了它不返回 NULL 空几何参数。

    mysql> SET @g1 = Point(1,1), @g2 = Point(2,2);
    mysql>SELECT ST_Equals(@g1, @g1), ST_Equals(@g1, @g2);
    + --------------------- + --------------------- +
    | ST_Equals(@ g1,@ g1)| ST_Equals(@ g1,@ g2)|
    + --------------------- + --------------------- +
    | 1 | 0 |
    + --------------------- + --------------------- +
    
  • ST_Intersects(g1, g2)

    返回1或0以指示是否在 g1 空间上相交 g2

    ST_Intersects() 处理其参数,如本节的介绍中所述。

  • ST_Overlaps(g1, g2)

    如果它们相交,则 两个几何在 空间上重叠 ,并且它们的交点产生相同尺寸的几何形状但不等于给定几何形状中的任何一个。

    此函数返回1或0以指示是否在 g1 空间上重叠 g2

    ST_Overlaps() 处理其参数,如本节的介绍中所述,除了返回值是 NULL 针对两个几何的尺寸不相等的附加条件。

  • ST_Touches(g1, g2)

    如果它们的内部不相交,则 两个几何在 空间上接触 ,但是一个几何的边界与另一个的边界或内部相交。

    此函数返回1或0以指示是否在 g1 空间上接触 g2

    ST_Touches() 处理其参数,如本节的介绍中所述,除了返回值是 NULL 针对两个几何都是维度0( Point MultiPoint 的附加条件

  • ST_Within(g1, g2)

    返回1或0以指示是否 g1 在空间内 g2 这测试了相反的关系 ST_Contains()

    ST_Within() 处理其参数,如本节的介绍中所述。

12.16.9.2使用最小边界矩形的空间关系函数

MySQL提供用于测试最小外接矩形两个几何的(MBR)的之间的关系几个MySQL特定功能 g1 g2 返回值1和0分别表示true和false。

点的边界框被解释为边界和内部的点。

直水平或垂直线的边界框被解释为线的内部也是边界的线。 端点是边界点。

如果任何参数是几何集合,则这些参数的内部,边界和外部是集合中所有元素的并集的参数。

本节中的函数检测笛卡尔或地理空间参照系(SRS)中的参数,并返回适合SRS的结果。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL 或是空几何,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数引用未定义的空间参考系统(SRS), ER_SRS_NOT_FOUND 则会发生错误。

  • 对于采用多个几何参数的函数,如果这些参数不具有相同的SRID, ER_GIS_DIFFERENT_SRIDS 则会发生错误。

  • 如果任何参数在几何上无效,则结果为true或false(未定义哪个),或者发生错误。

  • 对于地理SRS几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

  • 否则,返回值为非 NULL

这些MBR函数可用于测试几何关系:

  • MBRContains(g1, g2)

    返回1或0以指示最小边界矩形是否 g1 包含最小边界矩形 g2 这测试了相反的关系 MBRWithin()

    MBRContains() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = ST_GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');
    mysql> SET @g2 = ST_GeomFromText('Point(1 1)');
    mysql>SELECT MBRContains(@g1,@g2), MBRWithin(@g2,@g1);
    + ---------------------- + -------------------- +
    | MBRContains(@ g1,@ g2)| MBRWithin(@ g2,@ g1)|
    + ---------------------- + -------------------- +
    | 1 | 1 |
    + ---------------------- + -------------------- +
    
  • MBRCoveredBy(g1, g2)

    返回1或0以指示最小边界矩形是否被最小边界矩形 g1 覆盖 g2 这测试了相反的关系 MBRCovers()

    MBRCoveredBy() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = ST_GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');
    mysql> SET @g2 = ST_GeomFromText('Point(1 1)');
    mysql>SELECT MBRCovers(@g1,@g2), MBRCoveredby(@g1,@g2);
    + -------------------- + ----------------------- +
    | MBRCovers(@ g1,@ g2)| MBRCoveredby(@ g1,@ g2)|
    + -------------------- + ----------------------- +
    | 1 | 0 |
    + -------------------- + ----------------------- +
    MySQL的> SELECT MBRCovers(@g2,@g1), MBRCoveredby(@g2,@g1);
    + -------------------- + ----------------------- +
    | MBRCovers(@ g2,@ g1)| MBRCoveredby(@ g2,@ g1)|
    + -------------------- + ----------------------- +
    | 0 | 1 |
    + -------------------- + ----------------------- +
    
  • MBRCovers(g1, g2)

    返回1或0以指示最小边界矩形是否 g1 覆盖最小边界矩形 g2 这测试了相反的关系 MBRCoveredBy() 请参阅 MBRCoveredBy() 示例的说明。

    MBRCovers() 处理其参数,如本节的介绍中所述。

  • MBRDisjoint(g1, g2)

    返回1或0,以指示两个几何的最小外接矩形是否 g1 g2 是不相交的(不相交)。

    MBRDisjoint() 处理其参数,如本节的介绍中所述。

  • MBREquals(g1, g2)

    返回1或0,以指示最低是否界定两个几何的矩形 g1 g2 是相同的。

    MBREquals() 处理其参数,如本节的介绍中所述,除了它不返回 NULL 空几何参数。

  • MBRIntersects(g1, g2)

    返回1或0,以指示两个几何的最小外接矩形是否 g1 g2 相交。

    MBRIntersects() 处理其参数,如本节的介绍中所述。

  • MBROverlaps(g1, g2)

    如果它们相交,则 两个几何在 空间上重叠 ,并且它们的交点产生相同尺寸的几何形状但不等于给定几何形状中的任何一个。

    此函数返回1或0,以指示是否所述两个几何的最小外接矩形 g1 g2 重叠。

    MBROverlaps() 处理其参数,如本节的介绍中所述。

  • MBRTouches(g1, g2)

    如果它们的内部不相交,则 两个几何在 空间上接触 ,但是一个几何的边界与另一个的边界或内部相交。

    此函数返回1或0,以指示最低是否界定两个几何的矩形 g1 g2 触感。

    MBRTouches() 处理其参数,如本节的介绍中所述。

  • MBRWithin(g1, g2)

    返回1或0以指示最小边界矩形是否在最小边界矩形 g1 g2 这测试了相反的关系 MBRContains()

    MBRWithin() 处理其参数,如本节的介绍中所述。

    mysql> SET @g1 = ST_GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');
    mysql> SET @g2 = ST_GeomFromText('Polygon((0 0,0 5,5 5,5 0,0 0))');
    mysql>SELECT MBRWithin(@g1,@g2), MBRWithin(@g2,@g1);
    + -------------------- + -------------------- +
    | MBRWithin(@ g1,@ g2)| MBRWithin(@ g2,@ g1)|
    + -------------------- + -------------------- +
    | 1 | 0 |
    + -------------------- + -------------------- +
    

12.16.10空间Geohash函数

Geohash是一种将任意精度的纬度和经度坐标编码为文本字符串的系统。 Geohash值是仅包含从中选择的字符的字符串 "0123456789bcdefghjkmnpqrstuvwxyz"

本节中的函数允许操作geohash值,这为应用程序提供了导入和导出geohash数据的功能,以及索引和搜索geohash值的功能。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL ,则返回值为 NULL

  • 如果任何参数无效,则会发生错误。

  • 如果任何参数的经度或纬度超出范围,则会发生错误:

    显示的范围以度为单位。 由于浮点运算,精确的范围限制略有偏差。

  • 如果任何点参数没有SRID 0或4326, ER_SRS_NOT_FOUND 则会发生错误。 point 参数SRID有效性未被检查。

  • 如果任何SRID参数引用未定义的空间参考系统(SRS), ER_SRS_NOT_FOUND 则会发生错误。

  • 如果任何SRID参数不在32位无符号整数的范围内, ER_DATA_OUT_OF_RANGE 则会发生错误。

  • 否则,返回值为非 NULL

这些geohash功能可用:

  • ST_GeoHash(longitude, latitude, max_length) ST_GeoHash(point, max_length)

    返回连接字符集和排序规则中的geohash字符串。

    对于第一种语法, longitude 必须是[-180,180]范围内的数字,并且 latitude 必须是[-90,90]范围内的数字。 对于第二种语法, POINT 需要 一个 值,其中X和Y坐标分别位于经度和纬度的有效范围内。

    生成的字符串不会超过 max_length 字符,其上限为100.字符串可能比 max_length 字符 短, 因为创建geohash值的算法会一直持续,直到创建了一个字符串,该字符串是位置或 max_length 字符 的精确表示形式 , 以先到者为准。

    ST_GeoHash() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_GeoHash(180,0,10), ST_GeoHash(-180,-90,15);
    + ---------------------- + ------------------------- +
    | ST_GeoHash(180,0,10)| ST_GeoHash(-180,-90,15)|
    + ---------------------- + ------------------------- +
    | xbpbpbpbpb | 000000000000000 |
    + ---------------------- + ------------------------- +
    
  • ST_LatFromGeoHash(geohash_str)

    从geohash字符串值返回纬度,作为[-90,90]范围内的双精度数。

    ST_LatFromGeoHash() 解码功能读取来自不超过433个字符 geohash_str 的参数。 这表示坐标值的内部表示中的信息的上限。 超过433rd的字符将被忽略,即使它们是非法的并产生错误。

    ST_LatFromGeoHash() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_LatFromGeoHash(ST_GeoHash(45,-20,10));
    + ------------------------------------------ +
    | ST_LatFromGeoHash(ST_GeoHash(45,-20,10))|
    + ------------------------------------------ +
    | -20 |
    + ------------------------------------------ +
    
  • ST_LongFromGeoHash(geohash_str)

    从geohash字符串值返回经度,作为[-180,180]范围内的双精度数。

    ST_LatFromGeoHash() 关于从 geohash_str 参数 处理的最大字符数 的描述中的注释 也适用于 ST_LongFromGeoHash()

    ST_LongFromGeoHash() 处理其参数,如本节的介绍中所述。

    MySQL的> SELECT ST_LongFromGeoHash(ST_GeoHash(45,-20,10));
    + ------------------------------------------- +
    | ST_LongFromGeoHash(ST_GeoHash(45,-20,10))|
    + ------------------------------------------- +
    | 45 |
    + ------------------------------------------- +
    
  • ST_PointFromGeoHash(geohash_str, srid)

    POINT 给定geohash字符串值, 返回 包含已解码的geohash值的值。

    该点的X和Y坐标分别是范围[-180,180]中的经度和范围[-90,90]中的纬度。

    所述 srid 参数是一个32位无符号整数。

    ST_LatFromGeoHash() 关于从 geohash_str 参数 处理的最大字符数 的描述中的注释 也适用于 ST_PointFromGeoHash()

    ST_PointFromGeoHash() 处理其参数,如本节的介绍中所述。

    mysql> SET @gh = ST_GeoHash(45,-20,10);
    mysql>SELECT ST_AsText(ST_PointFromGeoHash(@gh,0));
    + --------------------------------------- +
    | ST_AsText(ST_PointFromGeoHash(@ gh,0))|
    + --------------------------------------- +
    | POINT(45 -20)|
    + --------------------------------------- +
    

12.16.11空间GeoJSON函数

本节介绍在GeoJSON文档和空间值之间进行转换的功能。 GeoJSON是一种用于编码几何/地理特征的开放标准。 有关更多信息,请访问 http://geojson.org 这里讨论的函数遵循GeoJSON规范1.0版。

GeoJSON支持MySQL支持的相同几何/地理数据类型。 除了从中提取几何对象外,不支持Feature和FeatureCollection对象。 CRS支持仅限于标识SRID的值。

MySQL还支持本机 JSON 数据类型和一组SQL函数,以启用对JSON值的操作。 有关更多信息,请参见 第11.6节“JSON数据类型” 第12.17节“JSON函数”

  • ST_AsGeoJSON(g [, max_dec_digits [, options]])

    从几何体生成GeoJSON对象 g 对象字符串具有连接字符集和排序规则。

    如果有任何参数 NULL ,则返回值为 NULL 如果任何非 NULL 参数无效,则会发生错误。

    max_dec_digits ,如果指定,则限制坐标的小数位数并导致输出舍入。 如果未指定,则此参数默认为其最大值2 32 - 1.最小值为0。

    options ,如果指定,则是位掩码。 下表显示了允许的标志值。 如果geometry参数的SRID为0,则即使对于请求一个的标志值,也不会生成CRS对象。

    旗帜价值 含义
    0 没有选择。 如果 options 未指定, 则为默认值
    1 在输出中添加边界框。
    2 在输出中添加短格式CRS URN。 默认格式是短格式( )。 EPSG:srid
    4 添加长格式CRS URN( )。 此标志覆盖标志2.例如,选项值5和7表示相同(添加边界框和长格式CRS URN)。 urn:ogc:def:crs:EPSG::srid
    MySQL的> SELECT ST_AsGeoJSON(ST_GeomFromText('POINT(11.11111 12.22222)'),2);
    + ------------------------------------------------- ------------ +
    | ST_AsGeoJSON(ST_GeomFromText('POINT(11.11111 12.22222)'),2)|
    + ------------------------------------------------- ------------ +
    | {“type”:“Point”,“coordinates”:[11.11,12.22]} |
    + ------------------------------------------------- ------------ +
    
  • ST_GeomFromGeoJSON(str [, options [, srid]])

    解析 str 表示GeoJSON对象 的字符串 并返回几何。

    如果有任何参数 NULL ,则返回值为 NULL 如果任何非 NULL 参数无效,则会发生错误。

    options ,如果给定,则描述如何处理包含坐标尺寸大于2的几何的GeoJSON文档。下表显示了允许的 options 值。

    期权价值 含义
    1 拒绝文档并产生错误。 如果 options 未指定, 则为默认值
    2,3,4 接受文档并剥离坐标以获得更高的坐标尺寸。

    options 值2,3和4目前产生相同的效果。 如果将来支持坐标尺寸大于2的几何图形,则这些值将产生不同的效果。

    srid 参数,如果给定的,必须是一个32位无符号整数。 如果未给出,则几何返回值的SRID为4326。

    如果 srid 引用未定义的空间参照系(SRS), ER_SRS_NOT_FOUND 则会发生错误。

    对于地理SRS几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

    GeoJSON几何,要素和要素集合对象可能具有 crs 属性。 解析函数解析 名称空间 中的命名CRS URN ,但不 解析 作为链接对象给出的CRS。 此外, 还被识别为SRID 4326.如果对象具有未被理解的CRS,则会发生错误,但如果 给出 可选 参数,则即使CRS无效,也会忽略任何CRS。 urn:ogc:def:crs:EPSG::srid EPSG:srid urn:ogc:def:crs:OGC:1.3:CRS84 srid

    如果 crs 在GeoJSON文档的较低级别找到指定与顶级对象SRID不同的SRID 成员, ER_INVALID_GEOJSON_CRS_NOT_TOP_LEVEL 则会发生错误。

    正如GeoJSON规范中所指定的,解析对于 type GeoJSON输入 成员( Point LineString 等等) 区分大小写 该规范没有提及其他解析的区分大小写,在MySQL中它不区分大小写。

    此示例显示了简单GeoJSON对象的解析结果:

    mysql> SET @json = '{ "type": "Point", "coordinates": [102.0, 0.0]}';
    mysql>SELECT ST_AsText(ST_GeomFromGeoJSON(@json));
    + -------------------------------------- +
    | ST_AsText(ST_GeomFromGeoJSON(@json))|
    + -------------------------------------- +
    | 要点(102 0)|
    + -------------------------------------- +
    

12.16.12空间便利函数

本节中的函数提供了几何值的便捷操作。

除非另有说明,否则本节中的函数处理其参数如下:

  • 如果有任何参数 NULL ,则返回值为 NULL

  • 如果任何几何参数不是语法上格式良好的几何体, ER_GIS_INVALID_DATA 则会发生错误。

  • 如果任何几何参数具有引用未定义空间参考系统(SRS)的SRID值, ER_SRS_NOT_FOUND 则会发生错误。

  • 对于采用多个几何参数的函数,如果这些参数不具有相同的SRID, ER_GIS_DIFFERENT_SRIDS 则会发生错误。

  • 否则,返回值为非 NULL

这些便利功能可用:

  • ST_Distance_Sphere(g1, g2 [, radius])

    返回球体之间的最小球面距离 Point MultiPoint 球体上的参数(以米为单位)。 (对于通用距离计算,请参阅 ST_Distance() 函数。)可选 radius 参数应以米为单位。

    如果两个几何参数都是有效的笛卡尔坐标 Point MultiPoint SRID 0中的值,则返回值是具有所提供半径的球体上两个几何之间的最短距离。 如果省略,则默认半径为6,370,986米,点X和Y坐标分别以度为单位解释为经度和纬度。

    如果两个几何参数均为有效 Point MultiPoint 地理空间参照系(SRS)中的值,则返回值是球体上具有提供半径的两个几何之间的最短距离。 如果省略,则默认半径等于平均半径,定义为(2a + b)/ 3,其中a是半长轴,b是SRS的半短轴。

    ST_Distance_Sphere() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 支持的几何参数组合是 Point Point ,或 Point MultiPoint (以任何参数顺序)。 如果至少一个几何结构既不 Point MultiPoint 也不 是SRID为0, ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS 则会发生错误。 如果至少一个几何结构既不 Point MultiPoint 也不 SRID,则其SRID指的是地理SRS, ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS 则会发生错误。 如果任何几何图形指的是投影的SRS, ER_NOT_IMPLEMENTED_FOR_PROJECTED_SRS 则会发生错误。

    • 如果任何参数的经度或纬度超出范围,则会发生错误:

      显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

    • 如果 radius 参数存在但不是正数, ER_NONPOSITIVE_RADIUS 则会发生错误。

    • 如果距离超出双精度数的范围, ER_STD_OVERFLOW_ERROR 则会发生错误。

    mysql> SET @pt1 = ST_GeomFromText('POINT(0 0)');
    mysql> SET @pt2 = ST_GeomFromText('POINT(180 0)');
    mysql>SELECT ST_Distance_Sphere(@pt1, @pt2);
    + -------------------------------- +
    | ST_Distance_Sphere(@ pt1,@ pt2)|
    + -------------------------------- +
    | 20015042.813723423 |
    + -------------------------------- +
    
  • ST_IsValid(g)

    如果参数在几何上有效,则返回1;如果参数在几何上无效,则返回0。 几何有效性由OGC规范定义。

    唯一有效的空几何体以空几何集合值的形式表示。 ST_IsValid() 在这种情况下返回1。 MySQL不支持GIS EMPTY POINT EMPTY

    ST_IsValid() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 如果几何体具有经度或纬度超出范围的地理SRS,则会发生错误:

      显示的范围以度为单位。 如果SRS使用其他单位,则该范围使用其单位中的相应值。 由于浮点运算,精确的范围限制略有偏差。

    mysql> SET @ls1 = ST_GeomFromText('LINESTRING(0 0,-0.00 0,0.0 0)');
    mysql> SET @ls2 = ST_GeomFromText('LINESTRING(0 0, 1 1)');
    mysql>SELECT ST_IsValid(@ls1);
    + ------------------ +
    | ST_IsValid(@ ls1)|
    + ------------------ +
    | 0 |
    + ------------------ +
    MySQL的> SELECT ST_IsValid(@ls2);
    + ------------------ +
    | ST_IsValid(@ ls2)|
    + ------------------ +
    | 1 |
    + ------------------ +
    
  • ST_MakeEnvelope(pt1, pt2)

    返回形成围绕两点信封,作为一个矩形 Point LineString Polygon

    使用笛卡尔坐标系而不是球体,椭球体或地球上进行计算。

    给定两个点 pt1 pt2 ST_MakeEnvelope() 产生在这样一个抽象的平面结果的几何图形:

    • 如果 pt1 并且 pt2 相等,结果就是重点 pt1

    • 否则,如果 是垂直或水平线段,则结果是线段 (pt1, pt2) (pt1, pt2)

    • 否则,结果是使用多边形 pt1 pt2 作为对角点 的多边形

    结果几何的SRID为0。

    ST_MakeEnvelope() 处理其参数,如本节的介绍中所述,但有以下例外:

    mysql> SET @pt1 = ST_GeomFromText('POINT(0 0)');
    mysql> SET @pt2 = ST_GeomFromText('POINT(1 1)');
    mysql>SELECT ST_AsText(ST_MakeEnvelope(@pt1, @pt2));
    + ---------------------------------------- +
    | ST_AsText(ST_MakeEnvelope(@ pt1,@ pt2))|
    + ---------------------------------------- +
    | POLYGON((0 0,1 0,1 1,0 1,0 0))|
    + ---------------------------------------- +
    
  • ST_Simplify(g, max_distance)

    使用Douglas-Peucker算法简化几何,并返回相同类型的简化值。

    几何体可以是任何几何体类型,尽管Douglas-Peucker算法实际上可能不会处理每种类型。 通过将其组件逐个提供给简化算法来处理几何集合,并将返回的几何图形作为结果放入几何集合中。

    max_distance 参数是要除去的距离(在输入坐标的单位)顶点到其他段。 移除简化线串的此距离内的顶点。

    根据Boost.Geometry,由于简化过程,几何可能会变得无效,并且该过程可能会创建自相交。 要检查结果的有效性,请将其传递给 ST_IsValid()

    ST_Simplify() 处理其参数,如本节的介绍中所述,但有以下例外:

    • 如果 max_distance 参数不是正数,或者是 NaN ,则发生 ER_WRONG_ARGUMENTS 错误。

    mysql> SET @g = ST_GeomFromText('LINESTRING(0 0,0 1,1 1,1 2,2 2,2 3,3 3)');
    mysql>SELECT ST_AsText(ST_Simplify(@g, 0.5));
    + --------------------------------- +
    | ST_AsText(ST_Simplify(@ g,0.5))|
    + --------------------------------- +
    | LINESTRING(0 0,0 1,1 1,2 3,3 3)|
    + --------------------------------- +
    MySQL的> SELECT ST_AsText(ST_Simplify(@g, 1.0));
    + --------------------------------- +
    | ST_AsText(ST_Simplify(@ g,1.0))|
    + --------------------------------- +
    | LINESTRING(0 0,3 3)|
    + --------------------------------- +
    
  • ST_Validate(g)

    根据OGC规范验证几何。 几何可以在语法上格式良好(WKB值加SRID),但几何上无效。 例如,此多边形几何无效: POLYGON((0 0, 0 0, 0 0, 0 0, 0 0))

    ST_Validate() 返回几何体,如果它在语法上是格式良好的并且在几何上是有效的, NULL 如果参数在语法上没有良好形成或几何有效或是 NULL

    ST_Validate() 可用于过滤掉无效的几何数据,但需要付出代价。 对于需要更精确结果而不受无效数据污染的应用程序,这种惩罚可能是值得的。

    如果geometry参数有效,则按原样返回,除非输入 Polygon MultiPolygon 具有顺时针环, 否则 在检查有效性之前将这些环反转。 如果几何有效,则返回带有反转环的值。

    唯一有效的空几何体以空几何集合值的形式表示。 ST_Validate() 在这种情况下,无需进一步检查即可直接返回

    从MySQL 8.0.13开始, ST_Validate() 按照本节的介绍中的描述处理其参数,但有以下例外:

    • 如果几何体具有经度或纬度超出范围的地理SRS,则会发生错误:

      显示的范围以度为单位。 由于浮点运算,精确的范围限制略有偏差。

    在MySQL 8.0.13之前, ST_Validate() 按照本节的介绍中的描述处理其参数,但有以下例外:

    mysql> SET @ls1 = ST_GeomFromText('LINESTRING(0 0)');
    mysql> SET @ls2 = ST_GeomFromText('LINESTRING(0 0, 1 1)');
    mysql>SELECT ST_AsText(ST_Validate(@ls1));
    + ------------------------------ +
    | ST_AsText(ST_Validate(@ ls1))|
    + ------------------------------ +
    | NULL |
    + ------------------------------ +
    MySQL的> SELECT ST_AsText(ST_Validate(@ls2));
    + ------------------------------ +
    | ST_AsText(ST_Validate(@ ls2))|
    + ------------------------------ +
    | LINESTRING(0 0,1 1)|
    + ------------------------------ +
    

12.17 JSON函数

本节中描述的函数对JSON值执行操作。 有关 JSON 数据类型和其他示例的 讨论 ,请参见 第11.6节“JSON数据类型”

对于采用JSON参数的函数,如果参数不是有效的JSON值,则会发生错误。 解析为JSON的参数表示为 json_doc ; 指示的参数 val 未被解析。

还提供了一组用于操作GeoJSON值的空间函数。 请参见 第12.16.11节“空间GeoJSON函数”

12.17.1 JSON函数参考

表12.21 JSON函数

名称 描述
JSON_ARRAY() 创建JSON数组
JSON_ARRAY_APPEND() 将数据附加到JSON文档
JSON_ARRAY_INSERT() 插入JSON数组
-> 评估路径后从JSON列返回值; 相当于JSON_EXTRACT()。
JSON_CONTAINS() JSON文档是否包含路径中的特定对象
JSON_CONTAINS_PATH() JSON文档是否包含路径中的任何数据
JSON_DEPTH() JSON文档的最大深度
JSON_EXTRACT() 从JSON文档返回数据
->> 在评估路径并取消引用结果后,从JSON列返回值; 相当于JSON_UNQUOTE(JSON_EXTRACT())。
JSON_INSERT() 将数据插入JSON文档
JSON_KEYS() 来自JSON文档的键数组
JSON_LENGTH() JSON文档中的元素数量
JSON_MERGE() (已弃用8.0.3) 合并JSON文档,保留重复键。 JSON_MERGE_PRESERVE()的弃用词不再使用
JSON_MERGE_PATCH() 合并JSON文档,替换重复键的值
JSON_MERGE_PRESERVE() 合并JSON文档,保留重复键
JSON_OBJECT() 创建JSON对象
JSON_OVERLAPS() 比较两个JSON文档,如果它们具有任何共同的键值对或数组元素,则返回TRUE(1),否则返回FALSE(0)
JSON_PRETTY() 以人类可读的格式打印JSON文档
JSON_QUOTE() 引用JSON文档
JSON_REMOVE() 从JSON文档中删除数据
JSON_REPLACE() 替换JSON文档中的值
JSON_SCHEMA_VALID() 根据JSON模式验证JSON文档; 如果文档针对模式进行验证,则返回TRUE / 1;否则返回FALSE / 0
JSON_SCHEMA_VALIDATION_REPORT() 根据JSON模式验证JSON文档; 以JSON格式返回有关验证结果的报告,包括成功或失败以及失败原因
JSON_SEARCH() JSON文档中的值路径
JSON_SET() 将数据插入JSON文档
JSON_STORAGE_FREE() 在部分更新之后释放JSON列值的二进制表示内的空间
JSON_STORAGE_SIZE() 用于存储JSON文档的二进制表示的空间
JSON_TABLE() 将JSON表达式中的数据作为关系表返回
JSON_TYPE() JSON值的类型
JSON_UNQUOTE() 取消引用JSON值
JSON_VALID() JSON值是否有效
MEMBER OF() 如果第一个操作数匹配作为第二个操作数传递的JSON数组的任何元素,则返回true(1),否则返回false(0)

MySQL支持两个聚合JSON函数 JSON_ARRAYAGG() JSON_OBJECTAGG() 有关 这些的说明, 请参见 第12.20节“聚合(GROUP BY)函数”

MySQL还 使用该 函数 以易于阅读的格式 支持 JSON值的 漂亮打印 JSON_PRETTY() 您可以看到给定JSON值占用多少存储空间, JSON_STORAGE_SIZE() 以及 JSON_STORAGE_FREE() 分别 使用 存储额外存储空间 有关这些函数的完整描述,请参见 第12.17.8节“JSON实用程序函数”

12.17.2创建JSON值的函数

本节中列出的函数组成了组件元素的JSON值。

  • JSON_ARRAY([val[, val] ...])

    计算(可能为空)值列表并返回包含这些值的JSON数组。

    MySQL的> SELECT JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME());
    + --------------------------------------------- +
    | JSON_ARRAY(1,“abc”,NULL,TRUE,CURTIME())|
    + --------------------------------------------- +
    | [1,“abc”,null,true,“11:30:24.000000”] |
    + --------------------------------------------- +
    
  • JSON_OBJECT([key, val[, key, val] ...])

    计算键值对(可能为空)并返回包含这些对的JSON对象。 如果任何键名称 NULL 或参数数量为奇数, 则会发生错误

    MySQL的> SELECT JSON_OBJECT('id', 87, 'name', 'carrot');
    + ----------------------------------------- +
    | JSON_OBJECT('​​id',87,'name','carrot')|
    + ----------------------------------------- +
    | {“id”:87,“name”:“carrot”} |
    + ----------------------------------------- +
    
  • JSON_QUOTE(string)

    通过用双引号字符包装并转义内部引号和其他字符,然后将结果作为 utf8mb4 字符串 返回,将 字符串 引用为JSON值 NULL 如果参数是,则 返回 NULL

    此函数通常用于生成有效的JSON字符串文字以包含在JSON文档中。

    根据 表12.22“JSON_UNQUOTE()特殊字符转义序列”中 显示的转义序列,使用反斜杠转义某些特殊字符

    MySQL的> SELECT JSON_QUOTE('null'), JSON_QUOTE('"null"');
    + -------------------- + ---------------------- +
    | JSON_QUOTE('null')| JSON_QUOTE('“null”')|
    + -------------------- + ---------------------- +
    | “null”| “\”null \“”|
    + -------------------- + ---------------------- +
    MySQL的> SELECT JSON_QUOTE('[1, 2, 3]');
    + ------------------------- +
    | JSON_QUOTE('[1,2,3]')|
    + ------------------------- +
    | “[1,2,3]”|
    + ------------------------- +
    

您还可以通过 JSON 使用 其他类型的值转换为类型来获取JSON值 ; 有关更多信息, 请参阅 在JSON和非JSON值之间转换 CAST(value AS JSON)

可以使用两个生成JSON值的聚合函数。 JSON_ARRAYAGG() 将结果集作为单个JSON数组 JSON_OBJECTAGG() 返回 并将结果集作为单个JSON对象返回。 有关更多信息,请参见 第12.20节“聚合(GROUP BY)函数”

12.17.3搜索JSON值的函数

本节中的函数对JSON值执行搜索或比较操作,以从中提取数据,报告数据是否存在于其中的位置,或报告其中数据的路径。 MEMBER OF() 操作者在本文中也记载。

  • JSON_CONTAINS(target, candidate[, path])

    通过返回1或0来指示给定的 candidate JSON文档是否包含在 target JSON文档中,或者 - 如果提供了 path 参数 - 是否在目标内的特定路径中找到候选项。 返回 NULL 如果任何参数 NULL ,或者如果路径参数不识别目标文档的一部分。 如果发生错误 target candidate 不是有效的JSON文档,或者如果 path 参数不是一个有效的路径表达式或包含一个 * ** 通配符。

    要仅检查路径中是否存在任何数据,请 JSON_CONTAINS_PATH() 改用。

    以下规则定义了遏制:

    • 候选标量包含在目标标量中,当且仅当它们具有可比性且相等时。 如果它们具有相同的 JSON_TYPE() 类型, 则两个标量值是可比较的 ,除了类型的值 INTEGER 并且 DECIMAL 也彼此相当。

    • 当且仅当候选中的每个元素都包含在目标的某个元素中时,候选数组才包含在目标数组中。

    • 当且仅当候选者包含在目标的某个元素中时,候选非阵列包含在目标数组中。

    • 候选对象包含在目标对象中,当且仅当对于候选中的每个键时,在目标中存在具有相同名称的键,并且与候选键相关联的值包含在与目标键相关联的值中。

    否则,候选值不包含在目标文档中。

    mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
    mysql> SET @j2 = '1';
    mysql>SELECT JSON_CONTAINS(@j, @j2, '$.a');
    + ------------------------------- +
    | JSON_CONTAINS(@ j,@ j2,'$ .a')|
    + ------------------------------- +
    | 1 |
    + ------------------------------- +
    MySQL的> SELECT JSON_CONTAINS(@j, @j2, '$.b');
    + ------------------------------- +
    | JSON_CONTAINS(@ j,@ j2,'$ .b')|
    + ------------------------------- +
    | 0 |
    + ------------------------------- +
    
    mysql> SET @j2 = '{"d": 4}';
    mysql>SELECT JSON_CONTAINS(@j, @j2, '$.a');
    + ------------------------------- +
    | JSON_CONTAINS(@ j,@ j2,'$ .a')|
    + ------------------------------- +
    | 0 |
    + ------------------------------- +
    MySQL的> SELECT JSON_CONTAINS(@j, @j2, '$.c');
    + ------------------------------- +
    | JSON_CONTAINS(@ j,@ j2,'$ .c')|
    + ------------------------------- +
    | 1 |
    + ------------------------------- +
    
  • JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...)

    返回0或1以指示JSON文档是否包含给定路径或路径的数据。 NULL 如果有任何参数,则 返回 NULL 如果 json_doc 参数不是有效的JSON文档,任何 path 参数不是有效的路径表达式,或者 one_or_all 不是 'one' 则会发生错误 'all'

    要检查路径中的特定值,请 JSON_CONTAINS() 改用。

    如果文档中不存在指定的路径,则返回值为0。 否则,返回值取决于 one_or_all 参数:

    • 'one' :如果文档中至少存在一个路径,则为1,否则为0。

    • 'all' :如果文档中存在所有路径,则为1,否则为0。

    mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
    mysql>SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e');
    + --------------------------------------------- +
    | JSON_CONTAINS_PATH(@ j,'one','$ .a','$ .e')|
    + --------------------------------------------- +
    | 1 |
    + --------------------------------------------- +
    MySQL的> SELECT JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.e');
    + --------------------------------------------- +
    | JSON_CONTAINS_PATH(@j,'all','$ .a','$ .e')|
    + --------------------------------------------- +
    | 0 |
    + --------------------------------------------- +
    MySQL的> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.c.d');
    + ---------------------------------------- +
    | JSON_CONTAINS_PATH(@j,'one','$ .c.d')|
    + ---------------------------------------- +
    | 1 |
    + ---------------------------------------- +
    MySQL的> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a.d');
    + ---------------------------------------- +
    | JSON_CONTAINS_PATH(@ j,'one','$ .a.d')|
    + ---------------------------------------- +
    | 0 |
    + ---------------------------------------- +
    
  • JSON_EXTRACT(json_doc, path[, path] ...)

    返回JSON文档中的数据,该文档从 path 参数 匹配的文档部分中选择 返回 NULL 如果任何参数 NULL 或没有路径找到文档中的一个值。 如果 json_doc 参数不是有效的JSON文档或任何 path 参数不是有效的路径表达式, 则会发生错误

    返回值由 path 参数 匹配的所有值组成 如果这些参数可能返回多个值,则匹配的值将按照与生成它们的路径对应的顺序自动包装为数组。 否则,返回值是单个匹配的值。

    MySQL的> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]');
    + -------------------------------------------- +
    | JSON_EXTRACT('[10,20,[30,40]]','$ [1]')|
    + -------------------------------------------- +
    | 20 |
    + -------------------------------------------- +
    MySQL的> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]');
    + ------------------------------------------------- --- +
    | JSON_EXTRACT('[10,20,[30,40]]','$ [1]','$ [0]')|
    + ------------------------------------------------- --- +
    | [20,10] |
    + ------------------------------------------------- --- +
    MySQL的> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]');
    + ----------------------------------------------- +
    | JSON_EXTRACT('[10,20,[30,40]]','$ [2] [*]')|
    + ----------------------------------------------- +
    | [30,40] |
    + ----------------------------------------------- +
    

    MySQL支持 -> 运算符作为此函数的简写,与2个参数一起使用,其中左侧是 JSON 列标识符(不是表达式),右侧是要在列中匹配的JSON路径。

  • column->path

    当与两个参数一起使用时 -> 运算符充当 JSON_EXTRACT() 函数 的别名, 左侧是列标识符,右侧是根据JSON文档评估的JSON路径(列值)。 您可以使用此类表达式代替SQL语句中出现的列标识符。

    SELECT 这里显示 的两个 语句产生相同的输出:

    的MySQL> SELECT c, JSON_EXTRACT(c, "$.id"), g
         > FROM jemp
         > WHERE JSON_EXTRACT(c, "$.id") > 1
         >ORDER BY JSON_EXTRACT(c, "$.name");
    + ------------------------------- + ----------- + ----- -  +
    | c | c  - >“$。id”| g |
    + ------------------------------- + ----------- + ----- -  +
    | {“id”:“3”,“name”:“Barney”} | “3”| 3 |
    | {“id”:“4”,“name”:“Betty”} | “4”| 4 |
    | {“id”:“2”,“name”:“Wilma”} | “2”| 2 |
    + ------------------------------- + ----------- + ----- -  +
    3组(0.00秒)
    
    的MySQL> SELECT c, c->"$.id", g
         > FROM jemp
         > WHERE c->"$.id" > 1
         >ORDER BY c->"$.name";
    + ------------------------------- + ----------- + ----- -  +
    | c | c  - >“$。id”| g |
    + ------------------------------- + ----------- + ----- -  +
    | {“id”:“3”,“name”:“Barney”} | “3”| 3 |
    | {“id”:“4”,“name”:“Betty”} | “4”| 4 |
    | {“id”:“2”,“name”:“Wilma”} | “2”| 2 |
    + ------------------------------- + ----------- + ----- -  +
    3组(0.00秒)
    

    此功能不限 SELECT 于此,如下所示:

    MySQL的> ALTER TABLE jemp ADD COLUMN n INT;
    查询正常,0行受影响(0.68秒)
    记录:0重复:0警告:0
    
    MySQL的> UPDATE jemp SET n=1 WHERE c->"$.id" = "4";
    查询正常,1行受影响(0.04秒)
    匹配的行数:1已更改:1警告:0
    
    的MySQL> SELECT c, c->"$.id", g, n
         > FROM jemp
         > WHERE JSON_EXTRACT(c, "$.id") > 1
         >ORDER BY c->"$.name";
    + ------------------------------- + ----------- + ----- -  + ------ +
    | c | c  - >“$。id”| g | n |
    + ------------------------------- + ----------- + ----- -  + ------ +
    | {“id”:“3”,“name”:“Barney”} | “3”| 3 | NULL |
    | {“id”:“4”,“name”:“Betty”} | “4”| 4 | 1 |
    | {“id”:“2”,“name”:“Wilma”} | “2”| 2 | NULL |
    + ------------------------------- + ----------- + ----- -  + ------ +
    3组(0.00秒)
    
    MySQL的> DELETE FROM jemp WHERE c->"$.id" = "4";
    查询正常,1行受影响(0.04秒)
    
    的MySQL> SELECT c, c->"$.id", g, n
         > FROM jemp
         > WHERE JSON_EXTRACT(c, "$.id") > 1
         >ORDER BY c->"$.name";
    + ------------------------------- + ----------- + ----- -  + ------ +
    | c | c  - >“$。id”| g | n |
    + ------------------------------- + ----------- + ----- -  + ------ +
    | {“id”:“3”,“name”:“Barney”} | “3”| 3 | NULL |
    | {“id”:“2”,“name”:“Wilma”} | “2”| 2 | NULL |
    + ------------------------------- + ----------- + ----- -  + ------ +
    2行(0.00秒)
    

    (有关 用于创建和填充刚刚显示的表的语句, 请参阅 索引生成的列以提供JSON列索引 。)

    这也适用于JSON数组值,如下所示:

    MySQL的> CREATE TABLE tj10 (a JSON, b INT);
    查询OK,0行受影响(0.26秒)
    
    mysql INSERT INTO tj10
         >>VALUES ("[3,10,5,17,44]", 33), ("[3,10,5,17,[22,44,66]]", 0);
    查询正常,1行受影响(0.04秒)
    
    MySQL的> SELECT a->"$[4]" FROM tj10;
    + -------------- +
    | a  - >“$ [4]”|
    + -------------- +
    | 44 |
    | [22,44,66] |
    + -------------- +
    2行(0.00秒)
    
    MySQL的> SELECT * FROM tj10 WHERE a->"$[0]" = 3;
    + ------------------------------ + ------ +
    | a | b |
    + ------------------------------ + ------ +
    | [3,10,5,17,44] | 33 |
    | [3,10,5,17,[22,44,66]] | 0 |
    + ------------------------------ + ------ +
    2行(0.00秒)
    

    支持嵌套数组。 使用的表达式 -> 计算 NULL 好像在目标JSON文档中找不到匹配的键,如下所示:

    MySQL的> SELECT * FROM tj10 WHERE a->"$[4][1]" IS NOT NULL;
    + ------------------------------ + ------ +
    | a | b |
    + ------------------------------ + ------ +
    | [3,10,5,17,[22,44,66]] | 0 |
    + ------------------------------ + ------ +
    
    MySQL的> SELECT a->"$[4][1]" FROM tj10;
    + -------------- +
    | a  - >“$ [4] [1]”|
    + -------------- +
    | NULL |
    | 44 |
    + -------------- +
    2行(0.00秒)
    

    这与使用时的情况相同 JSON_EXTRACT()

    MySQL的> SELECT JSON_EXTRACT(a, "$[4][1]") FROM tj10;
    + ---------------------------- +
    | JSON_EXTRACT(a,“$ [4] [1]”)|
    + ---------------------------- +
    | NULL |
    | 44 |
    + ---------------------------- +
    2行(0.00秒)
    
  • column->>path

    这是一个改进的,不引用的提取操作符。 -> 操作者简单地提取的值时, ->> 在加法运算unquotes所提取的结果。 换句话说,给定 JSON 列值 column 和路径表达式 path ,以下三个表达式返回相同的值:

    ->> 操作可用于任何 JSON_UNQUOTE(JSON_EXTRACT()) 将被允许。 这包括(但不限于) SELECT 列表, WHERE HAVING 条款,并 ORDER BY GROUP BY 条款。

    接下来的几个语句演示 ->> mysql 客户端中 其他表达式的 一些 运算符等价

    MySQL的> SELECT * FROM jemp WHERE g > 2;
    + ------------------------------- + ------ +
    | c | g |
    + ------------------------------- + ------ +
    | {“id”:“3”,“name”:“Barney”} | 3 |
    | {“id”:“4”,“name”:“Betty”} | 4 |
    + ------------------------------- + ------ +
    2行(0.01秒)
    
    mysql> SELECT c->'$.name' AS name
        - >     FROM jemp WHERE g > 2;
    + ---------- +
    | 名字|
    + ---------- +
    | “巴尼”|
    | “贝蒂”|
    + ---------- +
    2行(0.00秒)
    
    mysql> SELECT JSON_UNQUOTE(c->'$.name') AS name
        - >     FROM jemp WHERE g > 2;
    + -------- +
    | 名字|
    + -------- +
    | 巴尼|
    | 贝蒂|
    + -------- +
    2行(0.00秒)
    
    mysql> SELECT c->>'$.name' AS name
        - >     FROM jemp WHERE g > 2;
    + -------- +
    | 名字|
    + -------- +
    | 巴尼|
    | 贝蒂|
    + -------- +
    2行(0.00秒)
    

    请参阅 索引生成的列以提供JSON列索引 ,用于在 jemp 刚刚显示的示例集中 创建和填充 的SQL语句

    此运算符也可以与JSON数组一起使用,如下所示:

    MySQL的> CREATE TABLE tj10 (a JSON, b INT);
    查询OK,0行受影响(0.26秒)
    
    mysql> INSERT INTO tj10 VALUES
        - >      ('[3,10,5,"x",44]', 33),
        - >     ('[3,10,5,17,[22,"y",66]]', 0);
    查询OK,2行受影响(0.04秒)
    记录:2个重复:0个警告:0
    
    MySQL的> SELECT a->"$[3]", a->"$[4][1]" FROM tj10;
    + ----------- -------------- + +
    | a  - >“$ [3]”| a  - >“$ [4] [1]”|
    + ----------- -------------- + +
    | “x”| NULL |
    | 17 | “y”|
    + ----------- -------------- + +
    2行(0.00秒)
    
    MySQL的> SELECT a->>"$[3]", a->>"$[4][1]" FROM tj10;
    + ------------ + --------------- +
    | a  -  >>“$ [3]”| a  -  >>“$ [4] [1]”|
    + ------------ + --------------- +
    | x | NULL |
    | 17 | y |
    + ------------ + --------------- +
    2行(0.00秒)
    

    与此同时 -> ->> 运算符总是在输出中展开 EXPLAIN ,如下例所示:

    mysql> EXPLAIN SELECT c->>'$.name' AS name
        - >     FROM jemp WHERE g > 2\G
    *************************** 1。排******************** *******
               id:1
      select_type:SIMPLE
            桌子:jemp
       分区:NULL
             类型:范围
    possible_keys:i
              关键:我
          key_len:5
              ref:NULL
             行:2
         过滤:100.00
            额外:使用在哪里
    1排,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS\G
    *************************** 1。排******************** *******
      等级:注意
       代码:1003
    消息:/ *选择#1 * /选择
    json_unquote(json_extract(`jtest` .jemp``c`,'$。name'))AS`name`来自
    `jtest``jemp` where(`jtest` .jemp``g`> 2)
    1排(0.00秒)
    

    这类似于MySQL -> 在相同情况下 扩展 运算符的方式。

  • JSON_KEYS(json_doc[, path])

    从JSON对象的顶级值返回键作为JSON数组,或者,如果 path 给出参数,则返回所选路径中的顶级键。 NULL 如果有任何参数 NULL ,则 返回 参数 ,该 json_doc 参数不是对象,或者 path ,如果给定,则不返回对象。 如果 json_doc 参数不是有效的JSON文档或 path 参数不是有效的路径表达式或包含 * ** 通配符, 则会发生错误

    如果所选对象为空,则结果数组为空。 如果顶级值具有嵌套的子对象,则返回值不包括来自这些子对象的键。

    MySQL的> SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}');
    + --------------------------------------- +
    | JSON_KEYS('{“a”:1,“b”:{“c”:30}}')|
    + --------------------------------------- +
    | [“a”,“b”] |
    + --------------------------------------- +
    MySQL的> SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b');
    + ---------------------------------------------- +
    | JSON_KEYS('{“a”:1,“b”:{“c”:30}}','$ .b')|
    + ---------------------------------------------- +
    | [“c”] |
    + ---------------------------------------------- +
    
  • JSON_OVERLAPS(json_doc1, json_doc2)

    比较两个JSON文档。 如果两个文档具有任何共同的键值对或数组元素,则返回true(1)。 如果两个参数都是标量,则该函数执行简单的相等性测试。

    该函数用作对应函数 JSON_CONTAINS() ,其要求搜索到的数组的所有元素都存在于搜索的数组中。因此, JSON_CONTAINS() 在执行 AND 操作的同时对搜索键 JSON_OVERLAPS() 执行 OR 操作。

    当两个比较两个数组时, JSON_OVERLAPS() 如果它们共享一个或多个共同的数组元素 ,则 返回true;如果不共享 ,则 返回false:

    MySQL的> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]");
    + --------------------------------------- +
    | JSON_OVERLAPS(“[1,3,5,7]”,“[2,5,7]”)|
    + --------------------------------------- +
    | 1 |
    + --------------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]");
    + --------------------------------------- +
    | JSON_OVERLAPS(“[1,3,5,7]”,“[2,6,7]”)|
    + --------------------------------------- +
    | 1 |
    + --------------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]");
    + --------------------------------------- +
    | JSON_OVERLAPS(“[1,3,5,7]”,“[2,6,8]”)|
    + --------------------------------------- +
    | 0 |
    + --------------------------------------- +
    1排(0.00秒)
    

    部分匹配被视为不匹配,如下所示:

    MySQL的> SELECT JSON_OVERLAPS('[[1,2],[3,4],5]', '[1,[2,3],[4,5]]');
    + ------------------------------------------------- ---- +
    | JSON_OVERLAPS('[[1,2],[3,4],5]','[1,[2,3],[4,5]]')|
    + ------------------------------------------------- ---- +
    | 0 |
    + ------------------------------------------------- ---- +
    1排(0.00秒)
    

    比较对象时,如果它们至少有一个共同的键值对,则结果为真。

    MySQL的> SELECT JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"c":1,"e":10,"f":1,"d":10}');
    + ------------------------------------------------- ---------------------- +
    | JSON_OVERLAPS('{“a”:1,“b”:10,“d”:10}','{“c”:1,“e”:10,“f”:1,“d”:10} ')|
    + ------------------------------------------------- ---------------------- +
    | 1 |
    + ------------------------------------------------- ---------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"a":5,"e":10,"f":1,"d":20}');
    + ------------------------------------------------- ---------------------- +
    | JSON_OVERLAPS('{“a”:1,“b”:10,“d”:10}','{“a”:5,“e”:10,“f”:1,“d”:20} ')|
    + ------------------------------------------------- ---------------------- +
    | 0 |
    + ------------------------------------------------- ---------------------- +
    1排(0.00秒)
    

    如果使用两个标量作为函数的参数,则 JSON_OVERLAPS() 执行一个简单的相等测试:

    MySQL的> SELECT JSON_OVERLAPS('5', '5');
    + ------------------------- +
    | JSON_OVERLAPS('5','5')|
    + ------------------------- +
    | 1 |
    + ------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT JSON_OVERLAPS('5', '6');
    + ------------------------- +
    | JSON_OVERLAPS('5','6')|
    + ------------------------- +
    | 0 |
    + ------------------------- +
    1排(0.00秒)
    

    将标量与数组进行比较时,会 JSON_OVERLAPS() 尝试将标量视为数组元素。 在此示例中,第二个参数 6 被解释为 [6] ,如下所示:

    MySQL的> SELECT JSON_OVERLAPS('[4,5,6,7]', '6');
    + --------------------------------- +
    | JSON_OVERLAPS('[4,5,6,7]','6')|
    + --------------------------------- +
    | 1 |
    + --------------------------------- +
    1排(0.00秒)
    

    该函数不执行类型转换:

    MySQL的> SELECT JSON_OVERLAPS('[4,5,"6",7]', '6');
    + ----------------------------------- +
    | JSON_OVERLAPS('[4,5,“6”,7]','6')|
    + ----------------------------------- +
    | 0 |
    + ----------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT JSON_OVERLAPS('[4,5,6,7]', '"6"');
    + ----------------------------------- +
    | JSON_OVERLAPS('[4,5,6,7]','“6”')|
    + ----------------------------------- +
    | 0 |
    + ----------------------------------- +
    1排(0.00秒)
    

    JSON_OVERLAPS() 在MySQL 8.0.17中添加了。

  • JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])

    返回JSON文档中给定字符串的路径。 NULL 如果任何 ,或者 参数是 json_doc 返回 ; 文件中 存在; 或者 没找到。 发生错误时,如果 参数不是一个有效的JSON文档,任何 参数不是一个有效的路径表达式, 是不 ,或者 是不是一个常量表达式。 search_str path NULL path search_str json_doc path one_or_all 'one' 'all' escape_char

    one_or_all 参数影响搜索,如下所示:

    • 'one' :搜索在第一个匹配后终止,并返回一个路径字符串。 未定义哪个匹配首先考虑。

    • 'all' :搜索返回所有匹配的路径字符串,以便不包含重复的路径。 如果有多个字符串,则将它们自动包装为数组。 数组元素的顺序未定义。

    search_str 搜索字符串参数中, % _ 字符用于 LIKE 运算符: % 匹配任意数量的字符(包括零个字符),并且只 _ 匹配一个字符。

    在搜索字符串中 指定文字 % _ 字符,请在其前面加上转义字符。 默认值是 \ ,如果 escape_char 参数丢失或 NULL 否则, escape_char 必须是空或一个字符的常量。

    有关匹配和转义字符行为的详细信息,请参阅的说明 LIKE 12.5.1节,“字符串比较函数” 对于转义字符处理,与 LIKE 行为 的区别 在于转义字符 JSON_SEARCH() 必须在编译时计算为常量,而不仅仅是在执行时。 例如,如果 JSON_SEARCH() 在预准备语句中使用 if 并且使用 escape_char 参数提供 ? 参数,则参数值在执行时可能是常量,但不是在编译时。

    MySQL的> SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
    
    MySQL的> SELECT JSON_SEARCH(@j, 'one', 'abc');
    + ------------------------------- +
    | JSON_SEARCH(@j,'one','abc')|
    + ------------------------------- +
    | “$ [0]”|
    + ------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', 'abc');
    + ------------------------------- +
    | JSON_SEARCH(@j,'all','abc')|
    + ------------------------------- +
    | [“$ [0]”,“$ [2] .x”] |
    + ------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', 'ghi');
    + ------------------------------- +
    | JSON_SEARCH(@j,'all','ghi')|
    + ------------------------------- +
    | NULL |
    + ------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10');
    + ------------------------------ +
    | JSON_SEARCH(@j,'all','10')|
    + ------------------------------ +
    | “$ [1] [0] .k”|
    + ------------------------------ +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$');
    + ----------------------------------------- +
    | JSON_SEARCH(@ j,'all','10',NULL,'$')|
    + ----------------------------------------- +
    | “$ [1] [0] .k”|
    + ----------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[*]');
    + -------------------------------------------- +
    | JSON_SEARCH(@j,'all','10',NULL,'$ [*]')|
    + -------------------------------------------- +
    | “$ [1] [0] .k”|
    + -------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$**.k');
    + --------------------------------------------- +
    | JSON_SEARCH(@j,'all','10',NULL,'$ **。k')|
    + --------------------------------------------- +
    | “$ [1] [0] .k”|
    + --------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[*][0].k');
    + ------------------------------------------------- +
    | JSON_SEARCH(@ j,'all','10',NULL,'$ [*] [0] .k')|
    + ------------------------------------------------- +
    | “$ [1] [0] .k”|
    + ------------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[1]');
    + -------------------------------------------- +
    | JSON_SEARCH(@j,'all','10',NULL,'$ [1]')|
    + -------------------------------------------- +
    | “$ [1] [0] .k”|
    + -------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[1][0]');
    + ----------------------------------------------- +
    | JSON_SEARCH(@ j,'all','10',NULL,'$ [1] [0]')|
    + ----------------------------------------------- +
    | “$ [1] [0] .k”|
    + ----------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', 'abc', NULL, '$[2]');
    + --------------------------------------------- +
    | JSON_SEARCH(@ j,'all','abc',NULL,'$ [2]')|
    + --------------------------------------------- +
    | “$ [2] .x”|
    + --------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%a%');
    + ------------------------------- +
    | JSON_SEARCH(@j,'all','%a%')|
    + ------------------------------- +
    | [“$ [0]”,“$ [2] .x”] |
    + ------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%b%');
    + ------------------------------- +
    | JSON_SEARCH(@j,'all','%b%')|
    + ------------------------------- +
    | [“$ [0]”,“$ [2] .x”,“$ [3] .y”] |
    + ------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[0]');
    + --------------------------------------------- +
    | JSON_SEARCH(@j,'all','%b%',NULL,'$ [0]')|
    + --------------------------------------------- +
    | “$ [0]”|
    + --------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[2]');
    + --------------------------------------------- +
    | JSON_SEARCH(@j,'all','%b%',NULL,'$ [2]')|
    + --------------------------------------------- +
    | “$ [2] .x”|
    + --------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[1]');
    + --------------------------------------------- +
    | JSON_SEARCH(@j,'all','%b%',NULL,'$ [1]')|
    + --------------------------------------------- +
    | NULL |
    + --------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[1]');
    + ------------------------------------------- +
    | JSON_SEARCH(@j,'all','%b%','','$ [1]')|
    + ------------------------------------------- +
    | NULL |
    + ------------------------------------------- +
    
    MySQL的> SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[3]');
    + ------------------------------------------- +
    | JSON_SEARCH(@j,'all','%b%','','$ [3]')|
    + ------------------------------------------- +
    | “$ [3] .y”|
    + ------------------------------------------- +
    

    有关MySQL支持JSON的路径语法,包括有关通配符运营规则的详细信息 * ,并 ** 请参阅 JSON路径语法

  • value MEMBER OF(json_array)

    如果 value 是元素 json_array ,则 返回true(1) ,否则返回false(0)。 value 必须是标量或JSON文档; 如果它是标量,则运算符会尝试将其视为JSON数组的元素。

    简单标量被视为数组值,如下所示:

    MySQL的> SELECT 17 MEMBER OF('[23, "abc", 17, "ab", 10]');
    + ------------------------------------------- +
    | 17成员('[23,“abc”,17,“ab”,10]')|
    + ------------------------------------------- +
    | 1 |
    + ------------------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]');
    + --------------------------------------------- +
    | 'ab'成员('[23,“abc”,17,“ab”,10]')|
    + --------------------------------------------- +
    | 1 |
    + --------------------------------------------- +
    1排(0.00秒)
    

    数组元素值的部分匹配不匹配:

    MySQL的> SELECT 7 MEMBER OF('[23, "abc", 17, "ab", 10]');
    + ------------------------------------------ +
    | 7成员('[23,“abc”,17,“ab”,10]')|
    + ------------------------------------------ +
    | 0 |
    + ------------------------------------------ +
    1排(0.00秒)
    
    MySQL的> SELECT 'a' MEMBER OF('[23, "abc", 17, "ab", 10]');
    + -------------------------------------------- +
    | 'a'成员('[23,“abc”,17,“ab”,10]')|
    + -------------------------------------------- +
    | 0 |
    + -------------------------------------------- +
    1排(0.00秒)
    

    不执行与字符串类型之间的转换:

    mysql> SELECT 
        - > 17 MEMBER OF('[23, "abc", "17", "ab", 10]'), 
        - >"17" MEMBER OF('[23, "abc", 17, "ab", 10]')\G
    *************************** 1。排******************** *******
    17成员('[23,“abc”,“17”,“ab”,10]'):0
    “17”成员('[23,“abc”,17,“ab”,10]'):0
    1排(0.00秒)
    

    要将此运算符与其本身为数组的值一起使用,必须将其显式转换为JSON数组。 你可以这样做 CAST(... AS JSON)

    MySQL的> SELECT CAST('[4,5]' AS JSON) MEMBER OF('[[3,4],[4,5]]');
    + ------------------------------------------------- -  +
    | CAST('[4,5]'AS JSON)成员('[[3,4],[4,5]]')|
    + ------------------------------------------------- -  +
    | 1 |
    + ------------------------------------------------- -  +
    1排(0.00秒)
    

    也可以使用 JSON_ARRAY() 函数 执行必要的强制转换 ,如下所示:

    MySQL的> SELECT JSON_ARRAY(4,5) MEMBER OF('[[3,4],[4,5]]');
    + -------------------------------------------- +
    | JSON_ARRAY(4,5)成员('[[3,4],[4,5]]')|
    + -------------------------------------------- +
    | 1 |
    + -------------------------------------------- +
    1排(0.00秒)
    

    用作要测试的值或出现在目标数组中的任何JSON对象必须使用 CAST(... AS JSON) 强制转换为正确的类型 JSON_OBJECT() 此外,包含JSON对象的目标数组本身必须使用 JSON_ARRAY 这在以下语句序列中得到证明:

    MySQL的> SET @a = CAST('{"a":1}' AS JSON);
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SET @b = JSON_OBJECT("b", 2);
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SET @c = JSON_ARRAY(17, @b, "abc", @a, 23);
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @a MEMBER OF(@c), @b MEMBER OF(@c);
    + ------------------ + ------------------ +
    | @a成员(@c)| @b MEMBER OF(@c)|
    + ------------------ + ------------------ +
    | 1 | 1 |
    + ------------------ + ------------------ +
    1排(0.00秒)
    

    MEMBER OF() 操作符已添加到MySQL 8.0.17中。

12.17.4修改JSON值的函数

本节中的函数修改JSON值并返回结果。

  • JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)

    将值附加到JSON文档中指定数组的末尾并返回结果。 NULL 如果有任何参数,则 返回 NULL 如果发生错误 json_doc 的参数是不是一个有效的JSON文档或任何 path 参数是不是有效的路径表达式或包含一个 * ** 通配符。

    路径值对从左到右进行评估。 通过评估一对产生的文档成为评估下一对的新值。

    如果路径选择标量或对象值,则该值将在数组中自动包装,并将新值添加到该数组中。 路径未标识JSON文档中的任何值的对将被忽略。

    mysql> SET @j = '["a", ["b", "c"], "d"]';
    mysql>SELECT JSON_ARRAY_APPEND(@j, '$[1]', 1);
    + ---------------------------------- +
    | JSON_ARRAY_APPEND(@ j,'$ [1]',1)|
    + ---------------------------------- +
    | [“a”,[“b”,“c”,1],“d”] |
    + ---------------------------------- +
    MySQL的> SELECT JSON_ARRAY_APPEND(@j, '$[0]', 2);
    + ---------------------------------- +
    | JSON_ARRAY_APPEND(@ j,'$ [0]',2)|
    + ---------------------------------- +
    | [[“a”,2],[“b”,“c”],“d”] |
    + ---------------------------------- +
    MySQL的> SELECT JSON_ARRAY_APPEND(@j, '$[1][0]', 3);
    + ------------------------------- +
    | JSON_ARRAY_APPEND(@ j,'$ [1] [0]',3)|
    + ------------------------------- +
    | [“a”,[[“b”,3],“c”],“d”] |
    + ------------------------------- +
    
    mysql> SET @j = '{"a": 1, "b": [2, 3], "c": 4}';
    mysql>SELECT JSON_ARRAY_APPEND(@j, '$.b', 'x');
    + ------------------------------------ +
    | JSON_ARRAY_APPEND(@ j,'$ .b','x')|
    + ------------------------------------ +
    | {“a”:1,“b”:[2,3,“x”],“c”:4} |
    + ------------------------------------ +
    MySQL的> SELECT JSON_ARRAY_APPEND(@j, '$.c', 'y');
    + -------------------------------------- +
    | JSON_ARRAY_APPEND(@ j,'$ .c','y')|
    + -------------------------------------- +
    | {“a”:1,“b”:[2,3],“c”:[4,“y”]} |
    + -------------------------------------- +
    
    mysql> SET @j = '{"a": 1}';
    mysql>SELECT JSON_ARRAY_APPEND(@j, '$', 'z');
    + --------------------------------- +
    | JSON_ARRAY_APPEND(@ j,'$','z')|
    + --------------------------------- +
    | [{“a”:1},“z”] |
    + --------------------------------- +
    

    在MySQL 5.7中,这个函数被命名了 JSON_APPEND() MySQL 8.0不再支持该名称。

  • JSON_ARRAY_INSERT(json_doc, path, val[, path, val] ...)

    更新JSON文档,插入文档中的数组并返回修改后的文档。 NULL 如果有任何参数,则 返回 NULL 如果发生错误 json_doc 的参数是不是一个有效的JSON文档或任何 path 参数是不是有效的路径表达式或包含一个 * ** 通配符或不与一个数组元素标识符结束。

    路径值对从左到右进行评估。 通过评估一对产生的文档成为评估下一对的新值。

    路径未标识JSON文档中的任何数组的对将被忽略。 如果路径标识数组元素,则在该元素位置插入相应的值,将任何后续值移到右侧。 如果路径标识超出数组末尾的数组位置,则该值将插入数组的末尾。

    mysql> SET @j = '["a", {"b": [1, 2]}, [3, 4]]';
    mysql>SELECT JSON_ARRAY_INSERT(@j, '$[1]', 'x');
    + ------------------------------------ +
    | JSON_ARRAY_INSERT(@ j,'$ [1]','x')|
    + ------------------------------------ +
    | [“a”,“x”,{“b”:[1,2]},[3,4]] |
    + ------------------------------------ +
    MySQL的> SELECT JSON_ARRAY_INSERT(@j, '$[100]', 'x');
    + -------------------------------------- +
    | JSON_ARRAY_INSERT(@ j,'$ [100]','x')|
    + -------------------------------------- +
    | [“a”,{“b”:[1,2]},[3,4],“x”] |
    + -------------------------------------- +
    MySQL的> SELECT JSON_ARRAY_INSERT(@j, '$[1].b[0]', 'x');
    + ----------------------------------------- +
    | JSON_ARRAY_INSERT(@ j,'$ [1] .b [0]','x')|
    + ----------------------------------------- +
    | [“a”,{“b”:[“x”,1,2]},[3,4]] |
    + ----------------------------------------- +
    MySQL的> SELECT JSON_ARRAY_INSERT(@j, '$[2][1]', 'y');
    + --------------------------------------- +
    | JSON_ARRAY_INSERT(@ j,'$ [2] [1]','y')|
    + --------------------------------------- +
    | [“a”,{“b”:[1,2]},[3,“y”,4]] |
    + --------------------------------------- +
    MySQL的> SELECT JSON_ARRAY_INSERT(@j, '$[0]', 'x', '$[2][1]', 'y');
    + ------------------------------------------------- --- +
    | JSON_ARRAY_INSERT(@ j,'$ [0]','x','$ [2] [1]','y')|
    + ------------------------------------------------- --- +
    | [“x”,“a”,{“b”:[1,2]},[3,4]] |
    + ------------------------------------------------- --- +
    

    较早的修改会影响数组中以下元素的位置,因此同一 JSON_ARRAY_INSERT() 调用 中的后续路径 应考虑到这一点。 在最后一个示例中,第二个路径不插入任何内容,因为路径在第一次插入后不再匹配任何内容。

  • JSON_INSERT(json_doc, path, val[, path, val] ...)

    将数据插入JSON文档并返回结果。 NULL 如果有任何参数,则 返回 NULL 如果发生错误 json_doc 的参数是不是一个有效的JSON文档或任何 path 参数是不是有效的路径表达式或包含一个 * ** 通配符。

    路径值对从左到右进行评估。 通过评估一对产生的文档成为评估下一对的新值。

    将忽略文档中现有路径的路径值对,并且不会覆盖现有文档值。 如果路径标识了以下类型的值之一,则文档中不存在路径的路径值对会将值添加到文档中:

    • 不存在于现有对象中的成员。 该成员将添加到对象并与新值关联。

    • 位于现有数组末尾的位置。 使用新值扩展数组。 如果现有值不是数组,则将其作为数组自动包装,然后使用新值进行扩展。

    否则,将忽略文档中不存在路径的路径 - 值对,但不起作用。

    为了进行比较 JSON_INSERT() JSON_REPLACE() 以及 JSON_SET() ,看到的讨论 JSON_SET()

    mysql> SET @j = '{ "a": 1, "b": [2, 3]}';
    mysql>SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]');
    + ------------------------------------------------- --- +
    | JSON_INSERT(@ j,'$ .a',10,'$ .c','[true,false]')|
    + ------------------------------------------------- --- +
    | {“a”:1,“b”:[2,3],“c”:“[true,false]”} |
    + ------------------------------------------------- --- +
    

    结果中列出的第三个也是最后一个值是带引号的字符串,而不是像第二个那样的数组(在输出中没有引用); 不会将值转换为JSON类型。 要将数组作为数组插入,必须显式执行此类强制转换,如下所示:

    MySQL的> SELECT JSON_INSERT(@j, '$.a', 10, '$.c', CAST('[true, false]' AS JSON));
    + ------------------------------------------------- ----------------- +
    | JSON_INSERT(@ j,'$ .a',10,'$ .c',CAST('[true,false]'AS JSON))|
    + ------------------------------------------------- ----------------- +
    | {“a”:1,“b”:[2,3],“c”:[true,false]} |
    + ------------------------------------------------- ----------------- +
    1排(0.00秒)
    
  • JSON_MERGE(json_doc, json_doc[, json_doc] ...)

    合并两个或多个JSON文档。 同义词 JSON_MERGE_PRESERVE() ; 在MySQL 8.0.3中已弃用,并且在将来的版本中将被删除。

    MySQL的> SELECT JSON_MERGE('[1, 2]', '[true, false]');
    + --------------------------------------- +
    | JSON_MERGE('[1,2]','[true,false]')|
    + --------------------------------------- +
    | [1,2,true,false] |
    + --------------------------------------- +
    1排,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS\G
    *************************** 1。排******************** *******
      等级:警告
       代码:1287
    消息:'JSON_MERGE'已弃用,将在以后的版本中删除。\
     请改用JSON_MERGE_PRESERVE / JSON_MERGE_PATCH
    1排(0.00秒)
    

    有关其他示例,请参阅相关条目 JSON_MERGE_PRESERVE()

  • JSON_MERGE_PATCH(json_doc, json_doc[, json_doc] ...)

    执行 符合 RFC 7396 的两个或多个JSON文档的合并,并返回合并的结果,而不保留具有重复键的成员。 如果至少有一个作为参数传递给此函数的文档无效,则引发错误。

    注意

    有关此函数与之间差异的解释和示例 JSON_MERGE_PRESERVE() ,请参阅与 JSON_MERGE_PRESERVE()相比较的JSON_MERGE_PATCH()

    JSON_MERGE_PATCH() 执行合并如下:

    1. 如果第一个参数不是对象,则合并的结果与将空对象与第二个参数合并的结果相同。

    2. 如果第二个参数不是对象,则合并的结果是第二个参数。

    3. 如果两个参数都是对象,则合并的结果是具有以下成员的对象:

      • 第一个对象的所有成员没有在第二个对象中具有相同键的相应成员。

      • 第二个对象的所有成员在第一个对象中没有对应的键,其值不是JSON null 文字。

      • 具有在第一个和第二个对象中存在的键的所有成员,并且其在第二个对象中的值不是JSON null 文字。 这些成员的值是以递归方式将第一个对象中的值与第二个对象中的值合并的结果。

    有关其他信息,请参阅 JSON值的规范化,合并和自动包装

    MySQL的> SELECT JSON_MERGE_PATCH('[1, 2]', '[true, false]');
    + --------------------------------------------- +
    | JSON_MERGE_PATCH('[1,2]','[true,false]')|
    + --------------------------------------------- +
    | [true,false] |
    + --------------------------------------------- +
    
    MySQL的> SELECT JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}');
    + ------------------------------------------------- +
    | JSON_MERGE_PATCH('{“name”:“x”}','{“id”:47}')|
    + ------------------------------------------------- +
    | {“id”:47,“name”:“x”} |
    + ------------------------------------------------- +
    
    MySQL的> SELECT JSON_MERGE_PATCH('1', 'true');
    + ------------------------------- +
    | JSON_MERGE_PATCH('1','true')|
    + ------------------------------- +
    | 是的|
    + ------------------------------- +
    
    MySQL的> SELECT JSON_MERGE_PATCH('[1, 2]', '{"id": 47}');
    + ------------------------------------------ +
    | JSON_MERGE_PATCH('[1,2]','{“id”:47}')|
    + ------------------------------------------ +
    | {“id”:47} |
    + ------------------------------------------ +
    
    mysql SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }',
         >>     '{ "a": 3, "c":4 }');
    + ------------------------------------------------- ---------- +
    | JSON_MERGE_PATCH('{“a”:1,“b”:2}','{“a”:3,“c”:4}')|
    + ------------------------------------------------- ---------- +
    | {“a”:3,“b”:2,“c”:4} |
    + ------------------------------------------------- ---------- +
    
    mysql SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }',
         >>     '{ "a": 5, "d":6 }');
    + ------------------------------------------------- ------------------------------ +
    | JSON_MERGE_PATCH('{“a”:1,“b”:2}','{“a”:3,“c”:4}','{“a”:5,“d”:6}') |
    + ------------------------------------------------- ------------------------------ +
    | {“a”:5,“b”:2,“c”:4,“d”:6} |
    + ------------------------------------------------- ------------------------------ +
    

    您可以使用此函数通过 null 在seond参数中 指定 相同成员的值 来删除成员 ,如下所示:

    MySQL的> SELECT JSON_MERGE_PATCH('{"a":1, "b":2}', '{"b":null}');
    + ------------------------------------------------- -  +
    | JSON_MERGE_PATCH('{“a”:1,“b”:2}','{“b”:null}')|
    + ------------------------------------------------- -  +
    | {“a”:1} |
    + ------------------------------------------------- -  +
    

    这个例子表明该函数以递归方式运行; 也就是说,成员的值不仅限于标量,而是它们本身可以是JSON文档:

    MySQL的> SELECT JSON_MERGE_PATCH('{"a":{"x":1}}', '{"a":{"y":2}}');
    + ------------------------------------------------- --- +
    | JSON_MERGE_PATCH('{“a”:{“x”:1}}','{“a”:{“y”:2}}')|
    + ------------------------------------------------- --- +
    | {“a”:{“x”:1,“y”:2}} |
    + ------------------------------------------------- --- +
    

    JSON_MERGE_PATCH() MySQL 8.0.3及更高版本支持。

    JSON_MERGE_PATCH()与JSON_MERGE_PRESERVE()进行比较。  的行为 JSON_MERGE_PATCH() 是一样的是 JSON_MERGE_PRESERVE() ,有以下两种情况例外:

    • JSON_MERGE_PATCH() 使用第二个对象中的匹配键删除第一个对象中的任何成员,前提是与第二个对象中的键关联的值不是JSON null

    • 如果第二个对象的成员具有与第一个对象中的成员匹配的键,则使用第二个对象中 的值 JSON_MERGE_PATCH() 替换 第一个对象中的值,而 JSON_MERGE_PRESERVE() 第二个值 附加 到第一个值。

    此示例将相同的3个JSON对象(每个对象具有匹配的键 "a" )与这两个函数中的 每一个进行比较的结果进行比较

    MySQL的> SET @x = '{ "a": 1, "b": 2 }',
         >      @y = '{ "a": 3, "c": 4 }',
         >     @z = '{ "a": 5, "d": 6 }';
    
    mysql> SELECT  JSON_MERGE_PATCH(@x, @y, @z)    AS Patch,
        - >         JSON_MERGE_PRESERVE(@x, @y, @z) AS Preserve\G
    *************************** 1。排******************** *******
       补丁:{“a”:5,“b”:2,“c”:4,“d”:6}
    保留:{“a”:[1,3,5],“b”:2,“c”:4,“d”:6}
    
  • JSON_MERGE_PRESERVE(json_doc, json_doc[, json_doc] ...)

    合并两个或多个JSON文档并返回合并的结果。 NULL 如果有任何参数,则 返回 NULL 如果任何参数不是有效的JSON文档,则会发生错误。

    合并根据以下规则进行。 有关其他信息,请参阅 JSON值的规范化,合并和自动包装

    • 相邻阵列合并为单个阵列。

    • 相邻对象合并为单个对象。

    • 标量值作为数组自动包装并合并为数组。

    • 通过将对象自动包装为数组并合并两个数组来合并相邻的数组和对象。

    MySQL的> SELECT JSON_MERGE_PRESERVE('[1, 2]', '[true, false]');
    + ------------------------------------------------ +
    | JSON_MERGE_PRESERVE('[1,2]','[true,false]')|
    + ------------------------------------------------ +
    | [1,2,true,false] |
    + ------------------------------------------------ +
    
    MySQL的> SELECT JSON_MERGE_PRESERVE('{"name": "x"}', '{"id": 47}');
    + ------------------------------------------------- --- +
    | JSON_MERGE_PRESERVE('{“name”:“x”}','{“id”:47}')|
    + ------------------------------------------------- --- +
    | {“id”:47,“name”:“x”} |
    + ------------------------------------------------- --- +
    
    MySQL的> SELECT JSON_MERGE_PRESERVE('1', 'true');
    + ---------------------------------- +
    | JSON_MERGE_PRESERVE('1','true')|
    + ---------------------------------- +
    | [1,true] |
    + ---------------------------------- +
    
    MySQL的> SELECT JSON_MERGE_PRESERVE('[1, 2]', '{"id": 47}');
    + --------------------------------------------- +
    | JSON_MERGE_PRESERVE('[1,2]','{“id”:47}')|
    + --------------------------------------------- +
    | [1,2,{“id”:47}] |
    + --------------------------------------------- +
    
    mysql SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }',
         >>    '{ "a": 3, "c": 4 }');
    + ------------------------------------------------- ------------- +
    | JSON_MERGE_PRESERVE('{“a”:1,“b”:2}','{“a”:3,“c”:4}')|
    + ------------------------------------------------- ------------- +
    | {“a”:[1,3],“b”:2,“c”:4} |
    + ------------------------------------------------- ------------- +
    
    mysql SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }','{ "a": 3, "c": 4 }',
         >>    '{ "a": 5, "d": 6 }');
    + ------------------------------------------------- --------------------------------- +
    | JSON_MERGE_PRESERVE('{“a”:1,“b”:2}','{“a”:3,“c”:4}','{“a”:5,“d”:6}') |
    + ------------------------------------------------- --------------------------------- +
    | {“a”:[1,3,5],“b”:2,“c”:4,“d”:6} |
    + ------------------------------------------------- --------------------------------- +
    

    此功能在MySQL 8.0.3中添加为同义词 JSON_MERGE() JSON_MERGE() 函数现已弃用,并且将在MySQL的未来版本中删除。

    该功能与 JSON_MERGE_PATCH() 重要方面 相似但不同 ; 有关详细信息, 请参阅 JSON_MERGE_PATCH()与JSON_MERGE_PRESERVE() 进行比较。

  • JSON_REMOVE(json_doc, path[, path] ...)

    从JSON文档中删除数据并返回结果。 NULL 如果有任何参数,则 返回 NULL 如果 json_doc 参数不是有效的JSON文档或任何 path 参数不是有效的路径表达式或者是 $ 或包含 * ** 通配符, 则会发生错误

    path 参数进行评估从左到右。 通过评估一条路径生成的文档将成为评估下一条路径的新值。

    如果文档中不存在要删除的元素,则不是错误; 在这种情况下,路径不会影响文档。

    mysql> SET @j = '["a", ["b", "c"], "d"]';
    mysql>SELECT JSON_REMOVE(@j, '$[1]');
    + ------------------------- +
    | JSON_REMOVE(@ j,'$ [1]')|
    + ------------------------- +
    | [“a”,“d”] |
    + ------------------------- +
    
  • JSON_REPLACE(json_doc, path, val[, path, val] ...)

    替换JSON文档中的现有值并返回结果。 NULL 如果有任何参数,则 返回 NULL 如果发生错误 json_doc 的参数是不是一个有效的JSON文档或任何 path 参数是不是有效的路径表达式或包含一个 * ** 通配符。

    路径值对从左到右进行评估。 通过评估一对产生的文档成为评估下一对的新值。

    文档中现有路径的路径值对使用新值覆盖现有文档值。 文档中不存在路径的路径 - 值对将被忽略,并且不起作用。

    在MySQL 8.0.4中,优化器可以执行列的部分就地更新, JSON 而不是删除旧文档并将新文档完整地写入列。 可以对使用该 JSON_REPLACE() 函数 的更新语句执行此优化, 并满足 JSON值的部分更新中 概述的条件

    为了进行比较 JSON_INSERT() JSON_REPLACE() 以及 JSON_SET() ,看到的讨论 JSON_SET()

    mysql> SET @j = '{ "a": 1, "b": [2, 3]}';
    mysql>SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]');
    + ------------------------------------------------- ---- +
    | JSON_REPLACE(@j,'$ .a',10,'$ .c','[true,false]')|
    + ------------------------------------------------- ---- +
    | {“a”:10,“b”:[2,3]} |
    + ------------------------------------------------- ---- +
    
  • JSON_SET(json_doc, path, val[, path, val] ...)

    在JSON文档中插入或更新数据并返回结果。 返回 NULL 如果任何参数是 NULL path ,如果给,不定位的对象。 如果发生错误 json_doc 的参数是不是一个有效的JSON文档或任何 path 参数是不是有效的路径表达式或包含一个 * ** 通配符。

    路径值对从左到右进行评估。 通过评估一对产生的文档成为评估下一对的新值。

    文档中现有路径的路径值对使用新值覆盖现有文档值。 如果路径标识了以下类型的值之一,则文档中不存在路径的路径值对会将值添加到文档中:

    • 不存在于现有对象中的成员。 该成员将添加到对象并与新值关联。

    • 位于现有数组末尾的位置。 使用新值扩展数组。 如果现有值不是数组,则将其作为数组自动包装,然后使用新值进行扩展。

    否则,将忽略文档中不存在路径的路径 - 值对,但不起作用。

    在MySQL 8.0.4中,优化器可以执行列的部分就地更新, JSON 而不是删除旧文档并将新文档完整地写入列。 可以对使用该 JSON_SET() 函数 的更新语句执行此优化, 并满足 JSON值的部分更新中 概述的条件

    JSON_SET() JSON_INSERT() JSON_REPLACE() 功能的关系:

    以下示例说明了这些差异,使用了document( $.a 中存在的一个路径 和另一个 不存在的路径 $.c ):

    mysql> SET @j = '{ "a": 1, "b": [2, 3]}';
    mysql>SELECT JSON_SET(@j, '$.a', 10, '$.c', '[true, false]');
    + ------------------------------------------------- +
    | JSON_SET(@ j,'$ .a',10,'$ .c','[true,false]')|
    + ------------------------------------------------- +
    | {“a”:10,“b”:[2,3],“c”:“[true,false]”} |
    + ------------------------------------------------- +
    MySQL的> SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]');
    + ------------------------------------------------- --- +
    | JSON_INSERT(@ j,'$ .a',10,'$ .c','[true,false]')|
    + ------------------------------------------------- --- +
    | {“a”:1,“b”:[2,3],“c”:“[true,false]”} |
    + ------------------------------------------------- --- +
    MySQL的> SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]');
    + ------------------------------------------------- ---- +
    | JSON_REPLACE(@j,'$ .a',10,'$ .c','[true,false]')|
    + ------------------------------------------------- ---- +
    | {“a”:10,“b”:[2,3]} |
    + ------------------------------------------------- ---- +
    
  • JSON_UNQUOTE(json_val)

    取消引用JSON值并将结果作为 utf8mb4 字符串 返回 NULL 如果参数是,则 返回 NULL 如果值以双引号开头和结尾但不是有效的JSON字符串文字,则会发生错误。

    在字符串中,除非 NO_BACKSLASH_ESCAPES 启用S​​QL模式, 否则某些序列具有特殊含义 这些序列中的每一个都以反斜杠( \ 开头 ,称为 转义字符 MySQL识别 表12.22“JSON_UNQUOTE()特殊字符转义序列”中显示的转义序列 对于所有其他转义序列,将忽略反斜杠。 也就是说,转义字符被解释为好像它没有被转义。 例如, \x 就是这样 x 这些序列区分大小写。 例如, \b 被解释为退格,但 \B 被解释为 B

    表12.22 JSON_UNQUOTE()特殊字符转义序列

    逃脱序列 由Sequence表示的字符
    \" 双引号( " )字符
    \b 退格字符
    \f 一个换文字符
    \n 换行符(换行符)
    \r 回车符
    \t 制表符
    \\ 反斜杠( \ )字符
    \uXXXX Unicode值的UTF-8字节 XXXX

    这里显示了使用此函数的两个简单示例:

    mysql> SET @j = '"abc"';
    mysql>SELECT @j, JSON_UNQUOTE(@j);
    + ------- + ------------------ +
    | @j | JSON_UNQUOTE(@j)|
    + ------- + ------------------ +
    | “abc”| abc |
    + ------- + ------------------ +
    mysql> SET @j = '[1, 2, 3]';
    mysql>SELECT @j, JSON_UNQUOTE(@j);
    + ----------- + ------------------ +
    | @j | JSON_UNQUOTE(@j)|
    + ----------- + ------------------ +
    | [1,2,3] | [1,2,3] |
    + ----------- + ------------------ +
    

    以下示例显示了如何 JSON_UNQUOTE NO_BACKSLASH_ESCAPES 禁用和启用时 转义句柄

    MySQL的> SELECT @@sql_mode;
    + ------------ +
    | @@ sql_mode |
    + ------------ +
    | |
    + ------------ +
    
    MySQL的> SELECT JSON_UNQUOTE('"\\t\\u0032"');
    + ------------------------------ +
    | JSON_UNQUOTE('“\\ t \\ u0032”')|
    + ------------------------------ +
    | 2 |
    + ------------------------------ +
    
    mysql> SET @@sql_mode = 'NO_BACKSLASH_ESCAPES';
    mysql>SELECT JSON_UNQUOTE('"\\t\\u0032"');
    + ------------------------------ +
    | JSON_UNQUOTE('“\\ t \\ u0032”')|
    + ------------------------------ +
    | \ t \ u0032 |
    + ------------------------------ +
    
    MySQL的> SELECT JSON_UNQUOTE('"\t\u0032"');
    + ---------------------------- +
    | JSON_UNQUOTE('“\ t \ u0032”')|
    + ---------------------------- +
    | 2 |
    + ---------------------------- +
    

12.17.5返回JSON值属性的函数

本节中的函数返回JSON值的属性。

  • JSON_DEPTH(json_doc)

    返回JSON文档的最大深度。 NULL 如果参数是,则 返回 NULL 如果参数不是有效的JSON文档,则会发生错误。

    空数组,空对象或标量值具有深度1.仅包含深度为1的元素的非空数组或仅包含深度为1的成员值的非空对象具有深度2.否则,JSON文档的深度大于2。

    MySQL的> SELECT JSON_DEPTH('{}'), JSON_DEPTH('[]'), JSON_DEPTH('true');
    + ------------------ + ------------------ + ----------- --------- +
    | JSON_DEPTH('{}')| JSON_DEPTH('[]')| JSON_DEPTH('true')|
    + ------------------ + ------------------ + ----------- --------- +
    | 1 | 1 | 1 |
    + ------------------ + ------------------ + ----------- --------- +
    MySQL的> SELECT JSON_DEPTH('[10, 20]'), JSON_DEPTH('[[], {}]');
    + ------------------------ + ------------------------ +
    | JSON_DEPTH('[10,20]')| JSON_DEPTH('[[],{}]')|
    + ------------------------ + ------------------------ +
    | 2 | 2 |
    + ------------------------ + ------------------------ +
    MySQL的> SELECT JSON_DEPTH('[10, {"a": 20}]');
    + ------------------------------- +
    | JSON_DEPTH('[10,{“a”:20}]')|
    + ------------------------------- +
    | 3 |
    + ------------------------------- +
    
  • JSON_LENGTH(json_doc[, path])

    返回JSON文档的长度,或者,如果 path 给出参数 ,则返回 由路径标识的文档中的值的长度。 返回 NULL 如果任何参数 NULL path 参数不文档中确定的值。 如果 json_doc 参数不是有效的JSON文档或 path 参数不是有效的路径表达式或包含 * ** 通配符, 则会发生错误

    文件的长度确定如下:

    • 标量的长度为1。

    • 数组的长度是数组元素的数量。

    • 对象的长度是对象成员的数量。

    • 长度不计算嵌套数组或对象的长度。

    MySQL的> SELECT JSON_LENGTH('[1, 2, {"a": 3}]');
    + --------------------------------- +
    | JSON_LENGTH('[1,2,{“a”:3}]')|
    + --------------------------------- +
    | 3 |
    + --------------------------------- +
    MySQL的> SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}');
    + ----------------------------------------- +
    | JSON_LENGTH('{“a”:1,“b”:{“c”:30}}')|
    + ----------------------------------------- +
    | 2 |
    + ----------------------------------------- +
    MySQL的> SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b');
    + ------------------------------------------------ +
    | JSON_LENGTH('{“a”:1,“b”:{“c”:30}}','$ .b')|
    + ------------------------------------------------ +
    | 1 |
    + ------------------------------------------------ +
    
  • JSON_TYPE(json_val)

    返回 utf8mb4 表示JSON值类型的字符串。 这可以是对象,数组或标量类型,如下所示:

    mysql> SET @j = '{"a": [10, true]}';
    mysql>SELECT JSON_TYPE(@j);
    + --------------- +
    | JSON_TYPE(@j)|
    + --------------- +
    | 对象|
    + --------------- +
    MySQL的> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a'));
    + ------------------------------------ +
    | JSON_TYPE(JSON_EXTRACT(@ j,'$ .a'))|
    + ------------------------------------ +
    | ARRAY |
    + ------------------------------------ +
    MySQL的> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]'));
    + --------------------------------------- +
    | JSON_TYPE(JSON_EXTRACT(@ j,'$ .a [0]'))|
    + --------------------------------------- +
    | INTEGER |
    + --------------------------------------- +
    MySQL的> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]'));
    + --------------------------------------- +
    | JSON_TYPE(JSON_EXTRACT(@ j,'$ .a [1]'))|
    + --------------------------------------- +
    | BOOLEAN |
    + --------------------------------------- +
    

    JSON_TYPE() 返回 NULL 如果参数为 NULL

    MySQL的> SELECT JSON_TYPE(NULL);
    + ----------------- +
    | JSON_TYPE(NULL)|
    + ----------------- +
    | NULL |
    + ----------------- +
    

    如果参数不是有效的JSON值,则会发生错误:

    MySQL的> SELECT JSON_TYPE(1);
    ERROR 3146(22032):参数1中JSON数据的数据类型无效
    使用json_type; 需要JSON字符串或JSON类型。
    

    对于 NULL 非错误结果,以下列表描述了可能的 JSON_TYPE() 返回值:

    • 纯JSON类型:

      • OBJECT :JSON对象

      • ARRAY :JSON数组

      • BOOLEAN :JSON真假文字

      • NULL :JSON null文字

    • 数字类型:

    • 时间类型:

    • 字符串类型:

    • 二进制类型:

    • 所有其他类型:

      • OPAQUE (原始位)

  • JSON_VALID(val)

    返回0或1以指示值是否为有效JSON。 NULL 如果参数是,则 返回 NULL

    MySQL的> SELECT JSON_VALID('{"a": 1}');
    + ------------------------ +
    | JSON_VALID('{“a”:1}')|
    + ------------------------ +
    | 1 |
    + ------------------------ +
    MySQL的> SELECT JSON_VALID('hello'), JSON_VALID('"hello"');
    + --------------------- + ----------------------- +
    | JSON_VALID('你好')| JSON_VALID('“hello”')|
    + --------------------- + ----------------------- +
    | 0 | 1 |
    + --------------------- + ----------------------- +
    

12.17.6 JSON表函数

本节包含有关将JSON数据转换为表格数据的JSON函数的信息。 在MySQL 8.0.4及更高版本中, JSON_TABLE() 支持 一个这样的功能

  • JSON_TABLE(expr, path COLUMNS (column_list) [AS] alias)

    从JSON文档中提取数据并将其作为具有指定列的关系表返回。 此函数的完整语法如下所示:

    JSON_TABLE(
         exprpathCOLUMNS(column_list
    )[AS] alias
    
    column_listcolumn[,column] [,...]
    
    columnname为了ORDINALITY
        |  路径[ ] [ ]name typestring pathon_erroron_empty
        |  EXISTS PATH 
        | NESTED [PATH] COLUMNS(name typestring pathpathcolumn_list
    
    on_error
        {NULL | 错误| json_string错误的默认值
    
    on_empty
        {NULL | 错误| 空缺的DEFAULT json_string}
    

    expr :这是一个返回JSON数据的表达式。 这可以是constant( '{"a":1}' ),列( 子句 之前指定的 t1.json_data 给定表 )或函数调用( )。 t1 JSON_TABLE() FROM JSON_EXTRACT(t1,jsn_data,'$.post.comments')

    path :JSON路径表达式,应用于数据源。 我们将匹配路径的JSON值称为 行源 ; 这用于生成一行关系数据。 COLUMNS 子句计算行源,在行源中查找特定的JSON值,并将这些JSON值作为SQL值返回到一行关系数据的各列中。

    alias 是必需的。 表别名的通常规则适用(请参见 第9.2节“模式对象名称” )。

    JSON_TABLE() 支持四种类型的列,如下面的列表所述:

    1. name FOR ORDINALITY :此类型枚举 COLUMNS 子句中的 ; 命名列 name 是一个类型为的计数器 UNSIGNED INT ,其初始值为1.这相当于 AUTO_INCREMENT CREATE TABLE 语句中 指定列 ,并且可用于区分 NESTED [PATH] 子句 生成的多行的父行

    2. name type PATH string_path [on_error] [on_empty] :此类型的列用于提取指定的值 string_path type 是一种MySQL数据类型。 JSON_TABLE() 使用应用于MySQL中的JSON数据的常规自动类型转换,将数据提取为JSON,然后将其强制转换为列类型。 确切的行为取决于列类型:如果列类型是SQL类型,则只能在列中保存标量值。 保存对象或数组会触发该 on error 子句; 在从保存为JSON的值到表列的强制执行期间发生错误时也会发生这种情况,例如尝试保存字符串 'asd' 到整数列。 缺失值会触发 on_empty 子句。

      optional on_error 子句确定 JSON_TABLE() 保存对象或数组时的作用:

      • NULL ON ERROR :列设置为 NULL ; 这是默认行为。 如果在类型强制期间发生错误,则会引发警告。

      • ERROR ON ERROR :抛出错误。

      • DEFAULT json string ON ERROR json_string 解析为JSON(假设它是有效的)并存储而不是对象或数组。 如果错误是由类型强制引起的,则抛出警告。 列类型规则也适用于默认值。

      当截断保存到列的值(例如在 DECIMAL(10,1) 列中 保存3.14159)时 ,将独立于任何 ON ERROR 选项 发出警告 在单个语句中截断多个值时,警告仅发出一次。

      optional on empty 子句确定 JSON_TABLE() 在数据丢失的情况下(取决于类型)。 当子句中的列 NESTED PATH 没有匹配且 NULL 为其生成补充行时,也会 子句中 的列上触发此子句 on empty 采用以下值之一:

      • NULL ON EMPTY :列设置为 NULL ; 这是默认行为。

      • ERROR ON EMPTY :抛出错误。

      • DEFAULT json_string ON EMPTY :提供 json_string 的解析为JSON,只要它有效,并存储而不是缺少值。 列类型规则也适用于默认值。

      此查询演示了使用 ON ERROR ON EMPTY 选项。 对应的行 {"b":1} 对于路径是空的 "$.a" ,并且尝试保存 [1,2] 为标量会产生错误; 这些行在显示的输出中突出显示。

      mysql> SELECT *
          - > FROM
          - >    JSON_TABLE(
          - >      '[{"a":"3"},{"a":2},{"b":1},{"a":0},{"a":[1,2]}]',
          - >      "$[*]"
          - >      COLUMNS(
          - >        rowid FOR ORDINALITY,
          - >        ac VARCHAR(100) PATH "$.a" DEFAULT '999' ON ERROR DEFAULT '111' ON EMPTY,
          - >        aj JSON PATH "$.a" DEFAULT '{"x": 333}' ON EMPTY,
          - >        bx INT EXISTS PATH "$.b"
          - >      )
          - >   ) AS tt;
      
      + ------- + ------ + ------------ + ------ +
      | rowid | ac | aj | bx |
      + ------- + ------ + ------------ + ------ +
      | 1 | 3 | “3”| 0 |
      | 2 | 2 | 2 | 0 |
      | 3 | 111 | {“x”:333} | 1 |
      | 4 | 0 | 0 | 0 |
      | 5 | 999 | [1,2] | 0 |
      + ------- + ------ + ------------ + ------ +
      5行(0.00秒)
      
    3. name type EXISTS PATH path :如果在指定的位置存在任何数据,则此列返回1,否则返回 path 0。 type 可以是任何有效的MySQL数据类型,但通常应指定为多种类型 INT

    4. NESTED [PATH] path COLUMNS (column_list) :这将JSON数据中的嵌套对象或数组与父对象或数组中的JSON值一起展平为单行。 使用多个 PATH 选项可以将JSON值从多个嵌套级别投影到单个行中。

      path 是相对于父路径行路径 JSON_TABLE() ,或者 NESTED [PATH] 是嵌套路径中 父子 句的路径。

    列名遵循管理表列名称的通常规则和限制。 请参见 第9.2节“架构对象名称”

    检查所有JSON和JSON路径表达式的有效性; 任何一种类型的无效表达式都会导致错误。

    path 前面 COLUMNS 关键字的 每个匹配都 映射到结果表中的单个行。 例如,以下查询给出了此处显示的结果:

    mysql> SELECT *
        - > FROM
        - >    JSON_TABLE(
        - >      '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',
        - >      "$[*]" COLUMNS(
        - >        xval VARCHAR(100) PATH "$.x",
        - >        yval VARCHAR(100) PATH "$.y"
        - >      )
        - >   ) AS  jt1;
    
    + ------ + ------ +
    | xval | yval |
    + ------ + ------ +
    | 2 | 8 |
    | 3 | 7 |
    | 4 | 6 |
    + ------ + ------ +
    

    表达式 "$[*]" 匹配数组的每个元素。 您可以通过修改路径来过滤结果中的行。 例如,使用 "$[1]" 限制提取到用作源的JSON数组的第二个元素,如下所示:

    mysql> SELECT *
        - > FROM
        - >    JSON_TABLE(
        - >      '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',
        - >      "$[1]" COLUMNS(
        - >        xval VARCHAR(100) PATH "$.x",
        - >        yval VARCHAR(100) PATH "$.y"
        - >      )
        - >   ) AS  jt1;
    
    + ------ + ------ +
    | xval | yval |
    + ------ + ------ +
    | 3 | 7 |
    + ------ + ------ +
    

    在列定义中, "$" 将整个匹配传递给列; "$.x" 并且 "$.y" 仅传递与该键 匹配 的值 x y 该匹配内 的值 有关更多信息,请参阅 JSON路径语法

    NESTED PATH (或简单地 NESTED ; PATH 是可选的)为 COLUMNS 它所属 子句中的 每个匹配生成一组记录 如果没有匹配项,则嵌套路径的所有列都将设置为 NULL 这实现了最顶层子句和 NESTED [PATH] 之间的外连接 可以通过在 WHERE 子句中 应用合适的条件来模拟内部联接 ,如下所示:

    mysql> SELECT *
        - > FROM
        - >    JSON_TABLE(
        - >      '[ {"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]',
        - >      '$[*]' COLUMNS(
        - >              a INT PATH '$.a',
        - >              NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$')
        - >             )
        - >     ) AS jt
        - >WHERE b IS NOT NULL;
    
    + ------ + ------ +
    | a | b |
    + ------ + ------ +
    | 1 | 11 |
    | 1 | 111 |
    | 2 | 22 |
    | 2 | 222 |
    + ------ + ------ +
    

    兄弟姐妹嵌套路径 - 即 NESTED [PATH] 同一 COLUMNS 子句 中的 两个或多个实例 - 一个接一个地处理,一次一个。 当一个嵌套路径生成记录时,任何兄弟嵌套路径表达式的列都将设置为 NULL 这意味着单个包含 COLUMNS 子句中 单个匹配的记录总数 是总和,而不是 NESTED [PATH] 修饰符 生成的所有记录的乘积 ,如下所示:

    mysql> SELECT *
        - > FROM
        - >    JSON_TABLE(
        - >      '[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]',
        - >      '$[*]' COLUMNS(
        - >          a INT PATH '$.a',
        - >          NESTED PATH '$.b[*]' COLUMNS (b1 INT PATH '$'),
        - >          NESTED PATH '$.b[*]' COLUMNS (b2 INT PATH '$')
        - >      )
        - >) AS jt;
    
    + ------ + ------ + ------ +
    | a | b1 | b2 |
    + ------ + ------ + ------ +
    | 1 | 11 | NULL |
    | 1 | 111 | NULL |
    | 1 | NULL | 11 |
    | 1 | NULL | 111 |
    | 2 | 22 | NULL |
    | 2 | 222 | NULL |
    | 2 | NULL | 22 |
    | 2 | NULL | 222 |
    + ------ + ------ + ------ +
    

    FOR ORDINALITY 列列举由所产生的记录 COLUMNS 条款,并且可以用来区分一个嵌套路径的父记录,特别是如果在父记录值是相同的,因为在这里可以看到:

    mysql> SELECT *
        - > FROM
        - >    JSON_TABLE(
        - >      '[{"a": "a_val",
        '>        "b": [{"c": "c_val", "l": [1,2]}]},
        '>      {"a": "a_val",
        '>        "b": [{"c": "c_val","l": [11]}, {"c": "c_val", "l": [22]}]}]',
        - >      '$[*]' COLUMNS(
        - >        top_ord FOR ORDINALITY,
        - >        apath VARCHAR(10) PATH '$.a',
        - >        NESTED PATH '$.b[*]' COLUMNS (
        - >          bpath VARCHAR(10) PATH '$.c',
        - >          ord FOR ORDINALITY,
        - >          NESTED PATH '$.l[*]' COLUMNS (lpath varchar(10) PATH '$')
        - >          )
        - >      )
        - >) as jt;
    
    + --------- + --------- + --------- + ------ + ------- +
    | top_ord | apath | bpath | ord | lpath |
    + --------- + --------- + --------- + ------ + ------- +
    | 1 | a_val | c_val | 1 | 1 |
    | 1 | a_val | c_val | 1 | 2 |
    | 2 | a_val | c_val | 1 | 11 |
    | 2 | a_val | c_val | 2 | 22 |
    + --------- + --------- + --------- + ------ + ------- +
    

    源文档包含两个元素的数组; 这些元素中的每一个都产生两行。 整个结果集 的值 apath bpath 相同; 这意味着它们不能用于确定 lpath 值是来自相同或不同的父母。 ord 的值 保持与 top_ord 等于1 的记录集 相同,因此这两个值来自单个对象。 其余两个值来自不同的对象,因为它们在 ord 列中 具有不同的值

12.17.7 JSON模式验证函数

从MySQL 8.0.17开始,MySQL支持针对符合 JSON Schema规范草案4的 JSON模式验证JSON文档 这可以使用本节中详述的任一函数来完成,这两个函数都包含两个参数,一个JSON模式和一个根据模式验证的JSON文档。 JSON_SCHEMA_VALID() 如果文档对模式进行验证,则返回true;如果不是,则返回false;否则返回false。 JSON_SCHEMA_VALIDATION_REPORT() 提供有关验证的JSON格式的报告。

两个函数都处理null或无效输入,如下所示:

  • 如果至少有一个参数是 NULL ,则函数返回 NULL

  • 如果至少有一个参数不是有效的JSON,则该函数会引发错误( ER_INVALID_TYPE_FOR_JSON

  • 此外,如果架构不是有效的JSON对象,则函数返回 ER_INVALID_JSON_TYPE

MySQL支持 required JSON模式中 属性以强制包含必需的属性(请参阅函数说明中的示例)。

MySQL不支持JSON模式中的外部资源; 使用 $ref 关键字导致 JSON_SCHEMA_VALID() 失败 ER_NOT_SUPPORTED_YET

注意

MySQL支持JSON模式中的正则表达式模式,它支持但默默地忽略无效模式(请参阅 JSON_SCHEMA_VALID() 示例 的说明 )。

以下列表详细介绍了这些功能:

  • JSON_SCHEMA_VALID(schema,document)

    根据JSON验证 document JSON schema 两者 schema document 是必需的。 架构必须是有效的JSON对象; 该文档必须是有效的JSON文档。 只要满足这些条件:如果文档针对模式进行验证,则函数返回true(1); 否则,返回false(0)。

    在此示例中,我们将用户变量设置 @schema 为地理坐标的aa JSON模式 @document 的值,将 另一个 变量设置为 包含一个此类坐标的JSON文档的值。 然后,我们 通过使用它们作为参数来 @document 验证验证 @schema JSON_SCHEMA_VALID()

     
    mysql> SET @schema = '{
        '>   "id": "http://json-schema.org/geo",
        '> "$schema": "http://json-schema.org/draft-04/schema#",
        '> "description": "A geographical coordinate",
        '> "type": "object",
        '> "properties": {
        '>    "latitude": {
        '>      "type": "number",
        '>      "minimum": -90,
        '>      "maximum": 90
        '>    },
        '>    "longitude": {
        '>      "type": "number",
        '>      "minimum": -180,
        '>      "maximum": 180
        '>    }
        '> },
        '> "required": ["latitude", "longitude"]
        '>}';
    查询OK,0行受影响(0.01秒)
    
    
    mysql> SET @document = '{
        '> "latitude": 63.444697,
        '> "longitude": 10.445118
        '>}';
    查询正常,0行受影响(0.00秒)
    
    
    MySQL的> SELECT JSON_SCHEMA_VALID(@schema, @document);
    + --------------------------------------- +
    | JSON_SCHEMA_VALID(@schema,@ document)|
    + --------------------------------------- +
    | 1 |
    + --------------------------------------- +
    1排(0.00秒)
    

    由于 @schema 包含 required 属性,我们可以将其设置 @document 为有效但不包含必需属性的值,然后对其进行测试 @schema ,如下所示:

    MySQL的> SET @document = '{}';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT JSON_SCHEMA_VALID(@schema, @document);
    + --------------------------------------- +
    | JSON_SCHEMA_VALID(@schema,@ document)|
    + --------------------------------------- +
    | 0 |
    + --------------------------------------- +
    1排(0.00秒)
    

    如果我们现在将值设置为 @schema 相同的JSON模式但没有该 required 属性,则 @document 验证因为它是有效的JSON对象,即使它不包含任何属性,如下所示:

    mysql> SET @schema = '{
        '> "id": "http://json-schema.org/geo",
        '> "$schema": "http://json-schema.org/draft-04/schema#",
        '> "description": "A geographical coordinate",
        '> "type": "object",
        '> "properties": {
        '>    "latitude": {
        '>      "type": "number",
        '>      "minimum": -90,
        '>      "maximum": 90
        '>    },
        '>    "longitude": {
        '>      "type": "number",
        '>      "minimum": -180,
        '>      "maximum": 180
        '>    }
        '> }
        '>}';
    查询正常,0行受影响(0.00秒)
    
    
    MySQL的> SELECT JSON_SCHEMA_VALID(@schema, @document);
    + --------------------------------------- +
    | JSON_SCHEMA_VALID(@schema,@ document)|
    + --------------------------------------- +
    | 1 |
    + --------------------------------------- +
    1排(0.00秒)
    

    JSON Schema支持为字符串指定正则表达式模式,但MySQL使用的实现默默地忽略了无效模式。 这意味着 JSON_SCHEMA_VALID() 即使正则表达式模式无效, 可以返回true,如下所示:

    MySQL的> SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"');
    + ------------------------------------------------- -------------- +
    | JSON_SCHEMA_VALID('{“type”:“string”,“pattern”:“(”}','“abc”')|
    + ------------------------------------------------- -------------- +
    | 1 |
    + ------------------------------------------------- -------------- +
    1排(0.04秒)
    
  • JSON_SCHEMA_VALIDATION_REPORT(schema,document)

    根据JSON验证 document JSON schema 这两个 schema document 是必需的。 与JSON_VALID_SCHEMA()一样,模式必须是有效的JSON对象,并且文档必须是有效的JSON文档。 如果满足这些条件,则该函数将返回关于验证结果的报告(作为JSON文档)。 如果根据JSON模式认为JSON文档有效,则该函数返回一个JSON对象,其中一个属性 valid 的值为“true”。 如果JSON文档未通过验证,则该函数返回一个JSON对象,其中包含此处列出的属性:

    • valid :对于失败的模式验证,始终为“false”

    • reason :包含失败原因的人类可读字符串

    • schema-location :JSON指针URI片段标识符,指示验证失败的JSON模式中的位置(请参阅此列表后面的注释)

    • document-location :JSON指针URI片段标识符,指示验证失败的JSON文档中的位置(请参阅此列表后面的注释)

    • schema-failed-keyword :一个字符串,其中包含违反JSON模式中的关键字或属性的名称

    注意

    JSON指针URI片段标识符在 RFC 6901 - JavaScript Object Notation(JSON)指针中定义 (这些是 一样由所使用的JSON路径表示法 JSON_EXTRACT() 和其他MySQL JSON功能)。在这种表示法中, # 表示整个文档,和 #/myprop 表示包括在命名顶层属性的文档的所述部分 myprop 有关详细信息,请参阅刚才引用的规范和本节后面的示例。

    在此示例中,我们将用户变量设置 @schema 为地理坐标的aa JSON模式 @document 的值,将 另一个 变量设置为 包含一个此类坐标的JSON文档的值。 然后,我们 通过使用它们作为参数来 @document 验证验证 @schema JSON_SCHEMA_VALIDATION_REORT()

     
    mysql> SET @schema = '{
        '>   "id": "http://json-schema.org/geo",
        '> "$schema": "http://json-schema.org/draft-04/schema#",
        '> "description": "A geographical coordinate",
        '> "type": "object",
        '> "properties": {
        '>    "latitude": {
        '>      "type": "number",
        '>      "minimum": -90,
        '>      "maximum": 90
        '>    },
        '>    "longitude": {
        '>      "type": "number",
        '>      "minimum": -180,
        '>      "maximum": 180
        '>    }
        '> },
        '> "required": ["latitude", "longitude"]
        '>}';
    查询OK,0行受影响(0.01秒)
    
    mysql> SET @document = '{
        '> "latitude": 63.444697,
        '> "longitude": 10.445118
        '>}';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document);
    + ------------------------------------------------- -  +
    | JSON_SCHEMA_VALIDATION_REPORT(@schema,@ document)|
    + ------------------------------------------------- -  +
    | {“valid”:true} |
    + ------------------------------------------------- -  +
    1排(0.00秒)
    

    现在我们设置 @document 它为它的一个属性指定一个非法值,如下所示:

    mysql> SET @document = '{
        '> "latitude": 63.444697,
        '> "longitude": 310.445118
        '>}';
    

    @document 在测试时, 验证 现在失败 JSON_SCHEMA_VALIDATION_REPORT() 函数调用的输出包含有关失败的详细信息(函数包含 JSON_PRETTY() 以提供更好的格式化),如下所示:

    MySQL的> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G
    *************************** 1。排******************** *******
    JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema,@ document)):{
      “有效”:错误,
      “原因”:“JSON文档位置'#/经度'在JSON架构位置'#/ properties / longitude''的要求'最大'失败”,
      “schema-location”:“#/ properties / longitude”,
      “文件位置”:“#/经度”,
      “schema-failed-keyword”:“maximum”
    }
    1排(0.00秒)
    

    由于 @schema 包含 required 属性,我们可以设置 @document 为有效但不包含所需属性的值,然后对其进行测试 @schema 输出 JSON_SCHEMA_VALIDATION_REPORT() 显示验证因缺少必需元素而失败,如下所示:

    MySQL的> SET @document = '{}';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G
    *************************** 1。排******************** *******
    JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema,@ document)):{
      “有效”:错误,
      “reason”:“JSON Schema位置'#'”中的JSON文档位置'#'需要'''',
      “schema-location”:“#”,
      “文档位置”:“#”,
      “schema-failed-keyword”:“required”
    }
    1排(0.00秒)
    

    如果我们现在将值设置为 @schema 相同的JSON模式但没有该 required 属性,则 @document 验证因为它是有效的JSON对象,即使它不包含任何属性,如下所示:

    mysql> SET @schema = '{
        '> "id": "http://json-schema.org/geo",
        '> "$schema": "http://json-schema.org/draft-04/schema#",
        '> "description": "A geographical coordinate",
        '> "type": "object",
        '> "properties": {
        '>    "latitude": {
        '>      "type": "number",
        '>      "minimum": -90,
        '>      "maximum": 90
        '>    },
        '>    "longitude": {
        '>      "type": "number",
        '>      "minimum": -180,
        '>      "maximum": 180
        '>    }
        '> }
        '>}';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document);
    + ------------------------------------------------- -  +
    | JSON_SCHEMA_VALIDATION_REPORT(@schema,@ document)|
    + ------------------------------------------------- -  +
    | {“valid”:true} |
    + ------------------------------------------------- -  +
    1排(0.00秒)
    

12.17.8 JSON实用程序函数

本节介绍了作用于JSON值的实用程序函数,或者可以解析为JSON值的字符串。 JSON_PRETTY() 以易于阅读的格式打印出JSON值。 JSON_STORAGE_SIZE() JSON_STORAGE_FREE() 分别显示给定JSON值使用的存储空间量以及 JSON 部分更新后列中 剩余的空间量

  • JSON_PRETTY(json_val)

    提供类似于PHP和其他语言和数据库系统中实现的JSON值的漂亮打印。 提供的值必须是JSON值或JSON值的有效字符串表示形式。 此值中存在的外部空格和换行符对输出没有影响。 对于 NULL 值,函数返回 NULL 如果该值不是JSON文档,或者无法将其解析为一个,则该函数将失败并显示错误。

    此函数的输出格式符合以下规则:

    • 每个数组元素或对象成员显示在单独的行上,与其父级相比,缩进一个额外的级别。

    • 每个级别的缩进都添加了两个前导空格。

    • 在分隔两个元素或成员的换行符之前打印分隔各个数组元素或对象成员的逗号。

    • 对象成员的键和值由冒号后跟空格(' : ') 分隔

    • 空行或数组打印在一行上。 打开和关闭支架之间没有打印空间。

    • 字符串标量和键名中的特殊字符使用 JSON_QUOTE() 函数 使用的相同规则进行转义

    MySQL的> SELECT JSON_PRETTY('123'); # scalar
    + -------------------- +
    | JSON_PRETTY('123')|
    + -------------------- +
    | 123 |
    + -------------------- +
    
    MySQL的> SELECT JSON_PRETTY("[1,3,5]"); # array
    + ------------------------ +
    | JSON_PRETTY(“[1,3,5]”)|
    + ------------------------ +
    | [
      1,
      3,
    ] |
    + ------------------------ +
    
    MySQL的> SELECT JSON_PRETTY('{"a":"10","b":"15","x":"25"}'); # object
    + --------------------------------------------- +
    | JSON_PRETTY('{“a”:“10”,“b”:“15”,“x”:“25”}')|
    + --------------------------------------------- +
    | {
      “a”:“10”,
      “b”:“15”,
      “x”:“25”
    } |
    + --------------------------------------------- +
    
    mysql> SELECT JSON_PRETTY('["a",1,{"key1":
        '>     "value1"},"5",     "77" ,
        '>        {"key2":["value3","valueX",
        '>"valueY"]},"j", "2"   ]')\G  # nested arrays and objects
    *************************** 1。排******************** *******
    JSON_PRETTY('[ “一”,1,{ “KEY1”:
                 “value1”},“5”,“77”,
                    { “KEY2”:[ “值3”, “valuex”,
              “valuey”]},“j”,“2”]'):[
      “一个”,
      1,
      {
        “key1”:“value1”
      },
      “5”,
      “77”,
      {
        “key2”:[
          “值3”
          “valuex”
          “VALUE年”
        ]
      },
      “J”,
      “2”
    ]
    
  • JSON_STORAGE_FREE(json_val)

    对于 JSON 列值,该功能显示多少存储空间,在其二进制表示被释放它是使用到位更新后 JSON_SET() JSON_REPLACE() JSON_REMOVE() 参数也可以是一个有效的JSON文档或一个字符串,可以将其解析为一个文字值或用户变量的值 - 在这种情况下函数返回0.如果是,则返回正的非零值argument是一个 JSON 已经如前所述更新 列值,因此它的二进制表示占用的空间比更新之前的空间少。 为一个 JSON 已更新的列,使其二进制表示与之前相同或更大,或者如果更新无法利用部分更新,则返回0; NULL 如果参数是, 则返回 NULL

    如果 json_val 不是 NULL ,既不是有效的JSON文档也不能成功解析为一个,则会产生错误。

    在此示例中,我们创建一个包含 JSON 的表 ,然后插入包含JSON对象的行:

    MySQL的> CREATE TABLE jtable (jcol JSON);
    查询OK,0行受影响(0.38秒)
    
    mysql> INSERT INTO jtable VALUES
        - >     ('{"a": 10, "b": "wxyz", "c": "[true, false]"}');
    查询正常,1行受影响(0.04秒)
    
    MySQL的> SELECT * FROM jtable;
    + ---------------------------------------------- +
    | jcol |
    + ---------------------------------------------- +
    | {“a”:10,“b”:“wxyz”,“c”:“[true,false]”} |
    + ---------------------------------------------- +
    1排(0.00秒)
    

    现在我们使用更新列值 JSON_SET() 来执行部分更新; 在这种情况下,我们将 c 键(数组 [true, false] 指向的值替换为 占用较少空间(整数 1 )的值:

    mysql> UPDATE jtable
        - >     SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wxyz", "$.c", 1);
    查询正常,1行受影响(0.03秒)
    匹配的行数:1已更改:1警告:0
    
    MySQL的> SELECT * FROM jtable;
    + -------------------------------- +
    | jcol |
    + -------------------------------- +
    | {“a”:10,“b”:“wxyz”,“c”:1} |
    + -------------------------------- +
    1排(0.00秒)
    
    MySQL的> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    + ------------------------- +
    | JSON_STORAGE_FREE(jcol)|
    + ------------------------- +
    | 14 |
    + ------------------------- +
    1排(0.00秒)
    

    连续部分更新对此可用空间的影响是累积的,如此示例所示, JSON_SET() 用于减少具有键的值占用的空间 b (并且不进行其他更改):

    mysql> UPDATE jtable
        - >     SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wx", "$.c", 1);
    查询正常,1行受影响(0.03秒)
    匹配的行数:1已更改:1警告:0
    
    MySQL的> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    + ------------------------- +
    | JSON_STORAGE_FREE(jcol)|
    + ------------------------- +
    | 16 |
    + ------------------------- +
    1排(0.00秒)
    

    不使用 JSON_SET() 更新列 JSON_REPLACE() ,或 JSON_REMOVE() 意味着优化器无法就地执行更新; 在这种情况下, JSON_STORAGE_FREE() 返回0,如下所示:

    MySQL的> UPDATE jtable SET jcol = '{"a": 10, "b": 1}';
    查询OK,1行受影响(0.05秒)
    匹配的行数:1已更改:1警告:0
    
    MySQL的> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    + ------------------------- +
    | JSON_STORAGE_FREE(jcol)|
    + ------------------------- +
    | 0 |
    + ------------------------- +
    1排(0.00秒)
    

    只能对列值执行JSON文档的部分更新。 对于存储JSON值的用户变量,即使使用 JSON_SET() 以下命令 执行更新,也始终完全替换该值

    MySQL的> SET @j = '{"a": 10, "b": "wxyz", "c": "[true, false]"}';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SET @j = JSON_SET(@j, '$.a', 10, '$.b', 'wxyz', '$.c', '1');
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @j, JSON_STORAGE_FREE(@j) AS Free;
    + ---------------------------------- + ------ +
    | @j | 免费|
    + ---------------------------------- + ------ +
    | {“a”:10,“b”:“wxyz”,“c”:“1”} | 0 |
    + ---------------------------------- + ------ +
    1排(0.00秒)
    

    对于JSON文字,此函数始终返回0:

    MySQL的> SELECT JSON_STORAGE_FREE('{"a": 10, "b": "wxyz", "c": "1"}') AS Free;
    + ------ +
    | 免费|
    + ------ +
    | 0 |
    + ------ +
    1排(0.00秒)
    
  • JSON_STORAGE_SIZE(json_val)

    此函数返回用于存储JSON文档的二进制表示的字节数。 当参数是一 JSON 列时,这是用于存储JSON文档的空间,因为它插入到列中,之后可能已对其执行任何部分更新。 json_val 必须是有效的JSON文档或可以解析为一个的字符串。 在它是字符串的情况下,该函数返回JSON二进制表示形式中的存储空间量,该表示形式是通过将字符串解析为JSON并将其转换为二进制而创建的。 NULL 如果参数是 ,则返回 NULL

    如果 json_val 不是 NULL ,或者不能 - 或者不能成功解析为JSON文档,则会 导致错误

    为了说明此函数在与 JSON 列作为参数 一起使用时的行为 ,我们创建一个名为 jtable 包含 JSON 的表 jcol ,将JSON值插入表中,然后获取此列使用的存储空间 JSON_STORAGE_SIZE() ,如下所示:

    MySQL的> CREATE TABLE jtable (jcol JSON);
    查询OK,0行受影响(0.42秒)
    
    mysql> INSERT INTO jtable VALUES
        - >     ('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}');
    查询正常,1行受影响(0.04秒)
    
    mysql> SELECT
        - >      jcol,
        - >      JSON_STORAGE_SIZE(jcol) AS Size,
        - >      JSON_STORAGE_FREE(jcol) AS Free
        - >FROM jtable;
    + ----------------------------------------------- +  - ----- + ------ +
    | jcol | 尺寸| 免费|
    + ----------------------------------------------- +  - ----- + ------ +
    | {“a”:1000,“b”:“wxyz”,“c”:“[1,3,5,7]”} | 47 | 0 |
    + ----------------------------------------------- +  - ----- + ------ +
    1排(0.00秒)
    

    根据输出 JSON_STORAGE_SIZE() ,插入到列中的JSON文档占用47个字节。 我们还检查了以前使用该列的任何部分更新释放的空间量 JSON_STORAGE_FREE() ; 由于尚未执行任何更新,因此预期为0。

    接下来,我们 UPDATE 在表上 执行一个 应该导致存储的文档的部分更新 jcol ,然后测试结果,如下所示:

    mysql> UPDATE jtable SET jcol = 
        - >     JSON_SET(jcol, "$.b", "a");
    查询正常,1行受影响(0.04秒)
    匹配的行数:1已更改:1警告:0
    
    mysql> SELECT
        - >      jcol,
        - >      JSON_STORAGE_SIZE(jcol) AS Size,
        - >      JSON_STORAGE_FREE(jcol) AS Free
        - >FROM jtable;
    + -------------------------------------------- + ---- -  + ------ +
    | jcol | 尺寸| 免费|
    + -------------------------------------------- + ---- -  + ------ +
    | {“a”:1000,“b”:“a”,“c”:“[1,3,5,7]”} | 47 | 3 |
    + -------------------------------------------- + ---- -  + ------ +
    1排(0.00秒)
    

    JSON_STORAGE_FREE() 上一个查询 返回的值 表示执行了JSON文档的部分更新,并释放了用于存储它的3个字节的空间。 返回的结果由 JSON_STORAGE_SIZE() 部分更新保持不变。

    部分更新使用支持更新 JSON_SET() JSON_REPLACE() JSON_REMOVE() JSON 不能部分更新 值到 的直接分配 ; 在进行此类更新后, JSON_STORAGE_SIZE() 始终显示用于新设置值的存储:

    mysql> UPDATE jtable
    mysql>     SET jcol = '{"a": 4.55, "b": "wxyz", "c": "[true, false]"}';
    查询正常,1行受影响(0.04秒)
    匹配的行数:1已更改:1警告:0
    
    mysql> SELECT
        - >      jcol,
        - >      JSON_STORAGE_SIZE(jcol) AS Size,
        - >      JSON_STORAGE_FREE(jcol) AS Free
        - >FROM jtable;
    + ------------------------------------------------ + ------ + ------ +
    | jcol | 尺寸| 免费|
    + ------------------------------------------------ + ------ + ------ +
    | {“a”:4.55,“b”:“wxyz”,“c”:“[true,false]”} | 56 | 0 |
    + ------------------------------------------------ + ------ + ------ +
    1排(0.00秒)
    

    无法部分更新JSON用户变量。 这意味着此函数始终显示当前用于在用户变量中存储JSON文档的空间:

    MySQL的> SET @j = '[100, "sakila", [1, 3, 5], 425.05]';
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    + ------------------------------------ + ------ +
    | @j | 尺寸|
    + ------------------------------------ + ------ +
    | [100,“sakila”,[1,3,5],425.05] | 45 |
    + ------------------------------------ + ------ +
    1排(0.00秒)
    
    MySQL的> SET @j = JSON_SET(@j, '$[1]', "json");
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    + ---------------------------------- + ------ +
    | @j | 尺寸|
    + ---------------------------------- + ------ +
    | [100,“json”,[1,3,5],425.05] | 43 |
    + ---------------------------------- + ------ +
    1排(0.00秒)
    
    MySQL的> SET @j = JSON_SET(@j, '$[2][0]', JSON_ARRAY(10, 20, 30));
    查询正常,0行受影响(0.00秒)
    
    MySQL的> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    + --------------------------------------------- + --- --- +
    | @j | 尺寸|
    + --------------------------------------------- + --- --- +
    | [100,“json”,[[10,20,30],3,5],425.05] | 56 |
    + --------------------------------------------- + --- --- +
    1排(0.00秒)
    

    对于JSON文字,此函数始终返回当前使用的存储空间:

    mysql> SELECT
        - >      JSON_STORAGE_SIZE('[100, "sakila", [1, 3, 5], 425.05]') AS A,
        - >      JSON_STORAGE_SIZE('{"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"}') AS B,
        - >      JSON_STORAGE_SIZE('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}') AS C,
        - >     JSON_STORAGE_SIZE('[100, "json", [[10, 20, 30], 3, 5], 425.05]') AS D;
    + ---- + ---- + ---- + ---- +
    | A | B | C | D |
    + ---- + ---- + ---- + ---- +
    | 45 | 44 | 47 | 56 |
    + ---- + ---- + ---- + ---- +
    1排(0.00秒)
    

12.18与全局事务标识符(GTID)一起使用的函数

本节中描述的功能与基于GTID的复制一起使用。 重要的是要记住,所有这些函数都将GTID集的字符串表示作为参数。 因此,与它们一起使用时,必须始终引用GTID集。 有关 更多信息, 请参阅 GTID集

两个GTID集合的联合只是它们作为字符串的表示,用插入的逗号连接在一起。 换句话说,您可以定义一个非常简单的函数来获取两个GTID集的并集,类似于此处创建的:

创建功能GTID_UNION(g1 TEXT,g2 TEXT)
    返回文本确定性
    返回CONCAT(g1,',',g2);

有关GTID以及如何在实践中使用这些GTID功能的更多信息,请参见 第17.1.3节“使用全局事务标识符进行复制”

表12.23 GTID功能

名称 描述
GTID_SUBSET() 如果子集中的所有GTID也已设置,则返回true;否则返回true。 否则是假的。
GTID_SUBTRACT() 返回集合中不在子集中的所有GTID。
WAIT_FOR_EXECUTED_GTID_SET() 等到给定的GTID在slave上执行。
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 等到给定的GTID在slave上执行。

  • GTID_SUBSET(set1,set2)

    由于两套全局事务标识符 set1 set2 ,如果所有GTIDs返回true set1 也是 set2 否则返回false。

    与此函数一起使用的GTID集表示为字符串,如以下示例所示:

    mysql> SELECT GTID_SUBSET('3E11FA47-71CA-11E1-9E33-C80AA9429562:23',
        - >     '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')\G
    *************************** 1。排******************** *******
    GTID_SUBSET( '3E11FA47-71CA-11E1-9E33-C80AA9429562:23'
        '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'):1
    1排(0.00秒)
    
    mysql> SELECT GTID_SUBSET('3E11FA47-71CA-11E1-9E33-C80AA9429562:23-25',
        - >     '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')\G
    *************************** 1。排******************** *******
    GTID_SUBSET( '3E11FA47-71CA-11E1-9E33-C80AA9429562:23-25',
        '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'):1
    1排(0.00秒)
    
    mysql> SELECT GTID_SUBSET('3E11FA47-71CA-11E1-9E33-C80AA9429562:20-25',
        - >     '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')\G
    *************************** 1。排******************** *******
    GTID_SUBSET( '3E11FA47-71CA-11E1-9E33-C80AA9429562:20-25',
        '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'):0
    1排(0.00秒)
    
  • GTID_SUBTRACT(set1,set2)

    由于两套全局事务标识符 set1 set2 ,只返回那些GTIDs set1 不在 set2

    与此函数一起使用的所有GTID集都表示为字符串,必须引用,如下例所示:

    mysql> SELECT GTID_SUBTRACT('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57',
        - >     '3E11FA47-71CA-11E1-9E33-C80AA9429562:21')\G
    *************************** 1。排******************** *******
    GTID_SUBTRACT( '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57',
        '3E11FA47-71CA-11E1-9E33-C80AA9429562:21'):3e11fa47-71ca-11e1-9e33-c80aa9429562:22-57
    1排(0.00秒)
    
    mysql> SELECT GTID_SUBTRACT('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57',
        - >     '3E11FA47-71CA-11E1-9E33-C80AA9429562:20-25')\G
    *************************** 1。排******************** *******
    GTID_SUBTRACT( '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57',
        '3E11FA47-71CA-11E1-9E33-C80AA9429562:20-25'):3e11fa47-71ca-11e1-9e33-c80aa9429562:26-57
    1排(0.00秒)
    
    mysql> SELECT GTID_SUBTRACT('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57',
        - >     '3E11FA47-71CA-11E1-9E33-C80AA9429562:23-24')\G
    *************************** 1。排******************** *******
    GTID_SUBTRACT( '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57',
        '3E11FA47-71CA-11E1-9E33-C80AA9429562:23-24'):3e11fa47-71ca-11e1-9e33-c80aa9429562:21-22:25-57
    1排(0.01秒)
    
  • WAIT_FOR_EXECUTED_GTID_SET(gtid_set[, timeout])

    等到服务器应用了包含全局事务标识符的所有事务 gtid_set ; 也就是说,直到条件GTID_SUBSET( gtid_subset @@GLOBAL.gtid_executed )成立。 有关 GTID集的定义, 请参见 第17.1.3.1节“GTID格式和存储”

    如果指定了超时,并且 timeout 在应用GTID集中的所有事务之前经过了几秒钟,则该功能将停止等待。 timeout 是可选的,默认超时为0秒,在这种情况下,函数始终等待,直到应用了GTID集中的所有事务。

    WAIT_FOR_EXECUTED_GTID_SET() 监视服务器上应用的所有GTID,包括从所有复制通道和用户客户端到达的事务。 它没有考虑复制通道是否已启动或停止。

    有关更多信息,请参见 第17.1.3节“使用全局事务标识符进行复制”

    与此函数一起使用的GTID集表示为字符串,因此必须引用,如以下示例所示:

    MySQL的> SELECT WAIT_FOR_EXECUTED_GTID_SET('3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5');
            - > 0
    

    有关GTID集的语法说明,请参见 第17.1.3.1节“GTID格式和存储”

    对于 WAIT_FOR_EXECUTED_GTID_SET() ,返回值是查询的状态,其中0表示成功,1表示超时。 任何其他故障都会产生错误。

    gtid_mode 任何客户端使用此功能等待GTID应用时,都无法更改为OFF。

  • WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(gtid_set[, timeout][,channel])

    WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 类似于 WAIT_FOR_EXECUTED_GTID_SET() 它等待直到包含其全局事务标识符的所有事务 gtid_set 已被应用,或者直到 timeout 秒已经过去,以先发生者为准。 但是, WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 适用于特定的复制通道,并且仅在已在应用程序必须运行的指定通道上应用事务后停止。 相反, WAIT_FOR_EXECUTED_GTID_SET() 在应用事务后停止,无论它们应用于何处(在任何复制通道或任何用户客户端上),以及是否正在运行任何复制通道。

    channel 选项命名该函数适用的复制通道。 如果未命名通道且不存在默认复制通道以外的通道,则该功能将应用于默认复制通道。 如果存在多个复制通道,则必须指定通道,否则不知道该功能适用​​于哪个复制通道。 有关 复制通道 的更多信息 请参见 第17.2.3节“复制通道”

    注意

    由于 WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 应用于特定复制通道,如果预期事务到达不同的复制通道或用户客户端,例如在故障转移或手动恢复情况下,如果未设置超时,则该函数可无限期挂起。 使用 WAIT_FOR_EXECUTED_GTID_SET() ,而不是确保在这些情况下交易的正确处理。

    使用的GTID集 WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 表示为字符串,必须以与for相同的方式引用 WAIT_FOR_EXECUTED_GTID_SET() 因为 WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() ,函数的返回值是任意正数。 如果基于GTID的复制未激活(即,如果 gtid_mode 变量的值为OFF),则此值未定义并 WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() 返回NULL。 如果从站未运行,则该函数也返回NULL。

    gtid_mode 任何客户端使用此功能等待GTID应用时,都无法更改为OFF。

12.19 MySQL企业加密功能

注意

MySQL Enterprise Encryption是商业产品MySQL企业版中的扩展。 要了解有关商业产品的更多信息, 请访问https://www.mysql.com/products/

MySQL Enterprise Edition包含一组基于OpenSSL库的加密函数,这些函数在SQL级别公开OpenSSL功能。 这些功能使企业应用程序能够执行以下操作:

  • 使用公钥非对称加密实现增加的数据保护

  • 创建公钥和私钥以及数字签名

  • 执行非对称加密和解密

  • 使用加密散列进行数字签名和数据验证和验证

MySQL Enterprise Encryption支持RSA,DSA和DH加密算法。

MySQL Enterprise Encryption作为用户定义函数(UDF)库提供,可以从中单独安装各个函数。

12.19.1 MySQL Enterprise加密安装

MySQL Enterprise Encryption函数位于插件目录( plugin_dir 系统变量 指定的目录)中安装的用户定义函数(UDF)库文件中 UDF库基本名称 openssl_udf 和后缀是平台相关的。 例如,Linux或Windows上的文件名 分别 openssl_udf.so openssl_udf.dll

要从库文件安装函数,请使用 CREATE FUNCTION 语句。 要从库中加载所有函数,请使用这组语句(根据需要调整文件名后缀):

CREATE FUNCTION asymmetric_decrypt RETURNS STRING
  SONAME'openssl_udf.so';
CREATE FUNCTION asymmetric_derive RETURNS STRING
  SONAME'openssl_udf.so';
CREATE FUNCTION asymmetric_encrypt RETURNS STRING
  SONAME'openssl_udf.so';
CREATE FUNCTION asymmetric_sign RETURNS STRING
  SONAME'openssl_udf.so';
CREATE FUNCTION asymmetric_verify RETURNS INTEGER
  SONAME'openssl_udf.so';
创建功能create_asymmetric_priv_key返回STRING
  SONAME'openssl_udf.so';
CREATE FUNCTION create_asymmetric_pub_key RETURNS STRING
  SONAME'openssl_udf.so';
创建功能create_dh_parameters RETURNS STRING
  SONAME'openssl_udf.so';
CREATE FUNCTION create_digest RETURNS STRING
  SONAME'openssl_udf.so';

安装后,UDF将在服务器重新启动时保持安装状态。 要卸载UDF,请使用 DROP FUNCTION 语句。 例如,要卸载密钥生成功能,请执行以下操作:

DROP FUNCTION create_asymmetric_priv_key;
DROP FUNCTION create_asymmetric_pub_key;

CREATE FUNCTION DROP FUNCTION 语句中,函数名必须以小写形式指定。 这与它们在函数调用时的使用不同,您可以使用任何字母。

CREATE FUNCTION DROP FUNCTION 语句需要 INSERT DROP 权限,分别为 mysql 数据库。

12.19.2 MySQL Enterprise加密用法和示例

要在应用程序中使用MySQL Enterprise Encryption,请调用适合您要执行的操作的函数。 本节演示如何执行一些代表性任务:

使用RSA加密创建私钥/公钥对

 -  加密演算法; 可以是“DSA”或“DH”
SET @algo ='RSA';
- 密钥长度; 为更强的钥匙做大
SET @key_len = 1024;

- 创建私钥
SET @priv = CREATE_ASYMMETRIC_PRIV_KEY(@ algo,@ key_len);
- 使用相同的算法从私钥导出相应的公钥
SET @pub = CREATE_ASYMMETRIC_PUB_KEY(@algo,@ priv);

现在,您可以使用密钥对来加密和解密数据,签名和验证数据,或生成对称密钥。

使用私钥加密数据,使用公钥解密

这要求密钥对的成员是RSA密钥。

SET @ciphertext = ASYMMETRIC_ENCRYPT(@algo,'我的秘密文本',@ priv);
SET @plaintext = ASYMMETRIC_DECRYPT(@ algo,@ ciphertext,@ pub);

相反,您可以使用公钥进行加密并使用私钥进行解密。

SET @ciphertext = ASYMMETRIC_ENCRYPT(@algo,'我的秘密文本',@ pub);
SET @plaintext = ASYMMETRIC_DECRYPT(@ algo,@ ciphertext,@ priv);

在任何一种情况下,为加密和解密函数指定的算法必须与用于生成密钥的算法匹配。

从字符串生成摘要

 - 摘要类型; 可以是'SHA256','SHA384'或'SHA512'
SET @dig_type ='SHA224';

- 生成摘要字符串
SET @dig = CREATE_DIGEST(@dig_type,'我要消化的文字');

使用密钥对的摘要

密钥对可用于签署数据,然后验证签名是否与摘要匹配。

 -  加密演算法; 可能是'DSA'; 钥匙必须
- 使用相同的算法创建
SET @algo ='RSA';

- 为摘要生成签名并根据摘要验证签名
SET @sig = ASYMMETRIC_SIGN(@ algo,@ dig,@ priv,@ dig_type);
- 验证签名与摘要
SET @verf = ASYMMETRIC_VERIFY(@ algo,@ dig,@ sig,@ pub,@ dig_type);

创建对称密钥

这需要DH私钥/公钥作为输入,使用共享的对称秘密创建。 通过传递密钥长度来创建秘密 CREATE_DH_PARAMETERS() ,然后将密钥作为 密钥长度 传递给 CREATE_ASYMMETRIC_PRIV_KEY()

- 生成DH共享对称秘密
SET @dhp = CREATE_DH_PARAMETERS(1024);
- 生成DH密钥对
SET @algo ='DH';
SET @ priv1 = CREATE_ASYMMETRIC_PRIV_KEY(@algo,@ dhp);
SET @ pub1 = CREATE_ASYMMETRIC_PUB_KEY(@algo,@ priv1);
SET @ priv2 = CREATE_ASYMMETRIC_PRIV_KEY(@algo,@ dhp);
SET @ pub2 = CREATE_ASYMMETRIC_PUB_KEY(@algo,@ priv2);

- 使用第一方的公钥生成对称密钥,
- 第二方的私钥
SET @ sym1 = ASYMMETRIC_DERIVE(@ pub1,@ priv2);

- 或使用第二方的公钥,第一方的私钥
SET @ sym2 = ASYMMETRIC_DERIVE(@ pub2,@ priv1);

可以在运行时使用创建的密钥串的值,并存储到一个变量或表 SET SELECT INSERT

SET @ priv1 = CREATE_ASYMMETRIC_PRIV_KEY('RSA',1024);
SELECT CREATE_ASYMMETRIC_PRIV_KEY('RSA',1024)INTO @ priv2;
INSERT INTO t(key_col)VALUES(CREATE_ASYMMETRIC_PRIV_KEY('RSA',1024));

存储在文件中的键字符串值可以 LOAD_FILE() 由具有该 FILE 权限的 用户 使用该 函数 读取

摘要和签名字符串可以类似地处理。

通过密钥生成操作限制CPU使用率

CREATE_ASYMMETRIC_PRIV_KEY() CREATE_DH_PARAMETERS() 加密函数采用一个密钥长度参数,和CPU资源的这些功能所需的量随着密钥长度增加而增加。 对于某些安装,如果应用程序经常生成过长的密钥,则可能会导致CPU使用率不可接受。

OpenSSL为所有密钥强加最小密钥长度1,024位。 OpenSSL还为DSA和RSA密钥分别施加10,000位和16,384位 CREATE_ASYMMETRIC_PRIV_KEY() 的最大密钥长度,最大密钥长度为10,000位 CREATE_DH_PARAMETERS() 如果这些最大值太高,则可以使用三个环境变量来使MySQL服务器管理员为密钥生成设置较低的最大长度,从而限制CPU使用率:

  • MYSQL_OPENSSL_UDF_DSA_BITS_THRESHOLD :最大DSA密钥长度(以位为单位) CREATE_ASYMMETRIC_PRIV_KEY() 此变量的最小值和最大值为1,024和10,000。

  • MYSQL_OPENSSL_UDF_RSA_BITS_THRESHOLD :最大RSA密钥长度(以位为单位) CREATE_ASYMMETRIC_PRIV_KEY() 此变量的最小值和最大值分别为1,024和16,384。

  • MYSQL_OPENSSL_UDF_DH_BITS_THRESHOLD :最大密钥长度(以位为单位) CREATE_DH_PARAMETERS() 此变量的最小值和最大值为1,024和10,000。

要使用任何这些环境变量,请在启动服务器的进程的环境中设置它们。 如果设置,则它们的值优先于OpenSSL施加的最大密钥长度。 例如,要为DSA和RSA密钥设置最大密钥长度为4,096位 CREATE_ASYMMETRIC_PRIV_KEY() ,请设置以下变量:

export MYSQL_OPENSSL_UDF_DSA_BITS_THRESHOLD = 4096
export MYSQL_OPENSSL_UDF_RSA_BITS_THRESHOLD = 4096

该示例使用Bourne shell语法。 其他shell的语法可能不同。

12.19.3 MySQL企业加密功能参考

表12.24 MySQL企业加密功能

名称 描述
ASYMMETRIC_DECRYPT() 使用私钥或公钥解密密文
ASYMMETRIC_DERIVE() 从非对称密钥导出对称密钥
ASYMMETRIC_ENCRYPT() 使用私钥或公钥加密明文
ASYMMETRIC_SIGN() 从摘要生成签名
ASYMMETRIC_VERIFY() 验证签名是否与摘要匹配
CREATE_ASYMMETRIC_PRIV_KEY() 创建私钥
CREATE_ASYMMETRIC_PUB_KEY() 创建公钥
CREATE_DH_PARAMETERS() 生成共享DH密钥
CREATE_DIGEST() 从字符串生成摘要

12.19.4 MySQL企业加密功能描述

MySQL Enterprise Encryption功能具有以下一般特征:

  • 对于错误类型或不正确数量的参数的参数,每个函数都会返回错误。

  • 如果参数不适合允许函数执行所请求的操作,则它会 NULL 根据需要 返回 0或0。 例如,如果函数不支持指定的算法,密钥长度太短或太长,或者预期为PEM格式的密钥字符串的字符串不是有效密钥,则会发生这种情况。 (OpenSSL强加了自己的密钥长度限制,服务器管理员可以通过设置环境变量对最大密钥长度施加额外限制。请参见 第12.19.2节“MySQL Enterprise加密用法和示例” 。)

  • 底层SSL库负责随机初始化。

其中一些函数采用加密算法参数。 下表按功能总结了支持的算法。

表12.25按功能支持的算法


注意

虽然您可以使用任何RSA,DSA或DH加密算法创建密钥,但其他带有关键参数的函数可能只接受某些类型的密钥。 例如, ASYMMETRIC_ENCRYPT() 并且 ASYMMETRIC_DECRYPT() 只接受RSA密钥。

以下描述描述了MySQL Enterprise Encryption功能的调用序列。 有关其他示例和讨论,请参见 第12.19.2节“MySQL Enterprise Encryption用法和示例”

  • ASYMMETRIC_DECRYPT(algorithm, crypt_str, key_str)

    使用给定的算法和密钥字符串解密加密的字符串,并将生成的明文作为二进制字符串返回。 如果解密失败,结果是 NULL

    key_str 必须是PEM格式的有效密钥字符串。 为了成功解密,它必须是与 ASYMMETRIC_ENCRYPT() 用于生成加密字符串 的私钥或公钥字符串对应的公钥或私钥 字符串。 algorithm 表示用于创建密钥的加密算法。

    支持的 algorithm 值: 'RSA'

    有关用法示例,请参阅说明 ASYMMETRIC_ENCRYPT()

  • ASYMMETRIC_DERIVE(pub_key_str, priv_key_str)

    使用一方的私钥和另一方的公钥来派生对称密钥,并将得到的密钥作为二进制字符串返回。 如果密钥派生失败,则结果为 NULL

    pub_key_str 并且 priv_key_str 必须是PEM格式的有效密钥字符串。 必须使用DH算法创建它们。

    假设您有两对公钥和私钥:

    SET @dhp = CREATE_DH_PARAMETERS(1024);
    SET @ priv1 = CREATE_ASYMMETRIC_PRIV_KEY('DH',@ dhp);
    SET @ pub1 = CREATE_ASYMMETRIC_PUB_KEY('DH',@ priv1);
    SET @ priv2 = CREATE_ASYMMETRIC_PRIV_KEY('DH',@ dhp);
    SET @ pub2 = CREATE_ASYMMETRIC_PUB_KEY('DH',@ priv2);
    

    进一步假设您使用一对中的私钥和另一对中的公钥来创建对称密钥字符串。 然后,这种对称的密钥身份关系成立:

    ASYMMETRIC_DERIVE(@ pub1,@ priv2)= ASYMMETRIC_DERIVE(@ pub2,@ priv1)
    
  • ASYMMETRIC_ENCRYPT(algorithm, str, key_str)

    使用给定的算法和密钥字符串加密字符串,并将生成的密文作为二进制字符串返回。 如果加密失败,结果是 NULL

    str 长度不能大于更大 key_str 长度- 11,以字节为单位

    key_str 必须是PEM格式的有效密钥字符串。 algorithm 表示用于创建密钥的加密算法。

    支持的 algorithm 值: 'RSA'

    要加密字符串,请将私钥或公钥字符串传递给 ASYMMETRIC_ENCRYPT() 要恢复原始未加密的字符串,请将加密的字符串 ASYMMETRIC_DECRYPT() 与公钥或私钥字符串一起 传递 给与用于加密的私钥或公钥字符串相对应。

    - 生成私钥/公钥对
    SET @priv = CREATE_ASYMMETRIC_PRIV_KEY('RSA',1024);
    SET @pub = CREATE_ASYMMETRIC_PUB_KEY('RSA',@ priv);
    
    - 使用私钥加密,使用公钥解密
    SET @ciphertext = ASYMMETRIC_ENCRYPT('RSA','快速棕狐',@ priv);
    SET @plaintext = ASYMMETRIC_DECRYPT('RSA',@ ciphertext,@ pub);
    
    - 使用公钥加密,使用私钥解密
    SET @ciphertext = ASYMMETRIC_ENCRYPT('RSA','快速棕狐',@ pub);
    SET @plaintext = ASYMMETRIC_DECRYPT('RSA',@ ciphertext,@ priv);
    

    假设:

    SET @s =要加密的字符串
    SET @priv = PEM格式的有效私有RSA密钥字符串
    SET @pub = PEM格式的相应公共RSA密钥字符串
    

    然后这些身份关系成立:

    ASYMMETRIC_DECRYPT('RSA',ASYMMETRIC_ENCRYPT('RSA',@ s,@ priv),@ pub)= @s
    ASYMMETRIC_DECRYPT('RSA',ASYMMETRIC_ENCRYPT('RSA',@ s,@ pub),@ priv)= @s
    
  • ASYMMETRIC_SIGN(algorithm, digest_str, priv_key_str, digest_type)

    使用私钥字符串签署摘要字符串,并将签名作为二进制字符串返回。 如果签名失败,结果是 NULL

    digest_str 是摘要字符串。 它可以通过调用生成 CREATE_DIGEST() digest_type 表示用于生成摘要字符串的摘要算法。

    priv_key_str 是用于对摘要字符串进行签名的私钥字符串。 它必须是PEM格式的有效密钥字符串。 algorithm 表示用于创建密钥的加密算法。

    支持的 algorithm 值: 'RSA' 'DSA'

    支持的 digest_type 值: 'SHA224' 'SHA256' 'SHA384' 'SHA512'

    有关用法示例,请参阅说明 ASYMMETRIC_VERIFY()

  • ASYMMETRIC_VERIFY(algorithm, digest_str, sig_str, pub_key_str, digest_type)

    验证签名字符串是否与摘要字符串匹配,并返回1或0以指示验证是成功还是失败。

    digest_str 是摘要字符串。 它可以通过调用生成 CREATE_DIGEST() digest_type 表示用于生成摘要字符串的摘要算法。

    sig_str 是签名字符串。 它可以通过调用生成 ASYMMETRIC_SIGN()

    pub_key_str 是签名者的公钥字符串。 它对应于传递给 ASYMMETRIC_SIGN() 生成签名字符串 的私钥, 并且必须是PEM格式的有效密钥字符串。 algorithm 表示用于创建密钥的加密算法。

    支持的 algorithm 值: 'RSA' 'DSA'

    支持的 digest_type 值: 'SHA224' 'SHA256' 'SHA384' 'SHA512'

    - 设置加密算法和摘要类型
    SET @algo ='RSA';
    SET @dig_type ='SHA224';
    
    - 创建私钥/公钥对
    SET @priv = CREATE_ASYMMETRIC_PRIV_KEY(@algo,1024);
    SET @pub = CREATE_ASYMMETRIC_PUB_KEY(@algo,@ priv);
    
    - 从字符串生成摘要
    SET @dig = CREATE_DIGEST(@dig_type,'快速棕狐');
    
    - 为摘要生成签名并根据摘要验证签名
    SET @sig = ASYMMETRIC_SIGN(@ algo,@ dig,@ priv,@ dig_type);
    SET @verf = ASYMMETRIC_VERIFY(@ algo,@ dig,@ sig,@ pub,@ dig_type);
    
  • CREATE_ASYMMETRIC_PRIV_KEY(algorithm, {key_len|dh_secret})

    使用给定的算法和密钥长度或DH密钥创建私钥,并将密钥作为PEM格式的二进制字符串返回。 如果密钥生成失败,结果是 NULL

    支持的 algorithm 值: 'RSA' 'DSA' 'DH'

    支持的 key_len 值:最小密钥长度(以位为单位)为1,024。 最大密钥长度取决于算法:RSA为16,384,DSA为10,000。 这些密钥长度限制是OpenSSL强加的约束。 服务器管理员可以通过设置环境变量对最大密钥长度施加额外限制。 请参见 第12.19.2节“MySQL Enterprise Encryption用法和示例”

    对于DH密钥,传递共享DH密钥而不是密钥长度。 要创建密钥,请将密钥长度传递给 CREATE_DH_PARAMETERS()

    此示例创建一个2,048位DSA私钥,然后从私钥派生公钥:

    SET @priv = CREATE_ASYMMETRIC_PRIV_KEY('DSA',2048);
    SET @pub = CREATE_ASYMMETRIC_PUB_KEY('DSA',@ priv);
    

    有关显示DH密钥生成的示例,请参阅说明 ASYMMETRIC_DERIVE()

    选择密钥长度和加密算法时的一些一般注意事项:

    • 私钥和公钥的加密强度随密钥大小的增加而增加,但密钥生成的时间也会增加。

    • DH密钥的生成比RSA或RSA密钥花费更长的时间。

    • 非对称加密函数比对称函数慢。 如果性能是一个重要因素,并且要经常使用这些功能,那么最好使用对称加密。 例如,考虑使用 AES_ENCRYPT() AES_DECRYPT()

  • CREATE_ASYMMETRIC_PUB_KEY(algorithm, priv_key_str)

    使用给定算法从给定私钥派生公钥,并将密钥作为PEM格式的二进制字符串返回。 如果密钥派生失败,则结果为 NULL

    priv_key_str 必须是PEM格式的有效密钥字符串。 algorithm 表示用于创建密钥的加密算法。

    支持的 algorithm 值: 'RSA' 'DSA' 'DH'

    有关用法示例,请参阅说明 CREATE_ASYMMETRIC_PRIV_KEY()

  • CREATE_DH_PARAMETERS(key_len)

    创建用于生成DH私钥/公钥对的共享密钥,并返回可传递给的二进制字符串 CREATE_ASYMMETRIC_PRIV_KEY() 如果秘密生成失败,则结果为null。

    支持的 key_len 值:最小和最大密钥长度(以位为单位)为1,024和10,000。 这些密钥长度限制是OpenSSL强加的约束。 服务器管理员可以通过设置环境变量对最大密钥长度施加额外限制。 请参见 第12.19.2节“MySQL Enterprise Encryption用法和示例”

    有关如何使用返回值生成对称密钥的示例,请参阅的说明 ASYMMETRIC_DERIVE()

    SET @dhp = CREATE_DH_PARAMETERS(1024);
    
  • CREATE_DIGEST(digest_type, str)

    使用给定的摘要类型从给定字符串创建摘要,并将摘要作为二进制字符串返回。 如果摘要生成失败,结果是 NULL

    支持的 digest_type 值: 'SHA224' 'SHA256' 'SHA384' 'SHA512'

    SET @dig = CREATE_DIGEST('SHA512',快棕狐');
    

    生成的摘要字符串适合与 ASYMMETRIC_SIGN() 一起使用 ASYMMETRIC_VERIFY()

12.20聚合(GROUP BY)函数

12.20.1聚合(GROUP BY)功能描述

本节介绍对值集合进行操作的组(聚合)函数。

表12.26聚合(GROUP BY)函数

名称 描述
AVG() 返回参数的平均值
BIT_AND() 按位返回AND
BIT_OR() 按位返回OR
BIT_XOR() 按位返回异或
COUNT() 返回返回的行数
COUNT(DISTINCT) 返回许多不同值的计数
GROUP_CONCAT() 返回连接的字符串
JSON_ARRAYAGG() 将结果集作为单个JSON数组返回
JSON_OBJECTAGG() 将结果集作为单个JSON对象返回
MAX() 返回最大值
MIN() 返回最小值
STD() 返回人口标准差
STDDEV() 返回人口标准差
STDDEV_POP() 返回人口标准差
STDDEV_SAMP() 返回样本标准差
SUM() 归还总和
VAR_POP() 返回人口标准差异
VAR_SAMP() 返回样本方差
VARIANCE() 返回人口标准差异

除非另有说明,否则组函数会忽略 NULL 值。

如果在包含无 GROUP BY 子句 的语句中使用组函数 ,则等效于对所有行进行分组。 有关更多信息,请参见 第12.20.3节“GROUP BY的MySQL处理”

大多数聚合函数可用作窗口函数。 可以这种方式使用的那些在它们的语法描述中表示 ,表示可选 子句。 第12.21.2节“窗口函数概念和语法”中进行了描述 ,其中还包含有关窗口函数用法的其他信息。 [over_clause] OVER over_clause

对于数字参数,方差和标准差函数返回一个 DOUBLE 值。 SUM() AVG() 函数返回一个 DECIMAL 为准确值参数(整数或值 DECIMAL ),以及 DOUBLE 为近似值参数(值 FLOAT DOUBLE )。

SUM() AVG() 聚合函数不具有时间价值的工作。 (它们将值转换为数字,在第一个非数字字符后丢失所有内容。)要解决此问题,请转换为数字单位,执行聚合操作,然后转换回时间值。 例子:

SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col)))FROMtbl_name ;
SELECT FROM_DAYS(SUM(TO_DAYS(date_col)))FROM tbl_name;

如果需要, 诸如 SUM() AVG() 期望数字参数的函数将参数强制转换为数字。 对于 SET ENUM 值,强制转换操作会导致使用基础数值。

BIT_AND() BIT_OR() BIT_XOR() 聚合函数执行位操作。 在MySQL 8.0之前,位函数和运算符需要 BIGINT (64位整数)参数和返回 BIGINT 值,因此它们的最大范围为64位。 BIGINT 参数 BIGINT 在执行操作之前 被转换为 可能发生截断。

在MySQL 8.0中,位函数和运算符允许二进制字符串类型参数( BINARY VARBINARY BLOB 类型)并返回类似的值,这使它们能够获取参数并生成大于64位的返回值。 有关位操作的参数评估和结果类型的讨论,请参见 第12.12节“位功能和操作符”中 的介绍性讨论

  • AVG([DISTINCT] expr) [over_clause]

    返回的平均值 expr DISTINCT 选项可用于返回不同值的平均值 expr

    如果没有匹配的行,则 AVG() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述 ; 它不能用于 DISTINCT

    MySQL的> SELECT student_name, AVG(test_score)
           FROM student
           GROUP BY student_name;
    
  • BIT_AND(expr) [over_clause]

    返回 AND 所有位 的按 expr

    结果类型取决于函数参数值是作为二进制字符串还是数字计算:

    • 当参数值具有二进制字符串类型且参数不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数值转换为无符号64位整数。

    • 二进制字符串评估生成与参数值长度相同的二进制字符串。 如果参数值具有不相等的长度, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 如果参数大小超过511个字节, ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

    如果没有匹配的行,则 BIT_AND() 返回与参数值具有相同长度的中性值(所有位设置为1)。

    NULL 除非所有值都是,否则值不会影响结果 NULL 在这种情况下,结果是具有与参数值相同长度的中性值。

    有关参数评估和结果类型的更多信息讨论,请参见 第12.12节“位功能和操作符”中 的介绍性讨论

    从MySQL 8.0.12开始,如果 over_clause 存在 ,该函数将作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • BIT_OR(expr) [over_clause]

    返回 OR 所有位 的按 expr

    结果类型取决于函数参数值是作为二进制字符串还是数字计算:

    • 当参数值具有二进制字符串类型且参数不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数值转换为无符号64位整数。

    • 二进制字符串评估生成与参数值长度相同的二进制字符串。 如果参数值具有不相等的长度, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 如果参数大小超过511个字节, ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

    如果没有匹配的行,则 BIT_OR() 返回与参数值具有相同长度的中性值(所有位设置为0)。

    NULL 除非所有值都是,否则值不会影响结果 NULL 在这种情况下,结果是具有与参数值相同长度的中性值。

    有关参数评估和结果类型的更多信息讨论,请参见 第12.12节“位功能和操作符”中 的介绍性讨论

    从MySQL 8.0.12开始,如果 over_clause 存在 ,该函数将作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • BIT_XOR(expr) [over_clause]

    返回 XOR 所有位 的按 expr

    结果类型取决于函数参数值是作为二进制字符串还是数字计算:

    • 当参数值具有二进制字符串类型且参数不是十六进制文字,位字面值或 NULL 文字 时,会发生二进制字符串评估 否则进行数值计算,必要时将参数值转换为无符号64位整数。

    • 二进制字符串评估生成与参数值长度相同的二进制字符串。 如果参数值具有不相等的长度, ER_INVALID_BITWISE_OPERANDS_SIZE 则会发生错误。 如果参数大小超过511个字节, ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE 则会发生错误。 数值计算生成无符号的64位整数。

    如果没有匹配的行,则 BIT_XOR() 返回与参数值具有相同长度的中性值(所有位设置为0)。

    NULL 除非所有值都是,否则值不会影响结果 NULL 在这种情况下,结果是具有与参数值相同长度的中性值。

    有关参数评估和结果类型的更多信息讨论,请参见 第12.12节“位功能和操作符”中 的介绍性讨论

    从MySQL 8.0.12开始,如果 over_clause 存在 ,该函数将作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • COUNT(expr) [over_clause]

    返回 语句 检索的行 中非 NULL 数的计数 结果是一个 值。 expr SELECT BIGINT

    如果没有匹配的行,则 COUNT() 返回 0

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 如...中所述 第12.21.2节“窗口函数概念和语法”中所述

    MySQL的> SELECT student.student_name,COUNT(*)
           FROM student,course
           WHERE student.student_id=course.student_id
           GROUP BY student_name;
    

    COUNT(*) 有点不同,它返回检索的行数,无论它们是否包含 NULL 值。

    对于事务性存储引擎,例如 InnoDB ,存储精确的行数是有问题的。 多个交易可能同时发生,每个交易都可能影响计数。

    InnoDB 不保留表中的内部行数,因为并发事务可能同时 看到 不同数量的行。 因此, SELECT COUNT(*) 语句只计算当前事务可见的行。

    从MySQL 8.0.13开始, 如果没有诸如 或之类的 额外子句,则针对单线程工作负载优化表的 查询性能 SELECT COUNT(*) FROM tbl_name InnoDB WHERE GROUP BY

    InnoDB SELECT COUNT(*) 通过遍历最小的可用二级索引来 处理 语句,除非索引或优化程序提示指示优化程序使用不同的索引。 如果不存在辅助索引,则 通过扫描聚簇索引来 InnoDB 处理 SELECT COUNT(*) 语句。

    SELECT COUNT(*) 如果索引记录不完​​全在缓冲池中,则 处理 语句需要一些时间。 为了更快地计算,请创建一个计数器表,让应用程序根据插入和删除更新它。 但是,在数千个并发事务正在启动对同一计数器表的更新的情况下,此方法可能无法很好地扩展。 如果大概行数足够,请使用 SHOW TABLE STATUS

    InnoDB 以相同的方式 处理 SELECT COUNT(*) SELECT COUNT(1) 操作。 没有性能差异。

    对于 MyISAM 表, COUNT(*) 如果 SELECT 从一个表检索,没有检索到其他列,并且没有 WHERE 子句 则优化为非常快速地返回 例如:

    MySQL的> SELECT COUNT(*) FROM student;
    

    此优化仅适用于 MyISAM 表,因为为此存储引擎存储了精确的行数,并且可以非常快速地访问。 COUNT(1) 如果第一列定义为,则仅受相同优化的影响 NOT NULL

  • COUNT(DISTINCT expr,[expr...])

    返回具有不同非 NULL expr 的行数

    如果没有匹配的行,则 COUNT(DISTINCT) 返回 0

    MySQL的> SELECT COUNT(DISTINCT results) FROM student;
    

    在MySQL中,您可以 NULL 通过提供表达式列表 来获取不包含的不同表达式组合的数量 在标准SQL中,您必须对内部的所有表达式进行连接 COUNT(DISTINCT ...)

  • GROUP_CONCAT(expr)

    此函数返回字符串结果,其中 NULL 包含来自组 的连接非 值。 NULL 如果没有非 NULL ,则返回 完整语法如下:

    GROUP_CONCAT([DISTINCT] expr[,expr...]
                 [ORDER BY { unsigned_integer| col_name| expr}
                     [ASC | DESC] [,col_name ...]]
                 [SEPARATOR str_val])
    
    MySQL的> SELECT student_name,
             GROUP_CONCAT(test_score)
           FROM student
           GROUP BY student_name;
    

    要么:

    MySQL的> SELECT student_name,
             GROUP_CONCAT(DISTINCT test_score
                          ORDER BY test_score DESC SEPARATOR ' ')
           FROM student
           GROUP BY student_name;
    

    在MySQL中,您可以获得表达式组合的连接值。 要消除重复值,请使用该 DISTINCT 子句。 要对结果中的值进行排序,请使用该 ORDER BY 子句。 要按相反顺序排序,请将 DESC (descending)关键字 添加 到要在 ORDER BY 子句 中排序的列的名称中 默认为升序; 这可以使用 ASC 关键字 明确指定 组中值之间的默认分隔符是逗号( , )。 要明确指定分隔符,请使用 SEPARATOR 后跟应在组值之间插入的字符串文字值。 要完全消除分隔符,请指定 SEPARATOR ''

    结果被截断为 group_concat_max_len 系统变量 给出的最大长度 ,其默认值为1024.尽管返回值的有效最大长度受值的约束,但该值可以设置得更高 max_allowed_packet group_concat_max_len 在运行时 更改值的语法 如下,其中 val 是无符号整数:

    SET [GLOBAL | SESSION] group_concat_max_len = val;
    

    返回值是非二进制或二进制字符串,具体取决于参数是非二进制还是二进制字符串。 结果类型是 TEXT 或者 BLOB 除非 group_concat_max_len 小于或等于512,在这种情况下结果类型是 VARCHAR VARBINARY

    另见 CONCAT() CONCAT_WS() 第12.5节“字符串函数”

  • JSON_ARRAYAGG(col_or_expr) [over_clause]

    将结果集聚合为单个 JSON 数组,其元素由行组成。 此数组中元素的顺序未定义。 该函数作用于计算为单个值的列或表达式。 返回 NULL 如果结果不包含任何行,或在错误的事件。

    从MySQL 8.0.14开始,如果 over_clause 存在 ,该函数将作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

    MySQL的> SELECT o_id, attribute, value FROM t3;
    + ------ + ----------- + -------- +
    | o_id | 属性| 价值|
    + ------ + ----------- + -------- +
    | 2 | 颜色| 红色|
    | 2 | 面料| 丝绸|
    | 3 | 颜色| 绿色|
    | 3 | 形状| 广场|
    + ------ + ----------- + -------- +
    4行(0.00秒)
    
    MySQL的> SELECT o_id, JSON_ARRAYAGG(attribute) AS attributes 
           FROM t3 GROUP BY o_id;
    + ------ + --------------------- +
    | o_id | 属性|
    + ------ + --------------------- +
    | 2 | [“颜色”,“面料”] |
    | 3 | [“颜色”,“形状”] |
    + ------ + --------------------- +
    2行(0.00秒)
    
  • JSON_OBJECTAGG(key, value) [over_clause]

    将两个列名或表达式作为参数,第一个用作键,第二个用作值,并返回包含键值对的JSON对象。 返回 NULL 如果结果不包含任何行,或在错误的事件。 如果任何键名称 NULL 或参数数量不等于2, 则会发生错误

    从MySQL 8.0.14开始,如果 over_clause 存在 ,该函数将作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

    MySQL的> SELECT o_id, attribute, value FROM t3;
    + ------ + ----------- + -------- +
    | o_id | 属性| 价值|
    + ------ + ----------- + -------- +
    | 2 | 颜色| 红色|
    | 2 | 面料| 丝绸|
    | 3 | 颜色| 绿色|
    | 3 | 形状| 广场|
    + ------ + ----------- + -------- +
    4行(0.00秒)
    
    MySQL的> SELECT o_id, JSON_OBJECTAGG(attribute, value)
           FROM t3 GROUP BY o_id;
    + ------ + --------------------------------------- +
    | o_id | JSON_OBJECTAGG(属性,值)|
    + ------ + --------------------------------------- +
    | 2 | {“color”:“red”,“fabric”:“silk”}
    | 3 | {“color”:“green”,“shape”:“square”} |
    + ------ + --------------------------------------- +
    2行(0.00秒)
    
    重复密钥处理

    当对该函数的结果进行归一化时,丢弃具有重复键的值。 为了与 JSON 不允许重复键 的MySQL 数据类型规范 保持一致 ,只有遇到的最后一个值与返回对象中的该键一起使用( 最后重复键获胜 )。 这意味着在a的列上使用此函数的结果 SELECT 可以取决于返回行的顺序,这是不能保证的。 当用作窗口函数时,如果帧中存在重复的键,则结果中仅存在该键的最后一个值。 如果 ORDER BY 规范保证值具有特定顺序 ,则帧中最后一行的键值是确定的 如果不是,则键的结果值是不确定的。 考虑以下:

    MySQL的> CREATE TABLE t(c VARCHAR(10), i INT);
    查询正常,0行受影响(0.03秒)
    
    MySQL的> INSERT INTO t VALUES
           ('key', 3), ('key', 4), ('key', 5);
    查询OK,3行受影响(0.01秒)
    记录:3个重复:0个警告:0
    
    MySQL的> SELECT c, i FROM t;
    + ------ + ------ +
    | c | 我|
    + ------ + ------ +
    | 关键| 3 |
    | 关键| 4 |
    | 关键| 5 |
    + ------ + ------ +
    3组(0.00秒)
    
    MySQL的> SELECT JSON_OBJECTAGG(c, i) FROM t;
    + ---------------------- +
    | JSON_OBJECTAGG(c,i)|
    + ---------------------- +
    | {“key”:5} |
    + ---------------------- +
    1排(0.00秒)
    
    MySQL的> DELETE FROM t;
    查询OK,3行受影响(0.00秒)
    
    MySQL的> INSERT INTO t VALUES
           ('key', 3), ('key', 5), ('key', 4);
    查询OK,3行受影响(0.00秒)
    记录:3个重复:0个警告:0
    
    MySQL的> SELECT c, i FROM t;
    + ------ + ------ +
    | c | 我|
    + ------ + ------ +
    | 关键| 3 |
    | 关键| 5 |
    | 关键| 4 |
    + ------ + ------ +
    3组(0.00秒)
    
    MySQL的> SELECT JSON_OBJECTAGG(c, i) FROM t;
    + ---------------------- +
    | JSON_OBJECTAGG(c,i)|
    + ---------------------- +
    | {“key”:4} |
    + ---------------------- +
    1排(0.00秒)
    

    从上一个查询中选择的密钥是不确定的。 如果您更喜欢特定的键排序,则可以 JSON_OBJECTAGG() 通过包含 OVER 带有 ORDER BY 规范 子句 来调用 作为窗口函数, 以在帧行上强加特定顺序。 以下示例显示了 ORDER BY 对于一些不同的帧规范 会发生和不发生的情况

    没有 ORDER BY ,框架是整个分区:

    MySQL的> SELECT JSON_OBJECTAGG(c, i)
           OVER () AS json_object FROM t;
    + ------------- +
    | json_object |
    + ------------- +
    | {“key”:4} |
    | {“key”:4} |
    | {“key”:4} |
    + ------------- +
    

    with ORDER BY ,其中框架是默认值 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW (按升序和降序排列):

    MySQL的> SELECT JSON_OBJECTAGG(c, i)
           OVER (ORDER BY i) AS json_object FROM t;
    + ------------- +
    | json_object |
    + ------------- +
    | {“key”:3} |
    | {“key”:4} |
    | {“key”:5} |
    + ------------- +
    MySQL的> SELECT JSON_OBJECTAGG(c, i)
           OVER (ORDER BY i DESC) AS json_object FROM t;
    + ------------- +
    | json_object |
    + ------------- +
    | {“key”:5} |
    | {“key”:4} |
    | {“key”:3} |
    + ------------- +
    

    使用 ORDER BY 和整个分区的显式框架:

    MySQL的> SELECT JSON_OBJECTAGG(c, i)
           OVER (ORDER BY i
                ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
            AS json_object
           FROM t;
    + ------------- +
    | json_object |
    + ------------- +
    | {“key”:5} |
    | {“key”:5} |
    | {“key”:5} |
    + ------------- +
    

    要返回特定键值(例如最小值或最大值),请 LIMIT 在相应的查询中 包含一个 子句。 例如:

    MySQL的> SELECT JSON_OBJECTAGG(c, i)
           OVER (ORDER BY i) AS json_object FROM t LIMIT 1;
    + ------------- +
    | json_object |
    + ------------- +
    | {“key”:3} |
    + ------------- +
    MySQL的> SELECT JSON_OBJECTAGG(c, i)
           OVER (ORDER BY i DESC) AS json_object FROM t LIMIT 1;
    + ------------- +
    | json_object |
    + ------------- +
    | {“key”:5} |
    + ------------- +
    

    有关 其他信息和示例 请参阅 JSON值的规范化,合并和自动包装

  • MAX([DISTINCT] expr) [over_clause]

    返回的最大值 expr MAX() 可以采用字符串参数; 在这种情况下,它返回最大字符串值。 请参见 第8.3.1节“MySQL如何使用索引” DISTINCT 关键字可用于以找到最大的不同值中的 expr ,然而,这产生相同的结果作为遗漏 DISTINCT

    如果没有匹配的行,则 MAX() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述 ; 它不能用于 DISTINCT

    MySQL的> SELECT student_name, MIN(test_score), MAX(test_score)
           FROM student
           GROUP BY student_name;
    

    因为 MAX() ,MySQL当前 按字符串值 比较 ENUM SET 列,而不是字符串在集合中的相对位置。 这与 ORDER BY 比较它们 有所不同

  • MIN([DISTINCT] expr) [over_clause]

    返回的最小值 expr MIN() 可以采用字符串参数; 在这种情况下,它返回最小字符串值。 请参见 第8.3.1节“MySQL如何使用索引” DISTINCT 关键字可用来找到最小的不同值中的 expr ,然而,这产生相同的结果作为遗漏 DISTINCT

    如果没有匹配的行,则 MIN() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述 ; 它不能用于 DISTINCT

    MySQL的> SELECT student_name, MIN(test_score), MAX(test_score)
           FROM student
           GROUP BY student_name;
    

    因为 MIN() ,MySQL当前 按字符串值 比较 ENUM SET 列,而不是字符串在集合中的相对位置。 这与 ORDER BY 比较它们 有所不同

  • STD(expr) [over_clause]

    返回人口标准差 expr STD() 是标准SQL函数的同义词 STDDEV_POP() ,作为MySQL扩展提供。

    如果没有匹配的行,则 STD() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • STDDEV(expr) [over_clause]

    返回人口标准差 expr STDDEV() STDDEV_POP() 与Oracle兼容 的标准SQL函数的同义词

    如果没有匹配的行,则 STDDEV() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • STDDEV_POP(expr) [over_clause]

    返回 expr (平方根 VAR_POP() 的总体标准差 你也可以使用 STD() STDDEV() 等效但不是标准SQL。

    如果没有匹配的行,则 STDDEV_POP() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • STDDEV_SAMP(expr) [over_clause]

    返回样本标准差 expr (的平方根) VAR_SAMP()

    如果没有匹配的行,则 STDDEV_SAMP() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • SUM([DISTINCT] expr) [over_clause]

    返回的总和 expr 如果返回集没有行,则 SUM() 返回 NULL DISTINCT 关键字可用来仅求和的不同的值 expr

    如果没有匹配的行,则 SUM() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述 ; 它不能用于 DISTINCT

  • VAR_POP(expr) [over_clause]

    返回人口标准方差 expr 它将行视为整个总体,而不是作为样本,因此它将行数作为分母。 您也可以使用 VARIANCE() ,这是等效的但不是标准SQL。

    如果没有匹配的行,则 VAR_POP() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • VAR_SAMP(expr) [over_clause]

    返回样本方差 expr 也就是说,分母是行数减1。

    如果没有匹配的行,则 VAR_SAMP() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • VARIANCE(expr) [over_clause]

    返回人口标准方差 expr VARIANCE() 是标准SQL函数的同义词 VAR_POP() ,作为MySQL扩展提供。

    如果没有匹配的行,则 VARIANCE() 返回 NULL

    如果 over_clause 存在, 该函数作为窗口函数执行 over_clause 第12.21.2节“窗口函数概念和语法”中所述

12.20.2 GROUP BY修饰符

GROUP BY 子句允许使用一个 WITH ROLLUP 修饰符,使得​​汇总输出包含表示更高级别(即超级聚合)汇总操作的额外行。 ROLLUP 因此,您可以使用单个查询在多个分析级别回答问题。 例如, ROLLUP 可用于为OLAP(在线分析处理)操作提供支持。

假设一个 sales 表有 year country product ,和 profit 列记录销售利润率:

CREATE TABLE销售
    年INT,
    country VARCHAR(20),
    产品VARCHAR(32),
    利润INT
);

要总结每年的表格内容,请使用以下简单的内容 GROUP BY

MySQL的> SELECT year, SUM(profit) AS profit
       FROM sales
       GROUP BY year;
+ ------ + -------- +
| 一年| 利润|
+ ------ + -------- +
| 2000年| 4525 |
| 2001 | 3010 |
+ ------ + -------- +

输出显示每年的总(总)利润。 要确定所有年份的总利润总额,您必须自己添加单个值或运行其他查询。 或者您可以使用 ROLLUP ,它通过单个查询提供两种级别的分析。 子句 添加 WITH ROLLUP 修饰符 GROUP BY 会导致查询生成另一个(超级聚合)行,该行显示所有年份值的总计:

MySQL的> SELECT year, SUM(profit) AS profit
       FROM sales
       GROUP BY year WITH ROLLUP;
+ ------ + -------- +
| 一年| 利润|
+ ------ + -------- +
| 2000年| 4525 |
| 2001 | 3010 |
| NULL | 7535 |
+ ------ + -------- +

列中 NULL year 标识总计超级聚合行。

ROLLUP 当有多 GROUP BY 时,会产生更复杂的效果 在这种情况下,每次除最后一个分组列之外的任何值发生更改时,查询都会生成一个额外的超级聚合摘要行。

例如,如果没有 ROLLUP ,该摘要 sales 基于表 year country 以及 product 可能是这样的,当输出只在一年/国家/产品的分析水平表明汇总值:

MySQL的> SELECT year, country, product, SUM(profit) AS profit
       FROM sales
       GROUP BY year, country, product;
+ ------ + --------- + ------------ + -------- +
| 一年| 国家| 产品| 利润|
+ ------ + --------- + ------------ + -------- +
| 2000年| 芬兰| 电脑| 1500 |
| 2000年| 芬兰| 电话| 100 |
| 2000年| 印度| 计算器| 150 |
| 2000年| 印度| 电脑| 1200 |
| 2000年| 美国| 计算器| 75 |
| 2000年| 美国| 电脑| 1500 |
| 2001 | 芬兰| 电话| 10 |
| 2001 | 美国| 计算器| 50 |
| 2001 | 美国| 电脑| 2700 |
| 2001 | 美国| 电视| 250 |
+ ------ + --------- + ------------ + -------- +

随着 ROLLUP 增加,查询会产生一些额外行:

MySQL的> SELECT year, country, product, SUM(profit) AS profit
       FROM sales
       GROUP BY year, country, product WITH ROLLUP;
+ ------ + --------- + ------------ + -------- +
| 一年| 国家| 产品| 利润|
+ ------ + --------- + ------------ + -------- +
| 2000年| 芬兰| 电脑| 1500 |
| 2000年| 芬兰| 电话| 100 |
| 2000年| 芬兰| NULL | 1600 |
| 2000年| 印度| 计算器| 150 |
| 2000年| 印度| 电脑| 1200 |
| 2000年| 印度| NULL | 1350 |
| 2000年| 美国| 计算器| 75 |
| 2000年| 美国| 电脑| 1500 |
| 2000年| 美国| NULL | 1575 |
| 2000年| NULL | NULL | 4525 |
| 2001 | 芬兰| 电话| 10 |
| 2001 | 芬兰| NULL | 10 |
| 2001 | 美国| 计算器| 50 |
| 2001 | 美国| 电脑| 2700 |
| 2001 | 美国| 电视| 250 |
| 2001 | 美国| NULL | 3000 |
| 2001 | NULL | NULL | 3010 |
| NULL | NULL | NULL | 7535 |
+ ------ + --------- + ------------ + -------- +

现在输出包括四个分析级别的摘要信息,而不仅仅是一个:

  • 在给定年份和国家/地区的每组产品行之后,将显示额外的超级汇总摘要行,显示所有产品的总计。 这些行的 product 列设置为 NULL

  • 在给定年份的每组行之后,将显示一个额外的超级汇总摘要行,显示所有国家/地区和产品的总计。 这些行具有 country products 列设置为 NULL

  • 最后,在所有其他行之后,将显示一个额外的超级汇总摘要行,显示所有年份,国家/地区和产品的总计。 此行的 year ,, country products 列设置为 NULL

NULL 行发送到客户端时,将生成每个超级聚合行中 指示符。 服务器查看 GROUP BY 最左边的一个已更改值 子句中 指定的列 对于结果集中具有与任何名称匹配的名称的任何列,其值设置为 NULL (如果按列位置指定分组列,则服务器会 NULL 按位置 标识要设置的列 。)

由于 NULL 超级聚合行中 值在查询处理的后期阶段放入结果集中,因此 NULL 只能在选择列表或 HAVING 子句 中将 它们作为 进行测试 您无法 NULL 在连接条件或 WHERE 子句 中将 它们作为 值进行 测试, 以确定要选择的行。 例如,您无法添加 WHERE product IS NULL 查询以从输出中消除除超级聚合行之外的所有行。

这些 NULL 值确实显示 NULL 在客户端,可以使用任何MySQL客户端编程接口进行测试。 但是,此时,您无法区分a NULL 表示常规分组值还是超级聚合值。 要测试区别,请使用 GROUPING() 稍后描述 函数。

以前,MySQL不允许使用 DISTINCT ORDER BY 在具有 WITH ROLLUP 选项 的查询中使用 在MySQL 8.0.12及更高版本中解除了此限制。 (Bug#87450,Bug#86311,Bug#26640100,Bug#26073513)

对于 GROUP BY ... WITH ROLLUP 查询,要测试 NULL 结果中的值 是否 表示超级聚合值,该 GROUPING() 函数可用于选择列表, HAVING 子句和(从MySQL 8.0.12开始) ORDER BY 子句。 例如, 列中发生超级聚合行时 GROUPING(year) 返回1 ,否则 返回 0。 同样, 分别 列中 为超级聚合 返回1 NULL year GROUPING(country) GROUPING(product) NULL country product

MySQL的> SELECT
         year, country, product, SUM(profit) AS profit,
         GROUPING(year) AS grp_year,
         GROUPING(country) AS grp_country,
         GROUPING(product) AS grp_product
       FROM sales
       GROUP BY year, country, product WITH ROLLUP;
+ ------ + --------- + ------------ + -------- + ---------- + ------------- ------------- + +
| 一年| 国家| 产品| 利润| grp_year | grp_country | grp_product |
+ ------ + --------- + ------------ + -------- + ---------- + ------------- ------------- + +
| 2000年| 芬兰| 电脑| 1500 | 0 | 0 | 0 |
| 2000年| 芬兰| 电话| 100 | 0 | 0 | 0 |
| 2000年| 芬兰| NULL | 1600 | 0 | 0 | 1 |
| 2000年| 印度| 计算器| 150 | 0 | 0 | 0 |
| 2000年| 印度| 电脑| 1200 | 0 | 0 | 0 |
| 2000年| 印度| NULL | 1350 | 0 | 0 | 1 |
| 2000年| 美国| 计算器| 75 | 0 | 0 | 0 |
| 2000年| 美国| 电脑| 1500 | 0 | 0 | 0 |
| 2000年| 美国| NULL | 1575 | 0 | 0 | 1 |
| 2000年| NULL | NULL | 4525 | 0 | 1 | 1 |
| 2001 | 芬兰| 电话| 10 | 0 | 0 | 0 |
| 2001 | 芬兰| NULL | 10 | 0 | 0 | 1 |
| 2001 | 美国| 计算器| 50 | 0 | 0 | 0 |
| 2001 | 美国| 电脑| 2700 | 0 | 0 | 0 |
| 2001 | 美国| 电视| 250 | 0 | 0 | 0 |
| 2001 | 美国| NULL | 3000 | 0 | 0 | 1 |
| 2001 | NULL | NULL | 3010 | 0 | 1 | 1 |
| NULL | NULL | NULL | 7535 | 1 | 1 | 1 |
+ ------ + --------- + ------------ + -------- + ---------- + ------------- ------------- + +

GROUPING() 您可以使用 GROUPING() 替换标签来获取超级聚合 NULL 而不是 直接 显示 结果

MySQL的> SELECT
         IF(GROUPING(year), 'All years', year) AS year,
         IF(GROUPING(country), 'All countries', country) AS country,
         IF(GROUPING(product), 'All products', product) AS product,
         SUM(profit) AS profit
       FROM sales
       GROUP BY year, country, product WITH ROLLUP;
+ ----------- + -------- + -------------- + ------ -  +
| 一年| 国家| 产品| 利润|
+ ----------- + -------- + -------------- + ------ -  +
| 2000年| 芬兰| 电脑| 1500 |
| 2000年| 芬兰| 电话| 100 |
| 2000年| 芬兰| 所有产品| 1600 |
| 2000年| 印度| 计算器| 150 |
| 2000年| 印度| 电脑| 1200 |
| 2000年| 印度| 所有产品| 1350 |
| 2000年| 美国| 计算器| 75 |
| 2000年| 美国| 电脑| 1500 |
| 2000年| 美国| 所有产品| 1575 |
| 2000年| 所有国家| 所有产品| 4525 |
| 2001 | 芬兰| 电话| 10 |
| 2001 | 芬兰| 所有产品| 10 |
| 2001 | 美国| 计算器| 50 |
| 2001 | 美国| 电脑| 2700 |
| 2001 | 美国| 电视| 250 |
| 2001 | 美国| 所有产品| 3000 |
| 2001 | 所有国家| 所有产品| 3010 |
| 所有年份| 所有国家| 所有产品| 7535 |
+ ----------- + -------- + -------------- + ------ -  +

使用多个表达式参数, GROUPING() 返回表示位掩码的结果,组合每个表达式的结果,最低位对应于最右侧表达式的结果。 例如, GROUPING(year, country, product) 评估如下:

  GROUPING(product)的结果
+结果为GROUPING(country)<< 1
+结果为GROUPING(year)<< 2

GROUPING() 如果任何表达式表示超级聚合 NULL 此类结果 为非零 ,因此您只能返回超级聚合行并过滤掉常规分组行,如下所示:

MySQL的> SELECT year, country, product, SUM(profit) AS profit
       FROM sales
       GROUP BY year, country, product WITH ROLLUP
       HAVING GROUPING(year, country, product) <> 0;
+ ------ + --------- + --------- + -------- +
| 一年| 国家| 产品| 利润|
+ ------ + --------- + --------- + -------- +
| 2000年| 芬兰| NULL | 1600 |
| 2000年| 印度| NULL | 1350 |
| 2000年| 美国| NULL | 1575 |
| 2000年| NULL | NULL | 4525 |
| 2001 | 芬兰| NULL | 10 |
| 2001 | 美国| NULL | 3000 |
| 2001 | NULL | NULL | 3010 |
| NULL | NULL | NULL | 7535 |
+ ------ + --------- + --------- + -------- +

sales 表不包含任何 NULL 值,因此 结果中的 所有 NULL ROLLUP 表示超级聚合值。 当数据集包含 NULL 值时, ROLLUP 摘要 NULL 不仅 可以包含 超聚合行 中的 值, 还可以包含 常规分组行中的值。 GROUPING() 使这些可以区分。 假设该表 t1 包含一个简单的数据集,其中包含一组数量值的两个分组因子,其中 NULL 表示类似 其他 未知 ”的内容

MySQL的> SELECT * FROM t1;
+ ------ + ------- + ---------- +
| 名字| 尺寸| 数量|
+ ------ + ------- + ---------- +
| 球| 小| 10 |
| 球| 大| 20 |
| 球| NULL | 5 |
| 箍| 小| 15 |
| 箍| 大| 5 |
| 箍| NULL | 3 |
+ ------ + ------- + ---------- +

一个简单的 ROLLUP 操作会产生这些结果,在这些结果中,将 NULL 超级聚合行中的 NULL 值与常规分组行中的值 区分开来并不容易

MySQL的> SELECT name, size, SUM(quantity) AS quantity
       FROM t1
       GROUP BY name, size WITH ROLLUP;
+ ------ + ------- + ---------- +
| 名字| 尺寸| 数量|
+ ------ + ------- + ---------- +
| 球| NULL | 5 |
| 球| 大| 20 |
| 球| 小| 10 |
| 球| NULL | 35 |
| 箍| NULL | 3 |
| 箍| 大| 5 |
| 箍| 小| 15 |
| 箍| NULL | 23 |
| NULL | NULL | 58 |
+ ------ + ------- + ---------- +

使用 GROUPING() 替代标签的超总量 NULL 值,使得结果更容易解释:

MySQL的> SELECT
         IF(GROUPING(name) = 1, 'All items', name) AS name,
         IF(GROUPING(size) = 1, 'All sizes', size) AS size,
         SUM(quantity) AS quantity
       FROM t1
       GROUP BY name, size WITH ROLLUP;
+ ----------- ----------- + ---------- + +
| 名字| 尺寸| 数量|
+ ----------- ----------- + ---------- + +
| 球| NULL | 5 |
| 球| 大| 20 |
| 球| 小| 10 |
| 球| 所有尺寸| 35 |
| 箍| NULL | 3 |
| 箍| 大| 5 |
| 箍| 小| 15 |
| 箍| 所有尺寸| 23 |
| 所有项目| 所有尺寸| 58 |
+ ----------- ----------- + ---------- + +

其他注意事项使用ROLLUP时

以下讨论列出了一些特定于MySQL实现的行为 ROLLUP

在MySQL 8.0.12之前,当您使用时 ROLLUP ,您也不能使用 ORDER BY 子句对结果进行排序。 换句话说, ROLLUP 并且 ORDER BY 在MySQL中是互斥的。 但是,您仍然可以控制排序顺序。 若要解决阻止使用限制 ROLLUP 使用 ORDER BY ,实现分组结果的具体排序顺序,生成分组结果集派生表,并应用 ORDER BY 它。 例如:

MySQL的> SELECT * FROM
         (SELECT year, SUM(profit) AS profit
         FROM sales GROUP BY year WITH ROLLUP) AS dt
       ORDER BY year DESC;
+ ------ + -------- +
| 一年| 利润|
+ ------ + -------- +
| 2001 | 3010 |
| 2000年| 4525 |
| NULL | 7535 |
+ ------ + -------- +

从MySQL 8.0.12的, ORDER BY 并且 ROLLUP 可以一起使用,这使得能够使用 ORDER BY GROUPING() 实现分组结果的具体排序顺序。 例如:

MySQL的> SELECT year, SUM(profit) AS profit
       FROM sales
       GROUP BY year WITH ROLLUP
       ORDER BY GROUPING(year) DESC;
+ ------ + -------- +
| 一年| 利润|
+ ------ + -------- +
| NULL | 7535 |
| 2000年| 4525 |
| 2001 | 3010 |
+ ------ + -------- +

在这两种情况下,超级聚合摘要行都按计算它们的行进行排序,它们的位置取决于排序顺序(在升序排序的末尾,在降序排序的开头)。

LIMIT 可用于限制返回给客户端的行数。 LIMIT 在之后应用 ROLLUP ,因此该限制适用于添加的额外行 ROLLUP 例如:

MySQL的> SELECT year, country, product, SUM(profit) AS profit
       FROM sales
       GROUP BY year, country, product WITH ROLLUP
       LIMIT 5;
+ ------ + --------- + ------------ + -------- +
| 一年| 国家| 产品| 利润|
+ ------ + --------- + ------------ + -------- +
| 2000年| 芬兰| 电脑| 1500 |
| 2000年| 芬兰| 电话| 100 |
| 2000年| 芬兰| NULL | 1600 |
| 2000年| 印度| 计算器| 150 |
| 2000年| 印度| 电脑| 1200 |
+ ------ + --------- + ------------ + -------- +

使用 LIMIT with ROLLUP 可能会产生更难以解释的结果,因为用于理解超级聚合行的上下文较少。

MySQL扩展允许 GROUP BY 列表 中未出现的 列在选择列表中命名。 (有关非 聚合 列的信息 GROUP BY ,请参见 第12.20.3节“GROUP BY的MySQL处理” 。)在这种情况下,服务器可以自由选择摘要行中此非聚合列的任何值,这包括添加的额外行通过 WITH ROLLUP 例如,在以下查询中, country 是一个未出现在 GROUP BY 列表中的非 聚合列,并且 为此列选择的值是不确定的:

MySQL的> SELECT year, country, SUM(profit) AS profit
       FROM sales
       GROUP BY year WITH ROLLUP;
+ ------ + --------- + -------- +
| 一年| 国家| 利润|
+ ------ + --------- + -------- +
| 2000年| 印度| 4525 |
| 2001 | 美国| 3010 |
| NULL | 美国| 7535 |
+ ------ + --------- + -------- +

ONLY_FULL_GROUP_BY 未启用SQL模式 时,允许此行为 如果启用了该模式,则服务器会将查询拒绝为非法,因为 country GROUP BY 子句中 未列出 该查询 ONLY_FULL_GROUP_BY 启用,您仍然可以通过执行查询 ANY_VALUE() 非确定性值列功能:

MySQL的> SELECT year, ANY_VALUE(country) AS country, SUM(profit) AS profit
       FROM sales
       GROUP BY year WITH ROLLUP;
+ ------ + --------- + -------- +
| 一年| 国家| 利润|
+ ------ + --------- + -------- +
| 2000年| 印度| 4525 |
| 2001 | 美国| 3010 |
| NULL | 美国| 7535 |
+ ------ + --------- + -------- +

12.20.3 GROUP BY的MySQL处理

SQL-92和更早版本不允许选择列表, HAVING 条件或 ORDER BY 列表引用未在 GROUP BY 子句中 命名的非聚合列的查询 例如,此查询在标准SQL-92中是非法的,因为 name 选择列表中的非 聚合 列不会出现在 GROUP BY

SELECT o.custid,c.name,MAX(o.payment)
  来自订单AS o,客户AS c
  在哪里o.custid = c.custid
  GROUP BY o.custid;

要使查询在SQL-92中合法, name 必须从选择列表中省略该列,或在该 GROUP BY 子句中 对该 列进行命名

SQL:1999及更高版本允许每个可选功能T301的非聚合,如果它们在功能上依赖于 GROUP BY 列:如果 name 之间存在这样的关系 custid ,则查询是合法的。 例如,这是 custid 一个主要的关键 customers

MySQL实现了对功能依赖的检测。 如果 ONLY_FULL_GROUP_BY 启用 SQL模式(默认情况下是这样),则MySQL拒绝查询,其中选择列表, HAVING 条件或 ORDER BY 列表引用非聚合列,这些列既不在 GROUP BY 子句中 命名 也不在功能上依赖于它们。

如果 ONLY_FULL_GROUP_BY 禁用,则标准SQL使用的MySQL扩展 GROUP BY 允许选择列表, HAVING 条件或 ORDER BY 列表引用非聚合列,即使列在功能上不依赖于 GROUP BY 列。 这导致MySQL接受前面的查询。 在这种情况下,服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的,这可能不是您想要的。 此外,添加一个 ORDER BY 条款 不会影响每个组的值的选择 结果集排序在选择值后发生,并且 ORDER BY 不会影响服务器选择的每个组中的哪个值。 ONLY_FULL_GROUP_BY 当您知道由于数据的某些属性时,每个未分配的每个非聚合列中的所有值 GROUP BY 对于每个组都是相同的 ,因此 禁用 非常有用

您可以 ONLY_FULL_GROUP_BY 通过使用 ANY_VALUE() 引用非聚合列 来实现相同的效果而不禁用

以下讨论演示了函数依赖性,MySQL在缺少函数依赖时产生的错误消息,以及在没有函数依赖性的情况下使MySQL接受查询的方法。

ONLY_FULL_GROUP_BY 启用 此查询可能无效, 因为 address 选项列表中的非 聚合 列未在 GROUP BY 子句中 命名

SELECT名称,地址,MAX(年龄)FROM t GROUP BY名称;

如果查询是 name 主键 t 或是唯一 NOT NULL 列, 则查询有效 在这种情况下,MySQL会识别所选列在功能上依赖于分组列。 例如,如果 name 是主键,则其值确定值, address 因为每个组只有一个主键值,因此只有一行。 因此, address 的选择没有随机性 ,也不需要拒绝查询。

如果查询 name 不是主键 t 或唯一 NOT NULL 列, 则查询无效 在这种情况下,不能推断出功能依赖性并发生错误:


MySQL的> SELECT name, address, MAX(age) FROM t GROUP BY name;
错误1055(42000):SELECT列表的表达式#2不在GROUP中
BY子句并包含非聚合列'mydb.t.address'
在功能上不依赖于GROUP BY子句中的列; 这个
与sql_mode = only_full_group_by不兼容

如果您知道, 对于给定的数据集, 每个 name 值实际上唯一地确定该 address 值, address 在功能上是有效依赖的 name 要告诉MySQL接受查询,可以使用以下 ANY_VALUE() 函数:

SELECT名称,ANY_VALUE(地址),MAX(年龄)FROM t GROUP BY名称;

或者,禁用 ONLY_FULL_GROUP_BY

然而,前面的例子非常简单。 特别是,您不太可能在单个主键列上进行分组,因为每个组只包含一行。 有关在更复杂查询中显示函数依赖性的 附加 示例,请参见 第12.20.4节“函数依赖性检测”

如果查询具有聚合函数且没有 GROUP BY 子句,则在 启用 的选择列表, HAVING 条件或 ORDER BY 列表中 不能包含 非聚合 ONLY_FULL_GROUP_BY


MySQL的> SELECT name, MAX(age) FROM t;
错误1140(42000):在没有GROUP BY,表达式的聚合查询中
SELECT列表的#1包含非聚合列'mydb.t.name'; 这个
与sql_mode = only_full_group_by不兼容

没有 GROUP BY ,只有一个组,它是不确定的, name 为组选择值。 ANY_VALUE() 如果 name MySQL选择的值 不重要 也可以使用 这里

SELECT ANY_VALUE(name),MAX(age)FROM t;

ONLY_FULL_GROUP_BY 也会影响使用 DISTINCT 查询的处理 ORDER BY 考虑表的情况下, t 有三列 c1 c2 以及 c3 包含这些行:

c1 c2 c3
1 2 A.
3 4 B.
1 2 C.

假设我们执行以下查询,期望按以下顺序排序结果 c3

SELECT DISTINCT c1,c2 FROM t ORDER BY c3;

要订购结果,必须首先删除重复项。 但要这样做,我们应该保留第一行还是第三行? 这种任意选择会影响保留值 c3 ,从而影响排序并使其任意。 要防止出现此问题, 如果任何 表达式不满足以下条件中的至少一个条件 ,则该查询具有 DISTINCT ORDER BY 被拒绝为无效 ORDER BY

  • 表达式在选择列表中等于1

  • 表达式引用并属于查询所选表的所有列都是选择列表的元素

标准SQL的另一个MySQL扩展允许 HAVING 子句中的 引用 到选择列表中的别名表达式。 例如,以下查询返回 name 在表中只出现一次的值 orders

SELECT名称,COUNT(名称)FROM订单
  GROUP BY名称
  有COUNT(名字)= 1;

MySQL扩展允许 HAVING 在聚合列 子句中 使用别名

SELECT name,COUNT(name)AS c FROM orders
  GROUP BY名称
  有c = 1;

标准SQL只允许 GROUP BY 子句中的 列表达式 ,因此这样的语句无效,因为它 FLOOR(value/100) 是一个非列表达式:

SELECT id,FLOOR(value / 100)tbl_name
  GROUP BY id,FLOOR(value / 100);

MySQL扩展标准SQL以允许 GROUP BY 子句中的非 列表达式, 并认为前面的语句有效。

标准SQL也不允许 GROUP BY 子句中的 别名 MySQL扩展标准SQL以允许别名,因此编写查询的另一种方法如下:

SELECT id,FLOOR(value / 100)AS valtbl_name
  GROUP BY id,val;

别名 val GROUP BY 子句中 被视为列表达式

GROUP BY 子句中 存在非列表达式的情况下 ,MySQL会识别该表达式与选择列表中的表达式之间的相等性。 这意味着在 ONLY_FULL_GROUP_BY 启用S​​QL模式的情况下,包含的查询 GROUP BY id, FLOOR(value/100) 是有效的,因为 FLOOR() 在选择列表中会出现 相同的 表达式。 但是,MySQL不会尝试识别对非 GROUP BY 列表达式的 函数依赖性 ,因此以下查询在 ONLY_FULL_GROUP_BY 启用时 无效 ,即使第三个选定表达式是 id 的简单公式 子句中 FLOOR() 表达式 GROUP BY

SELECT id,FLOOR(value / 100),id + FLOOR(value / 100)tbl_name
  GROUP BY id,FLOOR(value / 100);

解决方法是使用派生表:

SELECT id,F,id + F.
    (SELECT id,FLOOR(value / 100)AS F.tbl_name
     GROUP BY id,FLOOR(value / 100))AS dt;

12.20.4功能依赖性的检测

以下讨论提供了MySQL检测功能依赖性的方式的几个示例。 示例使用此表示法:

{ X}  - > { Y}

理解这一点如 X 唯一地确定 Y 这也意味着, Y 在功能上依赖于 X

这些示例使用 world 数据库,可以从 https://dev.mysql.com/doc/index-other.html 下载 您可以在同一页面上找到有关如何安装数据库的详细信息。

从Keys派生的功能依赖

以下查询为每个国家/地区选择口语数量:

SELECT co.Name,COUNT(*)
来自countrylanguage cl,country co
在哪里cl.CountryCode = co.Code
GROUP BY co.Code;

co.Code 是一个主键 co ,因此所有列 co 都在功能上依赖于它,如使用此表示法表示的:

{co.Code}  - > {co。*}

因此, co.name 在功能上依赖于 GROUP BY 列并且查询是有效的。

可以使用列上 UNIQUE 索引 NOT NULL 而不是主键,并且将应用相同的功能依赖性。 (对于 UNIQUE 允许 NULL 索引,情况 并非如此, 因为它允许多个 NULL 值,在这种情况下,唯一性会丢失。)

源自多列密钥和来自等式的功能依赖性

此查询为每个国家/地区选择所有口语的列表以及有多少人说话:

SELECT co.Name,cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
来自countrylanguage cl,country co
在哪里cl.CountryCode = co.Code
GROUP BY cl.CountryCode,cl.Language;

对( cl.CountryCode cl.Language )是两列复合主键 cl ,因此列对唯一地确定所有列 cl

{cl.CountryCode,cl.Language}  - > {cl。*}

而且,由于 WHERE 条款 中的平等

{cl.CountryCode}  - > {co.Code}

并且,因为 co.Code 是主要关键 co

{co.Code}  - > {co。*}

唯一确定 关系是可传递的,因此:

{cl.CountryCode,cl.Language}  - > {cl。*,co。*}

因此,查询有效。

与前面的示例一样, 可以使用列上 UNIQUE NOT NULL 而不是主键。

INNER JOIN 条件可以被用来代替 WHERE 相同的功能依赖性适用:

SELECT co.Name,cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
来自countrylanguage cl INNER JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode,cl.Language;

功能依赖特殊案例

虽然 WHERE 条件或 INNER JOIN 条件中的相等性测试是对称的,但外部连接条件中的相等性测试不是,因为表扮演不同的角色。

假设参照完整性被意外破坏,并且存在一行 countrylanguage 没有相应的行 country 考虑与前一个示例中相同的查询,但使用 LEFT JOIN

SELECT co.Name,cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
来自countrylanguage cl LEFT JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode,cl.Language;

对于给定值 cl.CountryCode co.Code 连接结果中的值可以在匹配的行中找到(由...确定 cl.CountryCode ),或者 NULL 如果没有匹配 则也是 - 如果没有匹配(也由...确定 cl.CountryCode )。 在每种情况下,这种关系适用:

{cl.CountryCode}  - > {co.Code}

cl.CountryCode 它本身在功能上依赖于{ cl.CountryCode cl.Language }这是一个主键。

如果在连接结果中 co.Code NULL -complemented, co.Name 那么也是如此。 如果 co.Code 不是 NULL -complemented,那么因为它 co.Code 是一个主键,它确定 co.Name 因此,在所有情况下:

{co.Code}  - > {co.Name}

产量:

{cl.CountryCode,cl.Language}  - > {cl。*,co。*}

因此,查询有效。

但是,假设表已交换,如此查询中所示:

SELECT co.Name,cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
来自country co LEFT JOIN countrylanguage cl
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode,cl.Language;

现在,这种关系并 不能 适用:

{cl.CountryCode,cl.Language}  - > {cl。*,co。*}

实际上,所有已 NULL 完成的 cl 行将被放入一个组(它们的 GROUP BY 列都等于 NULL ),并且在这个组中,值 co.Name 可以变化。 查询无效,MySQL拒绝它。

因此,外连接中的功能依赖性与行列式列是属于左侧还是右侧有关 LEFT JOIN 如果存在嵌套外连接或连接条件不完全由相等比较组成,则函数依赖性的确定变得更加复杂。

功能依赖和视图

假设一个国家的观点产生他们的代码,他们的名字是大写的,他们有多少种不同的官方语言:

创建视图Country2 AS
SELECT co.Code,UPPER(co.Name)AS UpperName,
COUNT(cl.Language)AS OfficialLanguages
来自国家AS co JOIN countrylanguage AS cl
ON cl.CountryCode = co.Code
在哪里cl.isOfficial ='T'
GROUP BY co.Code;

此定义有效,因为:

{co.Code}  - > {co。*}

在视图结果中,第一个选定的列是 co.Code ,也是组列,因此确定所有其他选定的表达式:

{Country2.Code}  - > {Country2。*}

MySQL理解这一点并使用这些信息,如下所述。

此查询通过将视图加入 city 表格来 显示国家/地区,他们拥有多少种不同的官方语言以及他们拥有的城市数量

SELECT co2.Code,co2.UpperName,co2.OfficialLanguages,
COUNT(*)AS城市
来自country2 AS co2 JOIN city ci
ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

此查询有效,因为如前所示:

{co2.Code}  - > {co2。*}

MySQL能够在视图的结果中发现功能依赖,并使用它来验证使用该视图的查询。 如果 country2 是派生表(或公用表表达式),情况也是如此,如:

SELECT co2.Code,co2.UpperName,co2.OfficialLanguages,
COUNT(*)AS城市
 SELECT co.Code,UPPER(co.Name)AS UpperName,
 COUNT(cl.Language)AS OfficialLanguages
 来自国家AS co JOIN countrylanguage AS cl
 ON cl.CountryCode = co.Code
 在哪里cl.isOfficial ='T'
 GROUP BY co.Code
)AS co2
JOIN city ci ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

功能依赖的组合

MySQL能够结合所有前面类型的功能依赖(基于密钥,基于相等,基于视图)来验证更复杂的查询。

12.21窗口函数

MySQL支持窗口函数,对于查询中的每一行,它使用与该行相关的行执行计算。 以下部分讨论如何使用窗口函数,包括 OVER WINDOW 子句的 描述 第一部分提供非聚合窗口函数的描述。 有关聚合窗口函数的描述,请参见 第12.20.1节“聚合(GROUP BY)函数描述”

有关优化和窗口函数的信息,请参见 第8.2.1.20节“窗口函数优化”

12.21.1窗口功能描述

本节介绍非聚合窗口函数,对于查询中的每一行,它使用与该行相关的行执行计算。 大多数聚合函数也可以用作窗口函数; 请参见 第12.20.1节“聚合(GROUP BY)功能描述”

有关窗口函数用法信息和示例,以及术语(如 OVER 子句,窗口,分区,框架和对等项)的定义,请参见 第12.21.2节“窗口函数概念和语法”

表12.27窗口函数

名称 描述
CUME_DIST() 累积分配值
DENSE_RANK() 其分区内当前行的排名,没有间隙
FIRST_VALUE() 窗口框架第一行的参数值
LAG() 行中滞后当前行的参数值
LAST_VALUE() 窗口框架最后一行的参数值
LEAD() 分区中行前导行的参数值
NTH_VALUE() 第N行窗口框架的参数值
NTILE() 其分区中当前行的存储桶编号。
PERCENT_RANK() 百分比等级值
RANK() 其分区内当前行的排名,有差距
ROW_NUMBER() 其分区中当前行的数量

在以下函数描述中, over_clause 表示 第12.21.2节“窗口函数概念和语法”中 OVER 描述 子句 某些窗口函数允许一个 子句,指定 在计算结果时 如何处理 值。 该子句是可选的。 它是SQL标准的一部分,但MySQL实现仅允许 (这也是默认值)。 这意味着 在计算结果时会考虑值。 被解析,但产生错误。 null_treatment NULL RESPECT NULLS NULL IGNORE NULLS

  • CUME_DIST() over_clause

    返回一组值中的值的累积分布; 也就是说,分区值的百分比小于或等于当前行中的值。 这表示窗口分区的窗口顺序中当前行之前或与之对应的行数除以窗口分区中的总行数。 返回值的范围是0到1。

    应该使用此函数将 ORDER BY 分区行排序为所需的顺序。 如果没有 ORDER BY ,则所有行都是对等的并且值为 N / N = 1,其中 N 是分区大小。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述

    以下查询针对 val 列中的 CUME_DIST() 值集显示每行 值,以及类似 PERCENT_RANK() 函数 返回的百分比等级值 作为参考,查询还使用 ROW_NUMBER() 以下方式 显示行号

    MySQL的> SELECT
             val,
             ROW_NUMBER()   OVER w AS 'row_number',
             CUME_DIST()    OVER w AS 'cume_dist',
             PERCENT_RANK() OVER w AS 'percent_rank'
           FROM numbers
           WINDOW w AS (ORDER BY val);
    + ------ + ------------ + -------------------- + -------- ------ +
    | val | row_number | cume_dist | percent_rank |
    + ------ + ------------ + -------------------- + -------- ------ +
    | 1 | 1 | 0.2222222222222222 | 0 |
    | 1 | 2 | 0.2222222222222222 | 0 |
    | 2 | 3 | 0.3333333333333333 | 0.25 |
    | 3 | 4 | 0.6666666666666666 | 0.375 |
    | 3 | 5 | 0.6666666666666666 | 0.375 |
    | 3 | 6 | 0.6666666666666666 | 0.375 |
    | 4 | 7 | 0.8888888888888888 | 0.75 |
    | 4 | 8 | 0.8888888888888888 | 0.75 |
    | 5 | 9 | 1 | 1 |
    + ------ + ------------ + -------------------- + -------- ------ +
    
  • DENSE_RANK() over_clause

    返回其分区中当前行的排名,没有间隙。 同行被视为关系,并获得相同的排名。 此功能将连续的等级分配给对等组; 结果是,大于1的组不会产生不连续的等级数。 有关示例,请参阅 RANK() 功能说明。

    应该使用此函数将 ORDER BY 分区行排序为所需的顺序。 没有 ORDER BY ,所有行都是对等的。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述

  • FIRST_VALUE(expr) [ null_treatment ] over_clause

    返回 expr 窗口框架第一行 的值

    over_clause 第12.21.2节“窗口函数概念和语法”中所述 null_treatment 如引言部分所述。

    下面的查询演示 FIRST_VALUE() LAST_VALUE() 以及两个实例 NTH_VALUE()

    MySQL的> SELECT
             time, subject, val,
             FIRST_VALUE(val)  OVER w AS 'first',
             LAST_VALUE(val)   OVER w AS 'last',
             NTH_VALUE(val, 2) OVER w AS 'second',
             NTH_VALUE(val, 4) OVER w AS 'fourth'
           FROM observations
           WINDOW w AS (PARTITION BY subject ORDER BY time
                        ROWS UNBOUNDED PRECEDING);
    + ---------- + --------- + ------ + ------- + ------ + ------ -  + -------- +
    | 时间| 主题| val | 第一个| 最后| 第二个| 第四|
    + ---------- + --------- + ------ + ------- + ------ + ------ -  + -------- +
    | 07:00:00 | st113 | 10 | 10 | 10 | NULL | NULL |
    | 07:15:00 | st113 | 9 | 10 | 9 | 9 | NULL |
    | 07:30:00 | st113 | 25 | 10 | 25 | 9 | NULL |
    | 07:45:00 | st113 | 20 | 10 | 20 | 9 | 20 |
    | 07:00:00 | xh458 | 0 | 0 | 0 | NULL | NULL |
    | 07:15:00 | xh458 | 10 | 0 | 10 | 10 | NULL |
    | 07:30:00 | xh458 | 5 | 0 | 5 | 10 | NULL |
    | 07:45:00 | xh458 | 30 | 0 | 30 | 10 | 30 |
    | 08:00:00 | xh458 | 25 | 0 | 25 | 10 | 30 |
    + ---------- + --------- + ------ + ------- + ------ + ------ -  + -------- +
    

    每个函数使用当前帧中的行,根据所示的窗口定义,这些行从第一个分区行延伸到当前行。 对于 NTH_VALUE() 调用,当前帧并不总是包括所请求的行; 在这种情况下,返回值是 NULL

  • LAG(expr [, N[, default]]) [ null_treatment ] over_clause

    返回 expr 当前行滞后(先于) N 其分区内的 行的 行的值。 如果没有这样的行,则返回值为 default 例如,如果 N 为3,则返回值为 default 前两行。 如果 N default 缺少,则默认值分别为1和1 NULL

    N 必须是文字非负整数。 如果 N 为0, expr 则评估当前行。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述 null_treatment 如引言部分所述。

    LAG() (和类似的 LEAD() 功能)通常用于计算行之间的差异。 以下查询显示了一组按时间顺序排列的观察值,并且对于每个观察 值,显示了相邻行的值 LAG() LEAD() 值,以及当前行和相邻行之间的差异:

    MySQL的> SELECT
             t, val,
             LAG(val)        OVER w AS 'lag',
             LEAD(val)       OVER w AS 'lead',
             val - LAG(val)  OVER w AS 'lag diff',
             val - LEAD(val) OVER w AS 'lead diff'
           FROM series
           WINDOW w AS (ORDER BY t);
    + ---------- + ------ + ------ + ------ + ---------- + ------ ----- +
    | t | val | 滞后| 铅| 滞后差异| lead diff |
    + ---------- + ------ + ------ + ------ + ---------- + ------ ----- +
    | 12:00:00 | 100 | NULL | 125 | NULL | -25 |
    | 13:00:00 | 125 | 100 | 132 | 25 | -7 |
    | 14:00:00 | 132 | 125 | 145 | 7 | -13 |
    | 15:00:00 | 145 | 132 | 140 | 13 | 5 |
    | 16:00:00 | 140 | 145 | 150 | -5 | -10 |
    | 17:00:00 | 150 | 140 | 200 | 10 | -50 |
    | 18:00:00 | 200 | 150 | NULL | 50 | NULL |
    + ---------- + ------ + ------ + ------ + ---------- + ------ ----- +
    

    在示例中, LAG() LEAD() 调用分别使用默认值 N default 值1和 NULL

    第一行显示当没有前一行时发生的情况 LAG() :函数返回 default 值(在本例中为 NULL )。 当没有下一行时,最后一行显示相同的内容 LEAD()

    LAG() 并且 LEAD() 还用于计算总和而不是差异。 考虑这个数据集,其中包含Fibonacci系列的前几个数字:

    MySQL的> SELECT n FROM fib ORDER BY n;
    + ------ +
    | n |
    + ------ +
    | 1 |
    | 1 |
    | 2 |
    | 3 |
    | 5 |
    | 8 |
    + ------ +
    

    以下查询显示 LAG() LEAD() 当前行相邻的行 值。 它还使用这些函数将前一行和后一行中的值添加到当前行值。 效果是在Fibonacci系列中生成下一个数字,然后是下一个数字:

    MySQL的> SELECT
             n,
             LAG(n, 1, 0)      OVER w AS 'lag',
             LEAD(n, 1, 0)     OVER w AS 'lead',
             n + LAG(n, 1, 0)  OVER w AS 'next_n',
             n + LEAD(n, 1, 0) OVER w AS 'next_next_n'
           FROM fib
           WINDOW w AS (ORDER BY n);
    + ------ + ------ + ------ + -------- + ------------- +
    | n | 滞后| 铅| next_n | next_next_n |
    + ------ + ------ + ------ + -------- + ------------- +
    | 1 | 0 | 1 | 1 | 2 |
    | 1 | 1 | 2 | 2 | 3 |
    | 2 | 1 | 3 | 3 | 5 |
    | 3 | 2 | 5 | 5 | 8 |
    | 5 | 3 | 8 | 8 | 13 |
    | 8 | 5 | 0 | 13 | 8 |
    + ------ + ------ + ------ + -------- + ------------- +
    

    生成初始Fibonacci数集的一种方法是使用递归公用表表达式。 有关示例,请参阅 Fibonacci Series Generation

  • LAST_VALUE(expr) [ null_treatment ] over_clause

    返回 expr 窗口框架最后一行 的值

    over_clause 第12.21.2节“窗口函数概念和语法”中所述 null_treatment 如引言部分所述。

    有关示例,请参阅 FIRST_VALUE() 功能说明。

  • LEAD(expr [, N[, default]]) [ null_treatment ] over_clause

    返回 从其分区中 expr 的行引导(跟随)当前行的 N 行的值。 如果没有这样的行,则返回值为 default 例如,如果 N 为3,则返回值为 default 最后两行。 如果 N default 缺少,则默认值分别为1和1 NULL

    N 必须是文字非负整数。 如果 N 为0, expr 则评估当前行。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述 null_treatment 如引言部分所述。

    有关示例,请参阅 LAG() 功能说明。

  • NTH_VALUE(expr, N) [ from_first_last ] [ null_treatment ] over_clause

    返回 窗口框架 expr N 第-th行 的值 如果没有这样的行,则返回值为 NULL

    N 必须是字面正整数。

    from_first_last 是SQL标准的一部分,但MySQL实现仅允许 FROM FIRST (这也是默认值)。 这意味着计算从窗口的第一行开始。 FROM LAST 被解析,但产生错误。 要获得与 FROM LAST (在窗口的最后一行开始计算) 相同的效果 ,请使用 ORDER BY 相反的顺序排序。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述 null_treatment 如引言部分所述。

    有关示例,请参阅 FIRST_VALUE() 功能说明。

  • NTILE(N) over_clause

    将分区划分为 N 组(存储桶),为分区中的每一行分配其存储桶编号,并返回其分区中当前行的存储区编号。 例如,如果 N 为4, NTILE() 则将行分为四个桶。 如果 N 为100, NTILE() 则将行划分为100个桶。

    N 必须是字面正整数。 存储桶编号返回值的范围为1到 N

    应该使用此函数将 ORDER BY 分区行排序为所需的顺序。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述

    以下查询针对 val 列中 的值集显示 通过将行划分为两个或四个组而产生的百分位数值。 作为参考,查询还使用 ROW_NUMBER() 以下方式 显示行号

    MySQL的> SELECT
             val,
             ROW_NUMBER() OVER w AS 'row_number',
             NTILE(2)     OVER w AS 'ntile2',
             NTILE(4)     OVER w AS 'ntile4'
           FROM numbers
           WINDOW w AS (ORDER BY val);
    + ------ + ------------ + -------- + -------- +
    | val | row_number | ntile2 | ntile4 |
    + ------ + ------------ + -------- + -------- +
    | 1 | 1 | 1 | 1 |
    | 1 | 2 | 1 | 1 |
    | 2 | 3 | 1 | 1 |
    | 3 | 4 | 1 | 2 |
    | 3 | 5 | 1 | 2 |
    | 3 | 6 | 2 | 3 |
    | 4 | 7 | 2 | 3 |
    | 4 | 8 | 2 | 4 |
    | 5 | 9 | 2 | 4 |
    + ------ + ------------ + -------- + -------- +
    
  • PERCENT_RANK() over_clause

    返回小于当前行中值的分区值的百分比,不包括最高值。 返回值的范围从0到1,表示行的相对等级,计算为此公式的结果,其中 rank 是行等级, rows 是分区行的数量:

    rank-  1)/(rows-  1)
    

    应该使用此函数将 ORDER BY 分区行排序为所需的顺序。 没有 ORDER BY ,所有行都是对等的。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述

    有关示例,请参阅 CUME_DIST() 功能说明。

  • RANK() over_clause

    返回其分区中当前行的排名,带有间隙。 同行被视为关系,并获得相同的排名。 如果存在大于1的组,则此函数不会将连续的等级分配给对等组; 结果是不连续的排名数字。

    应该使用此函数将 ORDER BY 分区行排序为所需的顺序。 没有 ORDER BY ,所有行都是对等的。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述

    以下查询显示了它们之间的差异 RANK() ,它产生了具有间隙的排名,并且 DENSE_RANK() 产生了没有间隙的排名。 该查询显示 val 中一组值的每个成员的等级值 ,其中包含一些重复项。 RANK() 为对等体(重复)分配相同的等级值,并且下一个更大的值具有高于对等体的数量减去1的等级。 DENSE_RANK() 同时为对等体分配相同的等级值,但是下一个更高的值具有更高的等级1。 作为参考,查询还使用 ROW_NUMBER() 以下方式 显示行号

    MySQL的> SELECT
             val,
             ROW_NUMBER() OVER w AS 'row_number',
             RANK()       OVER w AS 'rank',
             DENSE_RANK() OVER w AS 'dense_rank'
           FROM numbers
           WINDOW w AS (ORDER BY val);
    + ------ + ------------ + ------ + ------------ +
    | val | row_number | 排名| dense_rank |
    + ------ + ------------ + ------ + ------------ +
    | 1 | 1 | 1 | 1 |
    | 1 | 2 | 1 | 1 |
    | 2 | 3 | 3 | 2 |
    | 3 | 4 | 4 | 3 |
    | 3 | 5 | 4 | 3 |
    | 3 | 6 | 4 | 3 |
    | 4 | 7 | 7 | 4 |
    | 4 | 8 | 7 | 4 |
    | 5 | 9 | 9 | 5 |
    + ------ + ------------ + ------ + ------------ +
    
  • ROW_NUMBER() over_clause

    返回其分区中当前行的编号。 行数从1到分区行数。

    ORDER BY 影响行的编号顺序。 没有 ORDER BY ,行编号是不确定的。

    ROW_NUMBER() 为同伴分配不同的行号。 要为对等体分配相同的值,请使用 RANK() DENSE_RANK() 有关示例,请参阅 RANK() 功能说明。

    over_clause 第12.21.2节“窗口函数概念和语法”中所述

12.21.2窗口函数概念和语法

本节介绍如何使用窗口函数。 示例使用与 第12.20.2节“GROUP BY Modifiers” 中的 GROUPING() 函数 讨论中相同的销售信息数据集

MySQL的> SELECT * FROM sales ORDER BY country, year, product;
+ ------ + --------- + ------------ + -------- +
| 一年| 国家| 产品| 利润|
+ ------ + --------- + ------------ + -------- +
| 2000年| 芬兰| 电脑| 1500 |
| 2000年| 芬兰| 电话| 100 |
| 2001 | 芬兰| 电话| 10 |
| 2000年| 印度| 计算器| 75 |
| 2000年| 印度| 计算器| 75 |
| 2000年| 印度| 电脑| 1200 |
| 2000年| 美国| 计算器| 75 |
| 2000年| 美国| 电脑| 1500 |
| 2001 | 美国| 计算器| 50 |
| 2001 | 美国| 电脑| 1500 |
| 2001 | 美国| 电脑| 1200 |
| 2001 | 美国| 电视| 150 |
| 2001 | 美国| 电视| 100 |
+ ------ + --------- + ------------ + -------- +

窗口函数对一组查询行执行类似聚合的操作。 但是,聚合操作将查询行分组到单个结果行中,而窗口函数会为每个查询行生成结果:

  • 发生功能评估的行称为当前行。

  • 与发生功能评估的当前行相关的查询行包括当前行的窗口。

例如,使用销售信息表,这两个查询执行聚合操作,为作为组的所有行生成单个全局总和,并按国家/地区分组的总和:

MySQL的> SELECT SUM(profit) AS total_profit
       FROM sales;
+ -------------- +
| total_profit |
+ -------------- +
| 7535 |
+ -------------- +
MySQL的> SELECT country, SUM(profit) AS country_profit
       FROM sales
       GROUP BY country
       ORDER BY country;
+ --------- + ---------------- +
| 国家| country_profit |
+ --------- + ---------------- +
| 芬兰| 1610 |
| 印度| 1350 |
| 美国| 4575 |
+ --------- + ---------------- +

相比之下,窗口操作不会将查询行组折叠到单个输出行。 相反,它们为每一行产生一个结果。 与前面的查询一样,以下查询使用 SUM() ,但这次作为窗口函数:

MySQL的> SELECT
         year, country, product, profit,
         SUM(profit) OVER() AS total_profit,
         SUM(profit) OVER(PARTITION BY country) AS country_profit
       FROM sales
       ORDER BY country, year, product, profit;
+ ------ + --------- + ------------ + -------- + ---------- ---- + ---------------- +
| 一年| 国家| 产品| 利润| total_profit | country_profit |
+ ------ + --------- + ------------ + -------- + ---------- ---- + ---------------- +
| 2000年| 芬兰| 电脑| 1500 | 7535 | 1610 |
| 2000年| 芬兰| 电话| 100 | 7535 | 1610 |
| 2001 | 芬兰| 电话| 10 | 7535 | 1610 |
| 2000年| 印度| 计算器| 75 | 7535 | 1350 |
| 2000年| 印度| 计算器| 75 | 7535 | 1350 |
| 2000年| 印度| 电脑| 1200 | 7535 | 1350 |
| 2000年| 美国| 计算器| 75 | 7535 | 4575 |
| 2000年| 美国| 电脑| 1500 | 7535 | 4575 |
| 2001 | 美国| 计算器| 50 | 7535 | 4575 |
| 2001 | 美国| 电脑| 1200 | 7535 | 4575 |
| 2001 | 美国| 电脑| 1500 | 7535 | 4575 |
| 2001 | 美国| 电视| 100 | 7535 | 4575 |
| 2001 | 美国| 电视| 150 | 7535 | 4575 |
+ ------ + --------- + ------------ + -------- + ---------- ---- + ---------------- +

查询中的每个窗口操作都通过包含一个 OVER 子句来 表示,该 子句指定如何将查询行分区为组以供窗口函数处理:

  • 第一个 OVER 子句为空,它将整个查询行集视为单个分区。 因此,窗函数产生全局和,但对每一行都这样做。

  • 第二个 OVER 子句按国家/地区划分行,每个分区(每个国家/地区)生成一个总和。 该函数为每个分区行生成此总和。

仅在选择列表和 ORDER BY 子句 中允许窗口函数 查询结果行从确定 FROM 子句后 WHERE GROUP BY 以及 HAVING 处理和开窗执行发生之前 ORDER BY LIMIT SELECT DISTINCT

OVER 子句允许用于许多聚合函数,因此可以用作窗口函数或非窗口函数,具体取决于是否 OVER 子句 存在:

AVG()
BIT_AND()
BIT_OR()
BIT_XOR()
计数()
JSON_ARRAYAGG()
JSON_OBJECTAGG()
MAX()
MIN()
STDDEV_POP(),STDDEV(),STD()
STDDEV_SAMP()
和()
VAR_POP(),VARIANCE()
VAR_SAMP()

有关每个聚合函数的详细信息,请参见 第12.20.1节“聚合(GROUP BY)函数说明”

MySQL还支持仅用作窗口函数的非聚合函数。 对于这些, OVER 条款是强制性的:

CUME_DIST()
DENSE_RANK()
FIRST_VALUE()
落后()
LAST_VALUE()
铅()
NTH_VALUE()
NTILE()
PERCENT_RANK()
秩()
ROW_NUMBER()

有关每个非 聚合 函数的详细信息,请参见 第12.21.1节“窗口函数说明”

作为其中一个非聚合窗口函数的示例,此查询使用 ROW_NUMBER() ,它生成其分区中每行的行号。 在这种情况下,行按每个国家/地区编号。 默认情况下,分区行是无序的,行编号是不确定的。 要对分区行进行排序,请 ORDER BY 在窗口定义中 包含一个 子句。 该查询使用无序和有序分区( row_num1 row_num2 列)来说明省略和包括之间的区别 ORDER BY

MySQL的> SELECT
         year, country, product, profit,
         ROW_NUMBER() OVER(PARTITION BY country) AS row_num1,
         ROW_NUMBER() OVER(PARTITION BY country ORDER BY year, product) AS row_num2
       FROM sales;
+ ------ + --------- + ------------ + -------- + ---------- + ---------- +
| 一年| 国家| 产品| 利润| row_num1 | row_num2 |
+ ------ + --------- + ------------ + -------- + ---------- + ---------- +
| 2000年| 芬兰| 电脑| 1500 | 2 | 1 |
| 2000年| 芬兰| 电话| 100 | 1 | 2 |
| 2001 | 芬兰| 电话| 10 | 3 | 3 |
| 2000年| 印度| 计算器| 75 | 2 | 1 |
| 2000年| 印度| 计算器| 75 | 3 | 2 |
| 2000年| 印度| 电脑| 1200 | 1 | 3 |
| 2000年| 美国| 计算器| 75 | 5 | 1 |
| 2000年| 美国| 电脑| 1500 | 4 | 2 |
| 2001 | 美国| 计算器| 50 | 2 | 3 |
| 2001 | 美国| 电脑| 1500 | 3 | 4 |
| 2001 | 美国| 电脑| 1200 | 7 | 5 |
| 2001 | 美国| 电视| 150 | 1 | 6 |
| 2001 | 美国| 电视| 100 | 6 | 7 |
+ ------ + --------- + ------------ + -------- + ---------- + ---------- +

如前所述,要使用窗口函数(或将聚合函数视为窗口函数),请 OVER 在函数调用后 包含一个 子句。 OVER 条款有两种形式:

over_clause
    {OVER(window_spec)| 超过window_name}

两种形式都定义了窗口函数应如何处理查询行。 它们的不同之处在于窗口是直接在 OVER 子句中 定义 ,还是由对查询中其他位置定义的命名窗口的引用提供:

  • 在第一种情况下,窗口规范直接出现在 OVER 括号内 子句中。

  • 在第二种情况下, window_name 是由 WINDOW 查询中其他地方 子句 定义的窗口规范的名称 有关详细信息,请参见 第12.21.4节“命名Windows”

对于 语法,窗口规范有几个部分,都是可选的: OVER (window_spec)

window_spec
    [ window_name] [ partition_clause] [ order_clause] [ frame_clause]

如果 OVER() 为空,则窗口由所有查询行组成,窗口函数使用所有行计算结果。 否则,括号内的子句确定使用哪些查询行来计算函数结果以及如何对它们进行分区和排序:

  • window_name :由 WINDOW 查询中其他位置 子句 定义的窗口的名称 如果 window_name OVER 子句中单独出现,则它完全定义窗口。 如果还给出了分区,排序或框架子句,则它们会修改指定窗口的解释。 有关详细信息,请参见 第12.21.4节“命名Windows”

  • partition_clause PARTITION BY 子句指示如何将查询行划分为组。 给定行的窗口函数结果基于包含该行的分区的行。 如果 PARTITION BY 省略,则存在由所有查询行组成的单个分区。

    注意

    窗口函数的分区与表分区不同。 有关表分区的信息,请参见 第23章, 分区

    partition_clause 有这种语法:

    partition_clause
        PARTITION BY expr[,expr] ......
    

    标准SQL只需要 PARTITION BY 后跟列名。 MySQL扩展是允许表达式,而不仅仅是列名。 例如,如果一个表包含一个 TIMESTAMP 名为 ts ,标准SQL允许 PARTITION BY ts 但不允许 PARTITION BY HOUR(ts) ,而MySQL允许两者。

  • order_clause ORDER BY 子句指示如何对每个分区中的行进行排序。 根据 ORDER BY 子句 相等的分区行 被视为对等。 如果 ORDER BY 省略,则分区行是无序的,没有隐含的处理顺序,并且所有分区行都是对等的。

    order_clause 有这种语法:

    order_clause
        ORDER BY expr[ASC | DESC] [,expr [ASC | DESC]] ......
    

    每个 ORDER BY 表达式可选地可以跟随 ASC DESC 指示排序方向。 默认为 ASC 未指定方向。 NULL 值首先排序为升序排序,最后排序为降序排序。

    一个 ORDER BY 单独的分区中的一个窗口定义适用。 要将结果集整体排序,请 ORDER BY 在查询顶级 包含a

  • frame_clause :帧是当前分区的子集,frame子句指定如何定义子集。 frame子句有许多子条款。 有关详细信息,请参见 第12.21.3节“窗口功能框架规范”

12.21.3窗口功能框架规范

与窗口函数一起使用的窗口的定义可以包括frame子句。 帧是当前分区的子集,frame子句指定如何定义子集。

帧是根据当前行确定的,这使得帧能够在分区内移动,具体取决于其分区内当前行的位置。 例子:

  • 通过将帧定义为从分区开始到当前行的所有行,您可以计算每行的运行总计。

  • 通过将框架定义为 N 当前行两侧的 扩展 行,您可以计算滚动平均值。

以下查询演示了如何使用移动框架来计算每组时间排序 level 值中的 运行总计 ,以及从当前行计算的滚动平均值以及紧接在其之前和之后的行:

MySQL的> SELECT
         time, subject, val,
         SUM(val) OVER (PARTITION BY subject ORDER BY time
                        ROWS UNBOUNDED PRECEDING)
           AS running_total,
         AVG(val) OVER (PARTITION BY subject ORDER BY time
                        ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
           AS running_average
       FROM observations;
+ ---------- + --------- + ------ + --------------- + ----- ------------ +
| 时间| 主题| val | running_total | running_average |
+ ---------- + --------- + ------ + --------------- + ----- ------------ +
| 07:00:00 | st113 | 10 | 10 | 9.5000 |
| 07:15:00 | st113 | 9 | 19 | 14.6667 |
| 07:30:00 | st113 | 25 | 44 | 18.0000 |
| 07:45:00 | st113 | 20 | 64 | 22.5000 |
| 07:00:00 | xh458 | 0 | 0 | 5.0000 |
| 07:15:00 | xh458 | 10 | 10 | 5.0000 |
| 07:30:00 | xh458 | 5 | 15 | 15.0000 |
| 07:45:00 | xh458 | 30 | 45 | 20.0000 |
| 08:00:00 | xh458 | 25 | 70 | 27.5000 |
+ ---------- + --------- + ------ + --------------- + ----- ------------ +

对于 running_average 列,在第一个之前或之后没有帧行。 在这些情况下, AVG() 计算可用行的平均值。

用作窗口函数的聚合函数对当前行框架中的行进行操作,这些非聚合窗口函数也是如此:

FIRST_VALUE()
LAST_VALUE()
NTH_VALUE()

标准SQL指定在整个分区上运行的窗口函数应该没有frame子句。 MySQL为这些函数允许一个frame子句但忽略它。 即使指定了框架,这些函数也会使用整个分区:

CUME_DIST()
DENSE_RANK()
落后()
铅()
NTILE()
PERCENT_RANK()
秩()
ROW_NUMBER()

如果给出了frame子句,则具有以下语法:

frame_clauseframe_units frame_extent

frame_units
    {ROWS | 范围}

在没有frame子句的情况下,默认帧取决于是否存在 ORDER BY 子句,如本节后面所述。

frame_units 值指示当前行和帧行之间的关系类型:

  • ROWS :框架由开始和结束行位置定义。 偏移量是行号与当前行号的差异。

  • RANGE :框架由值范围内的行定义。 偏移量是行值与当前行值的差异。

frame_extent 值表示帧的起点和终点。 您可以只指定帧的开头(在这种情况下,当前行隐式结束)或用于 BETWEEN 指定两个帧端点:

frame_extent
    { frame_start| frame_between}

frame_betweenframe_start和之间frame_end

frame_startframe_end:{
    当前行
  | 无约束的先行
  | 以下是无限制的
  | expr
  | expr以下
}

使用 BETWEEN 语法, frame_start 不得晚于 frame_end

允许 frame_start frame_end 值具有以下含义:

  • CURRENT ROW :对于 ROWS ,绑定是当前行。 因为 RANGE ,bound是当前行的对等体。

  • UNBOUNDED PRECEDING :绑定是第一个分区行。

  • UNBOUNDED FOLLOWING :绑定是最后一个分区行。

  • expr PRECEDING :对于 ROWS ,绑定是 expr 当前行之前的行。 对于 RANGE ,bound是值等于当前行值减去的行 expr ; 如果当前行值为 NULL 则该行是 该行的对等点。

    对于 expr PRECEDING (和 expr FOLLOWING ), expr 可以是 ? 参数标记(用于预准备语句),非负数字文字或表单的时间间隔 对于 表达式, 指定非负区间值,并且 是一个关键字,指示应在其中解释值的单位。 (有关详细信息,允许 符,看到的描述 功能在 12.7节,“日期和时间函数” 。) INTERVAL val unit INTERVAL val unit units DATE_ADD()

    RANGE 分别对 数字或时间表达式 的数字或时间 expr 要求 ORDER BY

    有效 expr PRECEDING expr FOLLOWING 指标的 例子

    10预先
    间隔5天预付款
    5以下
    INTERVAL'2:30'MINUTE_SECOND以下
    
  • expr FOLLOWING :对于 ROWS ,绑定是 expr 当前行之后的行。 对于 RANGE ,bound是值等于当前行值加上的行 expr ; 如果当前行值为 NULL 则该行是 该行的对等点。

    有关允许值 expr ,请参阅说明 expr PRECEDING

下面的查询演示 FIRST_VALUE() LAST_VALUE() 以及两个实例 NTH_VALUE()

MySQL的> SELECT
         time, subject, val,
         FIRST_VALUE(val)  OVER w AS 'first',
         LAST_VALUE(val)   OVER w AS 'last',
         NTH_VALUE(val, 2) OVER w AS 'second',
         NTH_VALUE(val, 4) OVER w AS 'fourth'
       FROM observations
       WINDOW w AS (PARTITION BY subject ORDER BY time
                    ROWS UNBOUNDED PRECEDING);
+ ---------- + --------- + ------ + ------- + ------ + ------ -  + -------- +
| 时间| 主题| val | 第一个| 最后| 第二个| 第四|
+ ---------- + --------- + ------ + ------- + ------ + ------ -  + -------- +
| 07:00:00 | st113 | 10 | 10 | 10 | NULL | NULL |
| 07:15:00 | st113 | 9 | 10 | 9 | 9 | NULL |
| 07:30:00 | st113 | 25 | 10 | 25 | 9 | NULL |
| 07:45:00 | st113 | 20 | 10 | 20 | 9 | 20 |
| 07:00:00 | xh458 | 0 | 0 | 0 | NULL | NULL |
| 07:15:00 | xh458 | 10 | 0 | 10 | 10 | NULL |
| 07:30:00 | xh458 | 5 | 0 | 5 | 10 | NULL |
| 07:45:00 | xh458 | 30 | 0 | 30 | 10 | 30 |
| 08:00:00 | xh458 | 25 | 0 | 25 | 10 | 30 |
+ ---------- + --------- + ------ + ------- + ------ + ------ -  + -------- +

每个函数使用当前帧中的行,根据所示的窗口定义,这些行从第一个分区行延伸到当前行。 对于 NTH_VALUE() 调用,当前帧并不总是包括所请求的行; 在这种情况下,返回值是 NULL

在没有frame子句的情况下,默认帧取决于是否存在 ORDER BY 子句:

  • 使用 ORDER BY :默认框架包括从分区开始到当前行的行,包括当前行的所有对等项(根据 ORDER BY 子句 等于当前行的行 )。 默认值等效于此帧规范:

    无界先行与当前行之间的范围
    
  • 不使用 ORDER BY :默认框架包括所有分区行(因为没有 ORDER BY ,所有分区行都是对等的)。 默认值等效于此帧规范:

    无界先行与无界之间的范围
    

因为默认框架根据是否存在而不同 ORDER BY ,添加 ORDER BY 到查询以获得确定性结果可能会更改结果。 (例如, SUM() 可能会更改 生成的值 。)要获得相同但按顺序排序的结果 ORDER BY ,请提供要使用的显式帧规范,而不管是否 ORDER BY 存在。

当前行值为时,帧规范的含义可以是非显而易见的 NULL 假设是这种情况,这些示例说明了各种帧规范如何适用:

  • ORDER BY X ASC RANGE BETWEEN 10 FOLLOWING AND 15 FOLLOWING

    帧开始于 NULL 和停止 NULL ,因此仅包括具有值的行 NULL

  • ORDER BY X ASC RANGE BETWEEN 10 FOLLOWING AND UNBOUNDED FOLLOWING

    框架从 NULL 分区结束处 开始 并停止。 因为 ASC 排序 NULL 首先 放置 值,所以帧是整个分区。

  • ORDER BY X DESC RANGE BETWEEN 10 FOLLOWING AND UNBOUNDED FOLLOWING

    框架从 NULL 分区结束处 开始 并停止。 因为 DESC 排序 NULL 最后 放置 值,所以框架只是 NULL 值。

  • ORDER BY X ASC RANGE BETWEEN 10 PRECEDING AND UNBOUNDED FOLLOWING

    框架从 NULL 分区结束处 开始 并停止。 因为 ASC 排序 NULL 首先 放置 值,所以帧是整个分区。

  • ORDER BY X ASC RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING

    帧开始于 NULL 和停止 NULL ,因此仅包括具有值的行 NULL

  • ORDER BY X ASC RANGE BETWEEN 10 PRECEDING AND 1 PRECEDING

    帧开始于 NULL 和停止 NULL ,因此仅包括具有值的行 NULL

  • ORDER BY X ASC RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING

    框架从分区的开始处开始,并在具有值的行处停止 NULL 因为 ASC 排序 NULL 首先 放置 值,所以框架只是 NULL 值。

12.21.4命名为Windows

可以定义Windows并给出用于在 OVER 子句中 引用它们的名称 为此,请使用 WINDOW 子句。 如果存在于查询中,则该 WINDOW 子句位于 HAVING ORDER BY 子句 的位置之间 ,并具有以下语法:

WINDOW window_nameAS(window_spec
    [,window_nameAS(window_spec)] ......

对于每个窗口定义, window_name 是窗口名称,并且与 子句 window_spec 的括号之间给出的窗口规范类型相同 OVER ,如 第12.21.2节“窗口函数概念和语法”中所述

window_spec
    [ window_name] [ partition_clause] [ order_clause] [ frame_clause]

WINDOW 子句对于其中多个查询是有用 OVER 的条款,否则定义相同的窗口。 相反,您可以定义窗口一次,为其命名,并在 OVER 子句中 引用名称 考虑这个查询,它多次定义同一个窗口:

选择
  VAL,
  ROW_NUMBER()OVER(ORDER BY val)AS'row_number',
  RANK()OVER(ORDER BY val)AS'rank',
  DENSE_RANK()OVER(ORDER BY val)AS'heavy_rank'
来自数字;

通过使用 WINDOW 一次定义窗口并在 OVER 子句中 按名称引用窗口, 可以更简单地编写查询

选择
  VAL,
  ROW_NUMBER()超过'row_number',
  RANK()超过'等级',
  DENSE_RANK()超过'dense_rank'
从数字
WINDOW W AS(ORDER BY val);

命名窗口还可以更轻松地尝试窗口定义以查看对查询结果的影响。 您只需要修改 WINDOW 子句中 的窗口定义 ,而不是多个 OVER 子句定义。

如果 OVER 子句使用 而不是 ,则可以通过添加其他子句来修改命名窗口。 例如,此查询定义了一个包含分区的窗口,并 子句中 使用 以不同方式修改窗口: OVER (window_name ...) OVER window_name ORDER BY OVER

选择
  DISTINCT年份,国家,
  FIRST_VALUE(年)超过(按年度ASC排序)AS,
  FIRST_VALUE(年)超过(按年度DESC)作为最后一个
从销售
WINDOW W AS(国家分区);

一个 OVER 子句只能添加属性命名的窗口,不能修改它们。 如果指定的窗口定义包含分区,排序或框架属性,则 OVER 引用窗口名称 子句也不能包含相同类型的属性或发生错误:

  • 允许此构造,因为窗口定义和引用 OVER 子句不包含相同类型的属性:

    超过(按国家/地区分类)
    ... WINDOW w AS(按国家划分)
    
  • 不允许使用此构造,因为该 OVER 子句 PARTITION BY 为已经具有以下内容的命名窗口 指定 PARTITION BY

    超过(按年度划分)
    ... WINDOW w AS(按国家划分)
    

命名窗口的定义本身可以以a开头 window_name 在这种情况下,允许前向和后向引用,但不允许循环:

  • 这是允许的; 它包含前向和后向引用,但没有循环:

    WINDOW w1 AS(w2),w2 AS(),w3 AS(w1)
    
  • 这是不允许的,因为它包含一个循环:

    WINDOW w1 AS(w2),w2 AS(w3),w3 AS(w1)
    

12.21.5窗口函数限制

SQL标准对不能使用的窗口函数 UPDATE DELETE 更新行的语句 施加约束 允许在这些语句的子查询中使用此类函数(以选择行)。

MySQL不支持这些窗口功能:

  • DISTINCT 聚合窗口函数的语法。

  • 嵌套窗口函数。

  • 动态帧端点,它取决于当前行的值。

解析器识别这些不支持的窗口构造:

  • GROUPS 帧为单位指定符进行解析,但产生一个错误。 只有 ROWS RANGE 支持。

  • EXCLUDE 解析帧规范 子句,但会产生错误。

  • IGNORE NULLS 被解析,但产生错误。 RESPECT NULLS 支持。

  • FROM LAST 被解析,但产生错误。 FROM FIRST 支持。

12.22性能模式函数

从MySQL 8.0.16开始,MySQL包含内置的SQL函数,可以格式化或检索性能模式数据,并且可以用作相应 sys 模式存储函数的 等效 函数。 可以在任何模式中调用内置函数,并且不需要限定符,这与 sys 需要 sys. 模式限定符或 sys 当前模式 函数 不同

表12.28性能模式函数

名称 描述
FORMAT_BYTES() 将字节数转换为带单位的值
FORMAT_PICO_TIME() 将时间(皮秒)转换为单位值
PS_CURRENT_THREAD_ID() 当前线程的性能架构线程ID
PS_THREAD_ID() 给定线程的性能架构线程ID

内置函数取代了相应的 sys 函数,这些函数已弃用,将在未来的MySQL版本中删除。 sys 应调整 使用这些 函数的 应用程序 以使用内置函数,同时记住 sys 函数和内置函数 之间的一些细微差别 有关这些差异的详细信息,请参阅本节中的功能说明。

  • FORMAT_BYTES(count)

    给定数字字节计数,将其转换为人类可读格式并返回由值和单位指示符组成的字符串。 该字符串包含舍入到2位小数的字节数和最少3位有效数字。 小于1024字节的数字表示为整数,不是舍入的。

    units指示符取决于byte-count参数的大小,如下表所示。

    论证价值 结果单位 结果单位指标
    高达1023 字节 字节
    最多1024 2 - 1 kibibytes 昆明植物研究所
    最多1024 3 - 1 mebibytes MIB
    最多1024 4 - 1 gibibytes 吉布
    最多1024 5 - 1 tebibytes 的TiB
    最多1024 6 - 1 pebibytes PiB负荷
    1024 6 及以上 exbibytes EIB
    MySQL的> SELECT FORMAT_BYTES(512), FORMAT_BYTES(18446644073709551615);
    + ------------------- + ----------------------------- ------- +
    | FORMAT_BYTES(512)| FORMAT_BYTES(18446644073709551615)|
    + ------------------- + ----------------------------- ------- +
    | 512字节| 16.00 EiB |
    + ------------------- + ----------------------------- ------- +
    

    FORMAT_BYTES() 在MySQL 8.0.16中添加了。 它可以用来代替 sys 模式 format_bytes() 函数,记住这个区别:

  • FORMAT_PICO_TIME(time_val)

    给定数字性能模式延迟或以皮秒为单位的等待时间,将其转换为人类可读格式并返回由值和单位指示符组成的字符串。 该字符串包含舍入到2位小数的十进制时间和最少3位有效数字。 1纳秒以下的时间表示为整数,不是四舍五入。

    单位指示符取决于时间值参数的大小,如下表所示。

    论证价值 结果单位 结果单位指标
    最多10 3 - 1 皮秒 PS
    最多10 6 - 1 纳秒 NS
    高达10 9 - 1 微秒 我们
    最多10 12 - 1 毫秒 女士
    高达60×10 12 - 1 小号
    高达3.6×10 15 - 1 分钟
    高达8.64×10 16 - 1 小时 H
    8.64×10 16 及以上 d
    MySQL的> SELECT FORMAT_PICO_TIME(3501), FORMAT_PICO_TIME(188732396662000);
    + ------------------------ + ------------------------ ----------- +
    | FORMAT_PICO_TIME(3501)| FORMAT_PICO_TIME(188732396662000)|
    + ------------------------ + ------------------------ ----------- +
    | 3.50 ns | 3.15分钟|
    + ------------------------ + ------------------------ ----------- +
    

    FORMAT_PICO_TIME() 在MySQL 8.0.16中添加了。 它可以用来代替 sys 模式 format_time() 函数,记住这些差异:

  • PS_CURRENT_THREAD_ID()

    返回 BIGINT UNSIGNED 表示分配给当前连接的Performance Schema线程ID 值。

    线程ID返回值是 THREAD_ID Performance Schema表列中 给出的类型的值

    性能架构配置的影响 PS_CURRENT_THREAD_ID() 方式 与之 相同 PS_THREAD_ID() 有关详细信息,请参阅该功能的说明。

    MySQL的> SELECT PS_CURRENT_THREAD_ID();
    + ------------------------ +
    | PS_CURRENT_THREAD_ID()|
    + ------------------------ +
    | 52 |
    + ------------------------ +
    MySQL的> SELECT PS_THREAD_ID(CONNECTION_ID());
    + ------------------------------- +
    | PS_THREAD_ID(CONNECTION_ID())|
    + ------------------------------- +
    | 52 |
    + ------------------------------- +
    

    PS_CURRENT_THREAD_ID() 在MySQL 8.0.16中添加了。 它可以用作调用 带有 的参数 sys 模式 ps_thread_id() 函数 的快捷方式 NULL CONNECTION_ID()

  • PS_THREAD_ID(connection_id)

    给定连接ID,返回 BIGINT UNSIGNED 表示分配给连接ID的性能模式线程ID 值,或 NULL 如果 不存在线程ID。 后者可以针对未检测的线程发生。

    连接ID参数是 PROCESSLIST_ID Performance Schema threads 表或 Id 列的 列中 给出的类型的值 SHOW PROCESSLIST 输出

    线程ID返回值是在给定的类型的值 THREAD_ID Performance Schema表列中

    性能模式配置会影响 PS_THREAD_ID() 操作,如下所示。 (这些评论也适用于 PS_CURRENT_THREAD_ID() 。)

    MySQL的> SELECT PS_THREAD_ID(6);
    + ----------------- +
    | PS_THREAD_ID(6)|
    + ----------------- +
    | 45 |
    + ----------------- +
    

    PS_THREAD_ID() 在MySQL 8.0.16中添加了。 它可以用来代替 sys 模式 ps_thread_id() 函数,记住这个区别:

12.23内部功能

表12.29内部功能

名称 描述
CAN_ACCESS_COLUMN() 限内部使用
CAN_ACCESS_DATABASE() 限内部使用
CAN_ACCESS_TABLE() 限内部使用
CAN_ACCESS_VIEW() 限内部使用
GET_DD_COLUMN_PRIVILEGES() 限内部使用
GET_DD_CREATE_OPTIONS() 限内部使用
GET_DD_INDEX_SUB_PART_LENGTH() 限内部使用
INTERNAL_AUTO_INCREMENT() 限内部使用
INTERNAL_AVG_ROW_LENGTH() 限内部使用
INTERNAL_CHECK_TIME() 限内部使用
INTERNAL_CHECKSUM() 限内部使用
INTERNAL_DATA_FREE() 限内部使用
INTERNAL_DATA_LENGTH() 限内部使用
INTERNAL_DD_CHAR_LENGTH() 限内部使用
INTERNAL_GET_COMMENT_OR_ERROR() 限内部使用
INTERNAL_GET_VIEW_WARNING_OR_ERROR() 限内部使用
INTERNAL_INDEX_COLUMN_CARDINALITY() 限内部使用
INTERNAL_INDEX_LENGTH() 限内部使用
INTERNAL_KEYS_DISABLED() 限内部使用
INTERNAL_MAX_DATA_LENGTH() 限内部使用
INTERNAL_TABLE_ROWS() 限内部使用
INTERNAL_UPDATE_TIME() 限内部使用

本节中列出的功能仅供服务器内部使用。 用户尝试调用它们会导致错误。

12.24其他功能

表12.30其他功能

名称 描述
ANY_VALUE() 抑制ONLY_FULL_GROUP_BY值拒绝
BIN_TO_UUID() 将二进制UUID转换为字符串
DEFAULT() 返回表列的默认值
GROUPING() 区分超级聚合ROLLUP行与常规行
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地址
IS_UUID() 参数是否是有效的UUID
MASTER_POS_WAIT() 阻止,直到从站已读取并应用所有更新到指定位置
NAME_CONST() 导致列具有给定名称
RAND() 返回随机浮点值
SLEEP() 睡几秒钟
UUID() 返回通用唯一标识符(UUID)
UUID_SHORT() 返回整数值通用标识符
UUID_TO_BIN() 将字符串UUID转换为二进制
VALUES() 定义INSERT期间要使用的值

  • ANY_VALUE(arg)

    对于 启用S​​QL模式的 GROUP BY 查询, 此函数非常有用 ONLY_FULL_GROUP_BY ,因为MySQL拒绝您知道MySQL无法确定的查询的查询。 函数返回值和类型与其参数的返回值和类型相同,但不检查 ONLY_FULL_GROUP_BY SQL模式 的函数结果

    例如,如果 name 是非索引列,则以下查询将失败并 ONLY_FULL_GROUP_BY 启用:

    
    MySQL的> SELECT name, address, MAX(age) FROM t GROUP BY name;
    错误1055(42000):SELECT列表的表达式#2不在GROUP中
    BY子句并包含非聚合列'mydb.t.address'
    在功能上不依赖于GROUP BY子句中的列; 这个
    与sql_mode = only_full_group_by不兼容
    

    发生故障是因为 address 非聚合列既不在 GROUP BY 列中 命名, 也不在功能上依赖于它们。 因此, address 每个 name 组中的 是不确定的。 有多种方法可以使MySQL接受查询:

    • 更改表以创建 name 主键或唯一 NOT NULL 列。 这使MySQL能够确定 address 在功能上依赖于 name ; 也就是说, address 由唯一确定 name (如果 NULL 必须允许 此技术 作为有效值, 则此技术不适用 name 。)

    • 使用 ANY_VALUE() 是指 address

      SELECT名称,ANY_VALUE(地址),MAX(年龄)FROM t GROUP BY名称;
      

      在这种情况下,MySQL忽略 address 每个 name 的不确定性 并接受查询。 如果您根本不关心为每个组选择哪个非聚合列的值,这可能很有用。 ANY_VALUE() 不是聚集函数,不像功能,例如 SUM() COUNT() 它只是用来抑制非确定性的测试。

    • 禁用 ONLY_FULL_GROUP_BY 这相当于使用 ANY_VALUE() with ONLY_FULL_GROUP_BY enabled,如上一项所述。

    ANY_VALUE() 如果列之间存在函数依赖,但MySQL无法确定它,这也很有用。 以下查询是有效的,因为 age 它在功能上依赖于分组列 age-1 ,但MySQL不能告诉它并拒绝 ONLY_FULL_GROUP_BY 启用 的查询

    选择年龄FROM t GROUP BY age-1;
    

    要使MySQL接受查询,请使用 ANY_VALUE()

    SELECT ANY_VALUE(age)FROM t GROUP BY age-1;
    

    ANY_VALUE() 可以用于在没有 GROUP BY 子句 的情况下引用聚合函数的查询

    
    MySQL的> SELECT name, MAX(age) FROM t;
    错误1140(42000):在没有GROUP BY,表达式的聚合查询中
    SELECT列表的#1包含非聚合列'mydb.t.name'; 这个
    与sql_mode = only_full_group_by不兼容
    

    没有 GROUP BY ,只有一个组,它是不确定的, name 为组选择值。 ANY_VALUE() 告诉MySQL接受查询:

    SELECT ANY_VALUE(name),MAX(age)FROM t;
    

    可能是由于给定数据集的某些属性,您知道所选的非聚合列在功能上有效地依赖于 GROUP BY 列。 例如,应用程序可以强制一列相对于另一列的唯一性。 在这种情况下,使用 ANY_VALUE() 有效的功能依赖列可能是有意义的。

    有关其他讨论,请参见 第12.20.3节“GROUP BY的MySQL处理”

  • BIN_TO_UUID(binary_uuid) BIN_TO_UUID(binary_uuid, swap_flag)

    BIN_TO_UUID() 是反的 UUID_TO_BIN() 它将二进制UUID转换为字符串UUID并返回结果。 二进制值应该是UUID作为 VARBINARY(16) 值。 返回值是 utf8 由破折号分隔的五个十六进制数字 字符串。 (有关此格式的详细信息,请参阅 UUID() 函数说明。)如果UUID参数为 NULL ,则返回值为 NULL 如果任何参数无效,则会发生错误。

    BIN_TO_UUID() 需要一个或两个参数:

    • 单参数形式采用二进制UUID值。 假设UUID值没有交换时间低和时间高的部分。 字符串结果与二进制参数的顺序相同。

    • 双参数形式采用二进制UUID值和swap-flag值:

      • 如果 swap_flag 为0,则双参数形式等效于单参数形式。 字符串结果与二进制参数的顺序相同。

      • 如果 swap_flag 为1,则假定UUID值具有交换的时间低和时间高的部分。 这些部件将交换回结果值中的原始位置。

    有关时间 - 部分交换的用法示例和信息,请参阅 UUID_TO_BIN() 功能说明。

  • DEFAULT(col_name)

    返回表列的默认值。 如果列没有默认值,则会出现错误。

    仅允许具有文字默认值的列 使用 指定命名列的默认值,而不允许使用具有表达式默认值的列。 DEFAULT(col_name)

    MySQL的> UPDATE t SET i = DEFAULT(i)+1 WHERE id < 100;
    
  • FORMAT(X,D)

    将数字格式化 X 为格式 '#,###,###.##' ,舍入到 D 小数位,并将结果作为字符串返回。 有关详细信息,请参见 第12.5节“字符串函数”

  • GROUPING(expr [, expr] ...)

    对于 GROUP BY 包含 WITH ROLLUP 修饰符的 查询 ,该 ROLLUP 操作会生成超级聚合输出行,其中 NULL 表示所有值的集合。 GROUPING() 功能使您可以区分 NULL 超级聚合行的 NULL 值与常规分组行中的值。

    GROUPING() 只允许在选择列表或 HAVING 子句中使用。

    每个参数 GROUPING() 必须是与 GROUP BY 子句 中的表达式完全匹配的表达式 表达式不能是位置说明符。 对于每个表达式, GROUPING() 如果当前行中的表达式值 NULL 表示超级聚合值 ,则 生成1 否则, GROUPING() 生成0,表示表达式值是 NULL 常规结果行的a或不是 NULL

    假设该表 t1 包含这些行,其中 NULL 表示 other unknown ”之类的内容

    MySQL的> SELECT * FROM t1;
    + ------ + ------- + ---------- +
    | 名字| 尺寸| 数量|
    + ------ + ------- + ---------- +
    | 球| 小| 10 |
    | 球| 大| 20 |
    | 球| NULL | 5 |
    | 箍| 小| 15 |
    | 箍| 大| 5 |
    | 箍| NULL | 3 |
    + ------ + ------- + ---------- +
    

    表的摘要不是 WITH ROLLUP 这样的:

    MySQL的> SELECT name, size, SUM(quantity) AS quantity
           FROM t1
           GROUP BY name, size;
    + ------ + ------- + ---------- +
    | 名字| 尺寸| 数量|
    + ------ + ------- + ---------- +
    | 球| 小| 10 |
    | 球| 大| 20 |
    | 球| NULL | 5 |
    | 箍| 小| 15 |
    | 箍| 大| 5 |
    | 箍| NULL | 3 |
    + ------ + ------- + ---------- +
    

    结果包含 NULL 值,但这些值不代表超级聚合行,因为查询不包含 WITH ROLLUP

    添加 WITH ROLLUP 会生成包含其他 NULL 值的 超级聚合摘要行 但是,如果不将此结果与前一个结果进行比较,则很难看出哪些 NULL 值出现在超级聚合行中,哪些值出现在常规分组行中:

    MySQL的> SELECT name, size, SUM(quantity) AS quantity
           FROM t1
           GROUP BY name, size WITH ROLLUP;
    + ------ + ------- + ---------- +
    | 名字| 尺寸| 数量|
    + ------ + ------- + ---------- +
    | 球| NULL | 5 |
    | 球| 大| 20 |
    | 球| 小| 10 |
    | 球| NULL | 35 |
    | 箍| NULL | 3 |
    | 箍| 大| 5 |
    | 箍| 小| 15 |
    | 箍| NULL | 23 |
    | NULL | NULL | 58 |
    + ------ + ------- + ---------- +
    

    要区分 NULL 超级聚合行中的值与常规分组行中的值,请使用 GROUPING() ,仅对超级聚合 NULL 返回1

    MySQL的> SELECT
             name, size, SUM(quantity) AS quantity,
             GROUPING(name) AS grp_name,
             GROUPING(size) AS grp_size
           FROM t1
           GROUP BY name, size WITH ROLLUP;
    + ------ + ------- + ---------- + ---------- + ---------- +
    | 名字| 尺寸| 数量| grp_name | grp_size |
    + ------ + ------- + ---------- + ---------- + ---------- +
    | 球| NULL | 5 | 0 | 0 |
    | 球| 大| 20 | 0 | 0 |
    | 球| 小| 10 | 0 | 0 |
    | 球| NULL | 35 | 0 | 1 |
    | 箍| NULL | 3 | 0 | 0 |
    | 箍| 大| 5 | 0 | 0 |
    | 箍| 小| 15 | 0 | 0 |
    | 箍| NULL | 23 | 0 | 1 |
    | NULL | NULL | 58 | 1 | 1 |
    + ------ + ------- + ---------- + ---------- + ---------- +
    

    常用用途 GROUPING()

    • 用标签代替超级聚合 NULL 值:

      MySQL的> SELECT
               IF(GROUPING(name) = 1, 'All items', name) AS name,
               IF(GROUPING(size) = 1, 'All sizes', size) AS size,
               SUM(quantity) AS quantity
             FROM t1
             GROUP BY name, size WITH ROLLUP;
      + ----------- ----------- + ---------- + +
      | 名字| 尺寸| 数量|
      + ----------- ----------- + ---------- + +
      | 球| NULL | 5 |
      | 球| 大| 20 |
      | 球| 小| 10 |
      | 球| 所有尺寸| 35 |
      | 箍| NULL | 3 |
      | 箍| 大| 5 |
      | 箍| 小| 15 |
      | 箍| 所有尺寸| 23 |
      | 所有项目| 所有尺寸| 58 |
      + ----------- ----------- + ---------- + +
      
    • 通过过滤掉常规的分组行,仅返回超级聚合行:

      MySQL的> SELECT name, size, SUM(quantity) AS quantity
             FROM t1
             GROUP BY name, size WITH ROLLUP
             HAVING GROUPING(name) = 1 OR GROUPING(size) = 1;
      + ------ + ------ + ---------- +
      | 名字| 尺寸| 数量|
      + ------ + ------ + ---------- +
      | 球| NULL | 35 |
      | 箍| NULL | 23 |
      | NULL | NULL | 58 |
      + ------ + ------ + ---------- +
      

    GROUPING() 允许多个表达式参数。 在这种情况下, GROUPING() 返回值表示从每个表达式的结果组合的位掩码,其中最低位对应于最右侧表达式的结果。 例如,使用三个表达式参数, 就像这样计算: GROUPING(expr1, expr2, expr3)

      GROUPING的结果(expr3)的
    +结果为GROUPING(expr2)<< 1
    +结果为GROUPING(expr1)<< 2
    

    以下查询显示如何 GROUPING() 单个参数的结果 组合以进行多参数调用以生成位掩码值:

    MySQL的> SELECT
             name, size, SUM(quantity) AS quantity,
             GROUPING(name) AS grp_name,
             GROUPING(size) AS grp_size,
           GROUPING(name, size) AS grp_all
           FROM t1
           GROUP BY name, size WITH ROLLUP;
    + ------ + ------- + ---------- + ---------- + ---------- +  - -------- +
    | 名字| 尺寸| 数量| grp_name | grp_size | grp_all |
    + ------ + ------- + ---------- + ---------- + ---------- +  - -------- +
    | 球| NULL | 5 | 0 | 0 | 0 |
    | 球| 大| 20 | 0 | 0 | 0 |
    | 球| 小| 10 | 0 | 0 | 0 |
    | 球| NULL | 35 | 0 | 1 | 1 |
    | 箍| NULL | 3 | 0 | 0 | 0 |
    | 箍| 大| 5 | 0 | 0 | 0 |
    | 箍| 小| 15 | 0 | 0 | 0 |
    | 箍| NULL | 23 | 0 | 1 | 1 |
    | NULL | NULL | 58 | 1 | 1 | 3 |
    + ------ + ------- + ---------- + ---------- + ---------- +  - -------- +
    

    对于多个表达式参数, GROUPING() 如果任何表达式表示超级聚合值 ,则 返回值为非零。 GROUPING() 因此,通过使用单个多参数 GROUPING() 调用而不是多个单参数调用, 多参数 语法提供了一种更简单的方法来编写仅返回超级聚合行的早期查询

    MySQL的> SELECT name, size, SUM(quantity) AS quantity
           FROM t1
           GROUP BY name, size WITH ROLLUP
           HAVING GROUPING(name, size) <> 0;
    + ------ + ------ + ---------- +
    | 名字| 尺寸| 数量|
    + ------ + ------ + ---------- +
    | 球| NULL | 35 |
    | 箍| NULL | 23 |
    | NULL | NULL | 58 |
    + ------ + ------ + ---------- +
    

    使用 GROUPING() 受以下限制:

    • 不要将子查询 GROUP BY 表达式用作 GROUPING() 参数,因为匹配可能会失败。 例如,此查询的匹配失败:

      MySQL的> SELECT GROUPING((SELECT MAX(name) FROM t1))
             FROM t1
             GROUP BY (SELECT MAX(name) FROM t1) WITH ROLLUP;
      ERROR 3580(HY000):GROUPING函数的参数#1不在GROUP BY中
      
    • GROUP BY 文字表达式不应该在 HAVING 子句中用作 GROUPING() 参数。 由于当优化评估之间的差异 GROUP BY HAVING ,匹配可能会成功,但 GROUPING() 评价不会产生预期的结果。 考虑这个查询:

      选择AS f1,'w'AS f2
      从T
      GROUP BY f1,f2 WITH ROLLUP
      分组(f2)= 1;
      

      GROUPING() 对于文字常量表达式的评估比对整个 HAVING 子句的 评估更早 并返回0.要检查此类查询是否受到影响, EXPLAIN Impossible having Extra 列中 使用 并查找

    有关详细信息 WITH ROLLUP ,并 GROUPING() 请参阅 第12.20.2,“GROUP BY修改”

  • INET_ATON(expr)

    给定IPv4网络地址的虚线四边形表示为字符串,返回一个整数,表示网络字节顺序(大端)的地址的数值。 如果它不理解它的参数,则 INET_ATON() 返回 NULL

    MySQL的> SELECT INET_ATON('10.0.5.9');
            - > 167773449
    

    对于此示例,返回值计算为10×256 3 + 0×256 2 + 5×256 + 9。

    INET_ATON() 可能会也可能不会返回 NULL 短格式IP地址 的非 结果(例如 '127.1' 表示 '127.0.0.1' )。 因此, INET_ATON() 不应将a用于此类地址。

    注意

    要存储生成的值 INET_ATON() ,请使用 INT UNSIGNED 列而不是 INT 签名。 如果使用带符号列,则无法正确存储与第一个八位字节大于127的IP地址对应的值。 请参见 第11.2.6节“超出范围和溢出处理”

  • INET_NTOA(expr)

    给定网络字节顺序的数字IPv4网络地址,返回地址的点分四字符串表示形式作为连接字符集中的字符串。 如果它不理解它的参数,则 INET_NTOA() 返回 NULL

    MySQL的> SELECT INET_NTOA(167773449);
            - > '10 .0.5.9'
    
  • INET6_ATON(expr)

    给定IPv6或IPv4网络地址作为字符串,返回二进制字符串,该字符串表示网络字节顺序(大端)的地址的数值。 由于数字格式的IPv6地址需要的字节数多于最大的整数类型,因此此函数返回的表示形式具有以下 VARBINARY 数据类型: VARBINARY(16) 用于IPv6地址和 VARBINARY(4) IPv4地址。 如果参数不是有效地址,则 INET6_ATON() 返回 NULL

    以下示例用于 HEX() INET6_ATON() 可打印的形式 显示 结果:

    MySQL的> SELECT HEX(INET6_ATON('fdfe::5a55:caff:fefa:9089'));
            - >'FDFE0000000000005A55CAFFFEFA9089'
    MySQL的> SELECT HEX(INET6_ATON('10.0.5.9'));
            - >'0A000509'
    

    INET6_ATON() 观察有效参数的几个约束。 这些在下面的列表中给出以及示例。

    • 不允许使用尾随区域ID,如 fe80::3%1 fe80::3%eth0

    • 不允许使用尾随网络掩码,如 2001:45f:3:ba::/64 198.51.100.0/24

    • 对于表示IPv4地址的值,仅支持无类地址。 有类别的地址如 198.51.1 被拒绝。 不允许使用尾随端口号,如 198.51.100.2:8080 不允许地址组件中的十六进制数字,如 198.0xa0.1.2 不支持八进制数: 198.51.010.1 被视为 198.51.10.1 ,不是 198.51.8.1 这些IPv4约束也适用于具有IPv4地址部分的IPv6地址,例如IPv4兼容或IPv4映射地址。

    expr 将以数字形式表示 的IPv4地址 作为 INT 转换为 以数字形式表示 的IPv6地址作为 VARBINARY 值,请使用以下表达式:

    INET6_ATON(INET_NTOA(expr))
    

    例如:

    MySQL的> SELECT HEX(INET6_ATON(INET_NTOA(167773449)));
            - >'0A000509'
    
  • INET6_NTOA(expr)

    给定以数字形式表示为二进制字符串的IPv6或IPv4网络地址,将地址的字符串表示形式返回为连接字符集中的字符串。 如果参数不是有效地址,则 INET6_NTOA() 返回 NULL

    INET6_NTOA() 有这些属性:

    • 它不使用操作系统函数来执行转换,因此输出字符串与平台无关。

    • 返回字符串的最大长度为39(4 x 8 + 7)。 鉴于此声明:

      CREATE TABLE t AS SELECT INET6_NTOA(expr)AS c1;
      

      结果表将具有以下定义:

      CREATE TABLE t(c1 VARCHAR(39)CHARACTER SET utf8 DEFAULT NULL);
      
    • 返回字符串使用小写字母表示IPv6地址。

    MySQL的> SELECT INET6_NTOA(INET6_ATON('fdfe::5a55:caff:fefa:9089'));
            - >'fdfe :: 5a55:caff:fefa:9089'
    MySQL的> SELECT INET6_NTOA(INET6_ATON('10.0.5.9'));
            - > '10 .0.5.9'
    
    MySQL的> SELECT INET6_NTOA(UNHEX('FDFE0000000000005A55CAFFFEFA9089'));
            - >'fdfe :: 5a55:caff:fefa:9089'
    MySQL的> SELECT INET6_NTOA(UNHEX('0A000509'));
            - > '10 .0.5.9'
    
  • IS_IPV4(expr)

    如果参数是指定为字符串的有效IPv4地址,则返回1,否则返回0。

    MySQL的> SELECT IS_IPV4('10.0.5.9'), IS_IPV4('10.0.5.256');
            - > 1,0
    

    对于给定的参数,如果 IS_IPV4() 返回1, INET_ATON() (和 INET6_ATON() )将返回非 NULL 相反的陈述不正确:在某些情况下, INET_ATON() 返回非 NULL IS_IPV4() 返回0 返回

    正如前面的评论所暗示的那样, IS_IPV4() INET_ATON() 构成有效IPv4地址的内容 更严格 ,因此对于需要对无效值执行强检查的应用程序可能很有用。 或者,用于 INET6_ATON() 将IPv4地址转换为内部格式并检查 NULL 结果(表示无效的地址)。 关于检查IPv4地址 INET6_ATON() 同样强大 IS_IPV4()

  • IS_IPV4_COMPAT(expr)

    此函数将以数字形式表示的IPv6地址作为二进制字符串,如返回 INET6_ATON() 如果参数是有效的IPv4兼容IPv6地址,则返回1,否则返回0。 IPv4兼容地址具有该形式 ::ipv4_address

    MySQL的> SELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.5.9'));
            - > 1
    MySQL的> SELECT IS_IPV4_COMPAT(INET6_ATON('::ffff:10.0.5.9'));
            - > 0
    

    IPv4兼容地址的IPv4部分也可以使用十六进制表示法表示。 例如, 198.51.100.1 具有此原始十六进制值:

    MySQL的> SELECT HEX(INET6_ATON('198.51.100.1'));
            - >'C6336401'
    

    以IPv4兼容的形式表示, ::198.51.100.1 相当于 ::c0a8:0001 或(没有前导零) ::c0a8:1

    mysql> SELECT
        - >   IS_IPV4_COMPAT(INET6_ATON('::198.51.100.1')),
        - >   IS_IPV4_COMPAT(INET6_ATON('::c0a8:0001')),
        - >  IS_IPV4_COMPAT(INET6_ATON('::c0a8:1'));
            - > 1,1,1
    
  • IS_IPV4_MAPPED(expr)

    此函数将以数字形式表示的IPv6地址作为二进制字符串,如返回 INET6_ATON() 如果参数是有效的IPv4映射IPv6地址,则返回1,否则返回0。 IPv4映射地址具有该形式 ::ffff:ipv4_address

    MySQL的> SELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.5.9'));
            - > 0
    MySQL的> SELECT IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.5.9'));
            - > 1
    

    IS_IPV4_COMPAT() IPv4映射地址的IPv4部分一样,也可以使用十六进制表示法表示:

    mysql> SELECT
        - >   IS_IPV4_MAPPED(INET6_ATON('::ffff:198.51.100.1')),
        - >   IS_IPV4_MAPPED(INET6_ATON('::ffff:c0a8:0001')),
        - >  IS_IPV4_MAPPED(INET6_ATON('::ffff:c0a8:1'));
            - > 1,1,1
    
  • IS_IPV6(expr)

    如果参数是指定为字符串的有效IPv6地址,则返回1,否则返回0。 此功能不会将IPv4地址视为有效的IPv6地址。

    MySQL的> SELECT IS_IPV6('10.0.5.9'), IS_IPV6('::1');
            - > 0,1
    

    对于给定的参数,如果 IS_IPV6() 返回1, INET6_ATON() 则返回非 NULL

  • IS_UUID(string_uuid)

    如果该参数是一个有效的字符串格式的UUID,0如果参数是不是有效的UUID,并返回1 NULL 如果该参数 NULL

    有效 表示该值采用可以解析的格式。 也就是说,它具有正确的长度并且仅包含允许的字符(任何字母表中的十六进制数字,以及可选的破折号和花括号)。 这种格式最常见:

    AAAAAAAA  -  BBBB  -  CCCC-DDDD-eeeeeeeeeeee
    

    这些其他格式也是允许的:

    aaaaaaaabbbbccccddddeeeeeeeeeeee
    {AAAAAAAA-BBBB-CCCC-DDDD-eeeeeeeeeeee}
    

    有关值内字段的含义,请参阅 UUID() 函数说明。

    MySQL的> SELECT IS_UUID('6ccd780c-baba-1026-9564-5b8c656024db');
    + ------------------------------------------------- +
    | IS_UUID('6ccd780c-baba-1026-9564-5b8c656024db')|
    + ------------------------------------------------- +
    | 1 |
    + ------------------------------------------------- +
    MySQL的> SELECT IS_UUID('6CCD780C-BABA-1026-9564-5B8C656024DB');
    + ------------------------------------------------- +
    | IS_UUID('6CCD780C-BABA-1026-9564-5B8C656024DB')|
    + ------------------------------------------------- +
    | 1 |
    + ------------------------------------------------- +
    MySQL的> SELECT IS_UUID('6ccd780cbaba102695645b8c656024db');
    + --------------------------------------------- +
    | IS_UUID('6ccd780cbaba102695645b8c656024db')|
    + --------------------------------------------- +
    | 1 |
    + --------------------------------------------- +
    MySQL的> SELECT IS_UUID('{6ccd780c-baba-1026-9564-5b8c656024db}');
    + ------------------------------------------------- -  +
    | IS_UUID('{6ccd780c-baba-1026-9564-5b8c656024db}')|
    + ------------------------------------------------- -  +
    | 1 |
    + ------------------------------------------------- -  +
    MySQL的> SELECT IS_UUID('6ccd780c-baba-1026-9564-5b8c6560');
    + --------------------------------------------- +
    | IS_UUID('6ccd780c-baba-1026-9564-5b8c6560')|
    + --------------------------------------------- +
    | 0 |
    + --------------------------------------------- +
    MySQL的> SELECT IS_UUID(RAND());
    + ----------------- +
    | IS_UUID(RAND())|
    + ----------------- +
    | 0 |
    + ----------------- +
    
  • MASTER_POS_WAIT(log_name,log_pos[,timeout][,channel])

    此功能对于控制主/从同步很有用。 它会阻塞,直到从属设备已读取并将所有更新应用到主日志中的指定位置。 返回值是从站必须等待前进到指定位置的日志事件数。 NULL 如果未启动从属SQL线程,未初始化从属主信息,参数不正确或发生错误,则 函数返回 -1 如果超出超时 ,则返回 如果从属SQL线程在 MASTER_POS_WAIT() 等待时 停止, 则该函数返回 NULL 如果从站超过指定位置,则该函数立即返回。

    上一个多线程从机,功能等待,直到由所述设置的限制期满 slave_checkpoint_group slave_checkpoint_period 系统变量,当检查点操作被称为更新从站的状态。 因此,根据系统变量的设置,函数可能会在达到指定位置后返回一段时间。

    如果 timeout 指定 值,则 MASTER_POS_WAIT() timeout 秒数过后 停止等待 timeout 必须大于0; 零或负 timeout 意味着没有超时。

    可选 channel 值使您可以命名该函数适用的复制通道。 有关 更多信息 请参见 第17.2.3节“复制通道”

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • NAME_CONST(name,value)

    返回给定值。 用于生成结果集列时, NAME_CONST() 会使列具有给定名称。 参数应该是常量。

    MySQL的> SELECT NAME_CONST('myname', 14);
    + -------- +
    | myname |
    + -------- +
    | 14 |
    + -------- +
    

    此功能仅供内部使用。 服务器在从包含对本地程序变量的引用的存储程序中编写语句时使用它,如 第24.7节“存储程序二进制日志记录”中所述 您可能会在 mysqlbinlog 的输出中看到此函数

    对于您的应用程序,您可以使用简单的别名获得与刚刚显示的示例完全相同的结果,如下所示:

    MySQL的> SELECT 14 AS myname;
    + -------- +
    | myname |
    + -------- +
    | 14 |
    + -------- +
    1排(0.00秒)
    

    有关列别名的更多信息 请参见 第13.2.10节“SELECT语法”

  • SLEEP(duration)

    休眠(暂停) duration 参数 给出的秒数 ,然后返回0.持续时间可能有一个小数部分。 如果参数为 NULL 或为负,则 SLEEP() 在严格SQL模式下生成警告或错误。

    当睡眠正常返回(没有中断)时,它返回0:

    MySQL的> SELECT SLEEP(1000);
    + ------------- +
    | 睡眠(1000)|
    + ------------- +
    | 0 |
    + ------------- +
    

    何时 SLEEP() 是被中断的查询调用的唯一内容,它返回1并且查询本身不返回错误。 无论查询是被终止还是超时,都是如此:

    • 使用 KILL QUERY 另一个会话 中断此语句

      MySQL的> SELECT SLEEP(1000);
      + ------------- +
      | 睡眠(1000)|
      + ------------- +
      | 1 |
      + ------------- +
      
    • 超时会中断此声明:

      MySQL的> SELECT /*+ MAX_EXECUTION_TIME(1) */ SLEEP(1000);
      + ------------- +
      | 睡眠(1000)|
      + ------------- +
      | 1 |
      + ------------- +
      

    如果 SLEEP() 只是查询中断的一部分,查询将返回错误:

    • 使用 KILL QUERY 另一个会话 中断此语句

      MySQL的> SELECT 1 FROM t1 WHERE SLEEP(1000);
      错误1317(70100):查询执行被中断
      
    • 超时会中断此声明:

      MySQL的> SELECT /*+ MAX_EXECUTION_TIME(1000) */ 1 FROM t1 WHERE SLEEP(1000);
      ERROR 3024(HY000):查询执行被中断,最大语句
      超出执行时间
      

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • UUID()

    返回根据RFC 4122 A Universally Unique IDentifier(UUID)URN命名空间 生成 的通用唯一标识符(UUID) http://www.ietf.org/rfc/rfc4122.txt )。

    UUID被设计为在空间和时间上全球唯一的数字。 UUID() 预计 两次调用将 生成两个不同的值,即使这些调用是在两个彼此未连接的独立设备上执行的。

    警告

    虽然 UUID() 价值观是独一无二的,但它们不一定是不可评论的或不可预测的。 如果需要不可预测性,则应以其他方式生成UUID值。

    UUID() 返回符合RFC 4122中描述的UUID版本1的值。该值是128位数字,表示为 utf8 格式为五个十六进制数字 字符串 aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee

    • 前三个数字是从时间戳的低,中,高部分生成的。 高部分还包括UUID版本号。

    • 如果时间戳值失去单调性(例如,由于夏令时),则第四个数字保留时间唯一性。

    • 第五个数字是提供空间唯一性的IEEE 802节点号。 如果后者不可用,则替换随机数(例如,因为主机设备没有以太网卡,或者不知道如何在主机操作系统上找到接口的硬件地址)。 在这种情况下,无法保证空间唯一性。 然而,碰撞应该具有 非常 低的概率。

      仅在FreeBSD,Linux和Windows上考虑接口的MAC地址。 在其他操作系统上,MySQL使用随机生成的48位数字。

    MySQL的> SELECT UUID();
            - >'6ccd780c-baba-1026-9564-5b8c656024db'
    

    要在字符串和二进制UUID值之间进行转换,请使用 UUID_TO_BIN() BIN_TO_UUID() 函数。 要检查字符串是否为有效的UUID值,请使用该 IS_UUID() 函数。

    此函数对于基于语句的复制不安全。 如果在 binlog_format 设置 为时使用此功能,则会记录警告 STATEMENT

  • UUID_SHORT()

    通用标识符作为64位无符号整数返回。 返回的值 UUID_SHORT() UUID() 函数 返回的字符串格式128位标识符 不同,并且具有不同的唯一性属性。 UUID_SHORT() 如果满足以下条件 则保证 是唯一的:

    • server_id 当前服务器的值介于0和255之间,您的设置主从服务器中是唯一的

    • 您不会在 mysqld restarts 之间设置服务器主机的系统时间

    • UUID_SHORT() mysqld 重启 之间, 平均每秒 调用的 次数少于1600万次

    UUID_SHORT() 返回值的构造是这样的:

      (server_id&255)<< 56
    +(server_startup_time_in_seconds << 24)
    + incremented_variable ++;
    
    MySQL的> SELECT UUID_SHORT();
            - > 92395783831158784
    
    注意

    UUID_SHORT() 不适用于基于语句的复制。

  • UUID_TO_BIN(string_uuid) UUID_TO_BIN(string_uuid, swap_flag)

    将字符串UUID转换为二进制UUID并返回结果。 IS_UUID() 函数描述列出了允许的字符串UUID格式。)返回二进制UUID是一个 VARBINARY(16) 值。 如果是UUID参数 NULL ,则返回值为 NULL 如果任何参数无效,则会发生错误。

    UUID_TO_BIN() 需要一个或两个参数:

    • 单参数形式采用字符串UUID值。 二进制结果与字符串参数的顺序相同。

    • 双参数形式采用字符串UUID值和标志值:

      • 如果 swap_flag 为0,则双参数形式等效于单参数形式。 二进制结果与字符串参数的顺序相同。

      • 如果 swap_flag 为1,则返回值的格式不同:交换时间低和时间高的部分(分别为第一组和第三组十六进制数字)。 这会将更快速变化的部分向右移动,并且如果结果存储在索引列中,则可以提高索引效率。

    时间 - 部分交换假定使用UUID版本1值,例如由 UUID() 函数 生成的 值。 对于不遵循版本1格式的其他方法生成的UUID值,时间 - 部分交换不会带来任何好处。 有关版本1格式的详细信息,请参阅 UUID() 功能说明。

    假设您具有以下字符串UUID值:

    MySQL的> SET @uuid = '6ccd780c-baba-1026-9564-5b8c656024db';
    

    要使用或不使用时间 - 部分交换将字符串UUID转换为二进制,请使用 UUID_TO_BIN()

    
    MySQL的> SELECT HEX(UUID_TO_BIN(@uuid));
    + ---------------------------------- +
    | HEX(UUID_TO_BIN(@uuid))|
    + ---------------------------------- +
    | 6CCD780CBABA102695645B8C656024DB |
    + ---------------------------------- +
    MySQL的> SELECT HEX(UUID_TO_BIN(@uuid, 0));
    + ---------------------------------- +
    | HEX(UUID_TO_BIN(@ uuid,0))|
    + ---------------------------------- +
    | 6CCD780CBABA102695645B8C656024DB |
    + ---------------------------------- +
    MySQL的> SELECT HEX(UUID_TO_BIN(@uuid, 1));
    + ---------------------------------- +
    | HEX(UUID_TO_BIN(@ uuid,1))|
    + ---------------------------------- +
    | 1026BABA6CCD780C95645B8C656024DB |
    + ---------------------------------- +
    

    要将返回的二进制UUID转换为 UUID_TO_BIN() 字符串UUID,请使用 BIN_TO_UUID() 如果通过 UUID_TO_BIN() 使用第二个参数1来交换时间部分来 生成二进制UUID ,则还应该传递第二个参数1, BIN_TO_UUID() 以便在将二进制UUID转换回字符串UUID时取消 交换时间部分

    
    MySQL的> SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid));
    + -------------------------------------- +
    | BIN_TO_UUID(UUID_TO_BIN(@ uuid))|
    + -------------------------------------- +
    | 6ccd780c-baba-1026-9564-5b8c656024db |
    + -------------------------------------- +
    MySQL的> SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,0),0);
    + -------------------------------------- +
    | BIN_TO_UUID(UUID_TO_BIN(@ uuid,0),0)|
    + -------------------------------------- +
    | 6ccd780c-baba-1026-9564-5b8c656024db |
    + -------------------------------------- +
    MySQL的> SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,1),1);
    + -------------------------------------- +
    | BIN_TO_UUID(UUID_TO_BIN(@ uuid,1),1)|
    + -------------------------------------- +
    | 6ccd780c-baba-1026-9564-5b8c656024db |
    + -------------------------------------- +
    

    如果两个方向的转换使用时间 - 部分交换不相同,则原始UUID将无法正确恢复:

    
    MySQL的> SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,0),1);
    + -------------------------------------- +
    | BIN_TO_UUID(UUID_TO_BIN(@ uuid,0),1)|
    + -------------------------------------- +
    | baba1026-780c-6ccd-9564-5b8c656024db |
    + -------------------------------------- +
    MySQL的> SELECT BIN_TO_UUID(UUID_TO_BIN(@uuid,1),0);
    + -------------------------------------- +
    | BIN_TO_UUID(UUID_TO_BIN(@ uuid,1),0)|
    + -------------------------------------- +
    | 1026baba-6ccd-780c-9564-5b8c656024db |
    + -------------------------------------- +
    
  • VALUES(col_name)

    INSERT ... ON DUPLICATE KEY UPDATE 语句中,您可以使用 子句中 函数 来引用 语句部分中的 列值 换句话说, 子句中引用了 将插入 的值 ,没有发生重复键冲突。 此功能在多行插入中特别有用。 函数仅在 语句 子句中 有意义 否则 返回 请参见 第13.2.6.2节“INSERT ... ON DUPLICATE KEY UPDATE语法” VALUES(col_name) UPDATE INSERT VALUES(col_name) UPDATE col_name VALUES() ON DUPLICATE KEY UPDATE INSERT NULL

    mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
        - >ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
    

12.25精度数学

MySQL提供对精确数学的支持:数值处理可以产生极其准确的结果,并且可以高度控制无效值。 精确数学基于以下两个特征:

  • 控制服务器接受或拒绝无效数据的严格程度的SQL模式。

  • 用于定点算术的MySQL库。

这些功能对数值运算有几个含义,并提供与标准SQL的高度兼容性:

  • 精确计算 :对于精确值数字,计算不会引入浮点错误。 相反,使用精确的精度。 例如,MySQL将一个数字视为 .0001 精确值而不是近似值,并将其相加10,000次会产生精确的结果 1 ,而不是仅仅 接近 1的值。

  • 明确定义的舍入行为 :对于精确值数字,结果 ROUND() 取决于其参数,而不取决于环境因素,例如底层C库的工作方式。

  • 平台独立性 :对于不同平台(如Windows和Unix),精确数值的操作是相同的。

  • 控制无效值的处理 :可以检测到溢出和除零,可以将其视为错误。 例如,您可以将对于列而言太大的值视为错误,而不是将值截断为位于列的数据类型的范围内。 类似地,您可以将除以零视为错误而不是作为产生结果的操作 NULL 选择采用哪种方法取决于服务器SQL模式的设置。

以下讨论涵盖精确数学如何工作的几个方面,包括可能与旧应用程序不兼容。 最后,给出了一些示例,演示了MySQL如何精确处理数值运算。 有关控制SQL模式的信息,请参见 第5.1.11节“服务器SQL模式”

12.25.1数值的类型

精确值运算的精度数学范围包括精确值数据类型(整数和 DECIMAL 类型)和精确值数字文字。 近似值数据类型和数字文字作为浮点数处理。

精确值数字文字具有整数部分或小数部分,或两者都有。 他们可能会签名。 例如: 1 .2 3.4 -5 -6.78 +9.10

近似值数字文字用科学记数法表示,带有尾数和指数。 可以签署任一部分或两部分。 例如: 1.2E3 1.2E-3 -1.2E3 -1.2E-3

两个看起来相似的数字可能会有不同的对待。 例如, 2.34 是精确值(定点)数,而是 2.34E0 近似值(浮点数)。

The DECIMAL data type is a fixed-point type and calculations are exact. In MySQL, the DECIMAL type has several synonyms: NUMERIC, DEC, FIXED. The integer types also are exact-value types.

The FLOAT and DOUBLE data types are floating-point types and calculations are approximate. In MySQL, types that are synonymous with FLOAT or DOUBLE are DOUBLE PRECISION and REAL.

12.25.2 DECIMAL Data Type Characteristics

This section discusses the characteristics of the DECIMAL data type (and its synonyms), with particular regard to the following topics:

  • Maximum number of digits

  • Storage format

  • Storage requirements

  • The nonstandard MySQL extension to the upper range of DECIMAL columns

The declaration syntax for a DECIMAL column is DECIMAL(M,D). The ranges of values for the arguments are as follows:

  • M is the maximum number of digits (the precision). It has a range of 1 to 65.

  • D is the number of digits to the right of the decimal point (the scale). It has a range of 0 to 30 and must be no larger than M.

If D is omitted, the default is 0. If M is omitted, the default is 10.

The maximum value of 65 for M means that calculations on DECIMAL values are accurate up to 65 digits. This limit of 65 digits of precision also applies to exact-value numeric literals, so the maximum range of such literals differs from before.

Values for DECIMAL columns are stored using a binary format that packs nine decimal digits into 4 bytes. The storage requirements for the integer and fractional parts of each value are determined separately. Each multiple of nine digits requires 4 bytes, and any remaining digits left over require some fraction of 4 bytes. The storage required for remaining digits is given by the following table.

Leftover Digits Number of Bytes
0 0
1–2 1
3–4 2
5–6 3
7–9 4

For example, a DECIMAL(18,9) column has nine digits on either side of the decimal point, so the integer part and the fractional part each require 4 bytes. A DECIMAL(20,6) column has fourteen integer digits and six fractional digits. The integer digits require four bytes for nine of the digits and 3 bytes for the remaining five digits. The six fractional digits require 3 bytes.

DECIMAL columns do not store a leading + character or - character or leading 0 digits. If you insert +0003.1 into a DECIMAL(5,1) column, it is stored as 3.1. For negative numbers, a literal - character is not stored.

DECIMAL columns do not permit values larger than the range implied by the column definition. For example, a DECIMAL(3,0) column supports a range of -999 to 999. A DECIMAL(M,D) column permits up to M - D digits to the left of the decimal point.

The SQL standard requires that the precision of NUMERIC(M,D) be exactly M digits. For DECIMAL(M,D), the standard requires a precision of at least M digits but permits more. In MySQL, DECIMAL(M,D) and NUMERIC(M,D) are the same, and both have a precision of exactly M digits.

For a full explanation of the internal format of DECIMAL values, see the file strings/decimal.c in a MySQL source distribution. The format is explained (with an example) in the decimal2bin() function.

12.25.3 Expression Handling

With precision math, exact-value numbers are used as given whenever possible. For example, numbers in comparisons are used exactly as given without a change in value. In strict SQL mode, for INSERT into a column with an exact data type (DECIMAL or integer), a number is inserted with its exact value if it is within the column range. When retrieved, the value should be the same as what was inserted. (If strict SQL mode is not enabled, truncation for INSERT is permissible.)

Handling of a numeric expression depends on what kind of values the expression contains:

  • If any approximate values are present, the expression is approximate and is evaluated using floating-point arithmetic.

  • If no approximate values are present, the expression contains only exact values. If any exact value contains a fractional part (a value following the decimal point), the expression is evaluated using DECIMAL exact arithmetic and has a precision of 65 digits. The term exact is subject to the limits of what can be represented in binary. For example, 1.0/3.0 can be approximated in decimal notation as .333..., but not written as an exact number, so (1.0/3.0)*3.0 does not evaluate to exactly 1.0.

  • Otherwise, the expression contains only integer values. The expression is exact and is evaluated using integer arithmetic and has a precision the same as BIGINT (64 bits).

If a numeric expression contains any strings, they are converted to double-precision floating-point values and the expression is approximate.

Inserts into numeric columns are affected by the SQL mode, which is controlled by the sql_mode system variable. (See Section 5.1.11, “Server SQL Modes”.) The following discussion mentions strict mode (selected by the STRICT_ALL_TABLES or STRICT_TRANS_TABLES mode values) and ERROR_FOR_DIVISION_BY_ZERO. To turn on all restrictions, you can simply use TRADITIONAL mode, which includes both strict mode values and ERROR_FOR_DIVISION_BY_ZERO:

SET sql_mode='TRADITIONAL';

If a number is inserted into an exact type column (DECIMAL or integer), it is inserted with its exact value if it is within the column range and precision.

If the value has too many digits in the fractional part, rounding occurs and a note is generated. Rounding is done as described in Section 12.25.4, “Rounding Behavior”. Truncation due to rounding of the fractional part is not an error, even in strict mode.

If the value has too many digits in the integer part, it is too large (out of range) and is handled as follows:

  • If strict mode is not enabled, the value is truncated to the nearest legal value and a warning is generated.

  • If strict mode is enabled, an overflow error occurs.

Underflow is not detected, so underflow handling is undefined.

For inserts of strings into numeric columns, conversion from string to number is handled as follows if the string has nonnumeric contents:

  • A string that does not begin with a number cannot be used as a number and produces an error in strict mode, or a warning otherwise. This includes the empty string.

  • A string that begins with a number can be converted, but the trailing nonnumeric portion is truncated. If the truncated portion contains anything other than spaces, this produces an error in strict mode, or a warning otherwise.

By default, division by zero produces a result of NULL and no warning. By setting the SQL mode appropriately, division by zero can be restricted.

With the ERROR_FOR_DIVISION_BY_ZERO SQL mode enabled, MySQL handles division by zero differently:

  • If strict mode is not enabled, a warning occurs.

  • If strict mode is enabled, inserts and updates involving division by zero are prohibited, and an error occurs.

In other words, inserts and updates involving expressions that perform division by zero can be treated as errors, but this requires ERROR_FOR_DIVISION_BY_ZERO in addition to strict mode.

Suppose that we have this statement:

INSERT INTO t SET i = 1/0;

This is what happens for combinations of strict and ERROR_FOR_DIVISION_BY_ZERO modes.

sql_mode Value Result
'' (Default) No warning, no error; i is set to NULL.
strict No warning, no error; i is set to NULL.
ERROR_FOR_DIVISION_BY_ZERO Warning, no error; i is set to NULL.
strict,ERROR_FOR_DIVISION_BY_ZERO Error condition; no row is inserted.

12.25.4 Rounding Behavior

This section discusses precision math rounding for the ROUND() function and for inserts into columns with exact-value types (DECIMAL and integer).

The ROUND() function rounds differently depending on whether its argument is exact or approximate:

  • For exact-value numbers, ROUND() uses the round half up rule: A value with a fractional part of .5 or greater is rounded up to the next integer if positive or down to the next integer if negative. (In other words, it is rounded away from zero.) A value with a fractional part less than .5 is rounded down to the next integer if positive or up to the next integer if negative. (In other words, it is rounded toward zero.)

  • For approximate-value numbers, the result depends on the C library. On many systems, this means that ROUND() uses the round to nearest even rule: A value with a fractional part exactly half way between two integers is rounded to the nearest even integer.

The following example shows how rounding differs for exact and approximate values:

mysql> SELECT ROUND(2.5), ROUND(25E-1);
+------------+--------------+
| ROUND(2.5) | ROUND(25E-1) |
+------------+--------------+
| 3          |            2 |
+------------+--------------+

For inserts into a DECIMAL or integer column, the target is an exact data type, so rounding uses round half away from zero, regardless of whether the value to be inserted is exact or approximate:

mysql> CREATE TABLE t (d DECIMAL(10,0));
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t VALUES(2.5),(2.5E0);
Query OK, 2 rows affected, 2 warnings (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 2

mysql> SHOW WARNINGS;
+-------+------+----------------------------------------+
| Level | Code | Message                                |
+-------+------+----------------------------------------+
| Note  | 1265 | Data truncated for column 'd' at row 1 |
| Note  | 1265 | Data truncated for column 'd' at row 2 |
+-------+------+----------------------------------------+
2 rows in set (0.00 sec)

mysql> SELECT d FROM t;
+------+
| d    |
+------+
|    3 |
|    3 |
+------+
2 rows in set (0.00 sec)

The SHOW WARNINGS statement displays the notes that are generated by truncation due to rounding of the fractional part. Such truncation is not an error, even in strict SQL mode (see Section 12.25.3, “Expression Handling”).

12.25.5 Precision Math Examples

This section provides some examples that show precision math query results in MySQL. These examples demonstrate the principles described in Section 12.25.3, “Expression Handling”, and Section 12.25.4, “Rounding Behavior”.

Example 1. Numbers are used with their exact value as given when possible:

mysql> SELECT (.1 + .2) = .3;
+----------------+
| (.1 + .2) = .3 |
+----------------+
|              1 |
+----------------+

For floating-point values, results are inexact:

mysql> SELECT (.1E0 + .2E0) = .3E0;
+----------------------+
| (.1E0 + .2E0) = .3E0 |
+----------------------+
|                    0 |
+----------------------+

Another way to see the difference in exact and approximate value handling is to add a small number to a sum many times. Consider the following stored procedure, which adds .0001 to a variable 1,000 times.

CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE d DECIMAL(10,4) DEFAULT 0;
  DECLARE f FLOAT DEFAULT 0;
  WHILE i < 10000 DO
    SET d = d + .0001;
    SET f = f + .0001E0;
    SET i = i + 1;
  END WHILE;
  SELECT d, f;
END;

The sum for both d and f logically should be 1, but that is true only for the decimal calculation. The floating-point calculation introduces small errors:

+--------+------------------+
| d      | f                |
+--------+------------------+
| 1.0000 | 0.99999999999991 |
+--------+------------------+

Example 2. Multiplication is performed with the scale required by standard SQL. That is, for two numbers X1 and X2 that have scale S1 and S2, the scale of the result is S1 + S2:

mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
| 0.0001    |
+-----------+

Example 3. Rounding behavior for exact-value numbers is well-defined:

Rounding behavior (for example, with the ROUND() function) is independent of the implementation of the underlying C library, which means that results are consistent from platform to platform.

  • Rounding for exact-value columns (DECIMAL and integer) and exact-valued numbers uses the round half away from zero rule. A value with a fractional part of .5 or greater is rounded away from zero to the nearest integer, as shown here:

    mysql> SELECT ROUND(2.5), ROUND(-2.5);
    +------------+-------------+
    | ROUND(2.5) | ROUND(-2.5) |
    +------------+-------------+
    | 3          | -3          |
    +------------+-------------+
    
  • Rounding for floating-point values uses the C library, which on many systems uses the round to nearest even rule. A value with a fractional part exactly half way between two integers is rounded to the nearest even integer:

    mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0);
    +--------------+---------------+
    | ROUND(2.5E0) | ROUND(-2.5E0) |
    +--------------+---------------+
    |            2 |            -2 |
    +--------------+---------------+
    

Example 4. In strict mode, inserting a value that is out of range for a column causes an error, rather than truncation to a legal value.

When MySQL is not running in strict mode, truncation to a legal value occurs:

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t SET i = 128;
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SELECT i FROM t;
+------+
| i    |
+------+
|  127 |
+------+
1 row in set (0.00 sec)

However, an error occurs if strict mode is in effect:

mysql> SET sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 128;
ERROR 1264(22003):超出了第1行第'i列'的范围值

MySQL的> SELECT i FROM t;
空集(0.00秒)

示例5 :在严格模式下并使用 ERROR_FOR_DIVISION_BY_ZERO set,除以零会导致错误,而不是结果 NULL

在非严格模式下,除以零的结果是 NULL

MySQL的> SET sql_mode='';
查询OK,0行受影响(0.01秒)

MySQL的> CREATE TABLE t (i TINYINT);
查询正常,0行受影响(0.00秒)

MySQL的> INSERT INTO t SET i = 1 / 0;
查询正常,1行受影响(0.00秒)

MySQL的> SELECT i FROM t;
+ ------ +
| 我|
+ ------ +
| NULL |
+ ------ +
1排(0.03秒)

但是,如果正确的SQL模式生效,除以零是错误的:

MySQL的> SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
查询正常,0行受影响(0.00秒)

MySQL的> CREATE TABLE t (i TINYINT);
查询正常,0行受影响(0.00秒)

MySQL的> INSERT INTO t SET i = 1 / 0;
ERROR 1365(22012):除以0

MySQL的> SELECT i FROM t;
空集(0.01秒)

例6 精确值文字被评估为精确值。

使用浮点计算近似值文字,但精确值文字的处理方式如下 DECIMAL

MySQL的> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
查询OK,1行受影响(0.01秒)
记录:1个重复:0警告:0

MySQL的> DESCRIBE t;
+ ------- + ------------ + ------ + ----- + ---- ----- + ------- +
| 领域| 输入| 空| 钥匙| 默认| 额外的|
+ ------- + ------------ + ------ + ----- + ---- ----- + ------- +
| a | 十进制(2,1)无符号| 没有| | 0.0 | |
| b | 双| 没有| | 0 | |
+ ------- + ------------ + ------ + ----- + ---- ----- + ------- +
2行(0.01秒)

例7 如果聚合函数的参数是精确的数字类型,则结果也是精确的数字类型,其比例至少为参数的比例。

请考虑以下陈述:

mysql> CREATE TABLE t (i INT, d DECIMAL, f FLOAT);
mysql> INSERT INTO t VALUES(1,1,1);
mysql>CREATE TABLE y SELECT AVG(i), AVG(d), AVG(f) FROM t;

结果是浮点参数只有一个double。 对于精确类型参数,结果也是精确类型:

MySQL的> DESCRIBE y;
+ -------- + -------- + ------ + ------ + --------- +  - ------ +
| 领域| 输入| 空| 钥匙| 默认| 额外的|
+ -------- + -------- + ------ + ------ + --------- +  - ------ +
| AVG(i)| 十进制(14,4)| 是的| | NULL | |
| AVG(d)| 十进制(14,4)| 是的| | NULL | |
| AVG(f)| 双| 是的| | NULL | |
+ -------- + -------- + ------ + ------ + --------- +  - ------ +

结果是浮点参数只有一个double。 对于精确类型参数,结果也是精确类型。

原文