【发布时间】:2022-01-09 20:18:30
【问题描述】:
我最近将 MySQL 数据存储从某个令人讨厌的多年过时版本升级到 8.0.26。
在一个特定的表中,我存储与每条记录相关的日期,但偶尔会有未知的未来日期。这些始终以 YYYY-MM-?? 格式存储,因此字段类型是 VARCHAR(10) 而不是 DATE,如果可以始终准确则可以预期。 否则字段数据是可靠的 YYYY-MM-DD。
但是,对这些数据进行排序的查询最近已按预期停止工作,MySQL 认为这种未知日期应该在确切日期之前排序。
查询归结为如下内容:SELECT * FROM table WHERE date_field <= CURDATE()
(今天是 12 月 3 日,所以 CURDATE 的计算结果为 2021-12-03。使用文字字符串值 2021-12-03 而不是 CURDATE 函数时也会发生同样的情况,所以这绝对是一个排序问题而不是数据类型之间的冲突。)
在之前运行的那些旧 MySQL 版本中,2021-12-??将评估高于/大于 03 之类的确切日期,因此不会返回。这也符合ASCII sort ordering 的预期。但是,现在有这样的吗?记录也被返回,问号字符显然被排序为之前/小于一个数字。
目前,我可以通过在查询中使用 REPLACE 来强制执行正确和预期的行为,但这是过程繁重、丑陋且不方便:SELECT * FROM table WHERE REPLACE(date_field , '??', '99') <= CURDATE()
谁能解释为什么会发生这种情况以及我应该如何纠正它?考虑到标准的 ASCII 排序和以前的经验(多年的经验),它可能是一个 MySQL 错误吗?
编辑:感谢最初的回复指出我的整理。该数据库几乎完全使用纯英语,只有偶尔的口音(等),所以我过去很少需要触摸默认设置。
根据 ProGu 和 Álvaro González 的回复,我已经开始四处挖掘并测试不涉及实际表/数据库的查询确实按建议返回。但是,一旦我尝试在真实表上运行任何东西,它的行为仍然不符合预期。
表在 InnoDB 上,整个数据库的所有表和(文本)字段都是 utf8mb4/utf8mb4_0900_ai_ci。我已经尝试在查询级别和通过更改实际的表和字段排序规则来强制排序规则,但无论我选择哪个,总是返回讨厌的 2021-12-??。我尝试了各种查询格式都无济于事:
SELECT * FROM table WHERE date_field <= CURDATE() ORDER BY date_field COLLATE utf8mb4_0900_ai_ci DESC
SELECT * FROM table WHERE date_field COLLATE utf8mb4_0900_ai_ci <= CURDATE() COLLATE utf8mb4_0900_ai_ci ORDER BY date_field COLLATE utf8mb4_0900_ai_ci DESC
基于Álvaro的代码测试,正确返回2021-12-03:
with sample_data (sample_value) as (
select '2021-12-??'
union all select '2021-12-03'
)
select *
from sample_data
where sample_value <= CURDATE()
order by sample_value COLLATE utf8mb4_0900_ai_ci DESC LIMIT 1;
我的整理经验不足吗?我错过了一些非常明显的事情吗?
编辑 2
所有表格和所有文本列(加上连接)已设置为utf8mb4 和utf8mb4_0900_ai_ci。
参见this DB Fiddle,它也错误地返回2021-12-??,显然小于比较值(当前日期,2021-12-08)。我找不到返回真正较小值的排序规则(示例数据中的2021-10-31)。
回到 Rick 最初的回复:
SELECT "2021-12-??" < "2021-12-03"
这将返回 1,即 03 大于 ??。为什么? ASCII 排序很清楚,数字字符在 - 小于 - 问号字符之前。
在我的帖子的原始版本中,在我看来,当 MySQL 使用数字作为字符串而不是 int 时,字符排序是错误的。
比较:
SELECT "?" < "0"; = 1
SELECT "?" < 0; = 0
【问题讨论】:
-
这是字符集问题,dbfiddle.uk/…
-
@ProGu 这有 99% 以上的可能性是答案。写下来。
-
你的意思是 YYYY 而不是 YYY?
-
我当然做到了!谢谢瑞克。
-
说实话,我不完全确定你最新的 sn-p 试图说明什么。但肯定还有一个与
curdate()相关的问题。我已编辑我的答案以添加相关信息。