存储为DD/MM/YYYY格式VARCHAR的PHP日期需在SQL查询中按ASC排序
嘿,这种遗留问题确实头疼,不过不用慌,有几个靠谱的解决方案能帮你实现正确的日期排序,完全不需要修改现有数千条记录:
因为你的日期是以DD/MM/YYYY格式存在VARCHAR字段里的,直接用ORDER BY order_date ASC会按字符串字典序排序,这和实际的日期顺序完全不符(比如05/12/2021会排在10/01/2020前面,因为字符串开头的0比1小)。所以我们需要把字符串转换成能正确反映日期顺序的格式,再进行排序。
方案1:转换为日期类型后排序(首推)
几乎所有主流数据库都提供了字符串转日期的内置函数,转换后再排序就能得到完全正确的升序结果。
MySQL/MariaDB 写法
用STR_TO_DATE()函数解析字符串:
SELECT * FROM your_table ORDER BY STR_TO_DATE(order_date, '%d/%m/%Y') ASC;
这里%d对应两位日期、%m对应两位月份、%Y对应四位年份,函数会自动把你的字符串转成标准DATE类型,排序逻辑自然和真实日期一致。
SQL Server 写法
用CONVERT()函数指定格式代码(103对应DD/MM/YYYY):
SELECT * FROM your_table ORDER BY CONVERT(DATE, order_date, 103) ASC;
Oracle 写法
用TO_DATE()函数指定格式:
SELECT * FROM your_table ORDER BY TO_DATE(order_date, 'DD/MM/YYYY') ASC;
方案2:拼接为YYYYMMDD字符串排序
如果因为某些限制不能用日期转换函数,还可以手动拆分字符串,重新拼接成YYYYMMDD格式的字符串——这种格式的字符串字典序和日期顺序是完全一致的。
通用写法(MySQL/SQL Server都适用)
SELECT * FROM your_table ORDER BY CONCAT( SUBSTRING(order_date, 7, 4), -- 提取年份(第7位开始的4个字符) SUBSTRING(order_date, 4, 2), -- 提取月份(第4位开始的2个字符) SUBSTRING(order_date, 1, 2) -- 提取日期(第1位开始的2个字符) ) ASC;
拼接后得到的是YYYYMMDD格式的字符串,直接排序就会和日期升序完全匹配。
性能优化小贴士
如果你的表数据量很大,用函数转换后排序可能会有点慢(因为数据库没法利用order_date字段上的索引)。这种情况下,如果你允许新增字段但不修改现有数据,可以考虑添加一个计算列或者函数索引:
比如在MySQL里,你可以新增一个存储生成列:
ALTER TABLE your_table ADD COLUMN order_date_normalized DATE AS (STR_TO_DATE(order_date, '%d/%m/%Y')) STORED;
然后给这个新列加索引:
CREATE INDEX idx_order_date_normalized ON your_table(order_date_normalized);
之后排序直接用这个新列就行,速度会快很多:
SELECT * FROM your_table ORDER BY order_date_normalized ASC;
这个操作完全不会影响原有的order_date字段和数据,只是多了一个辅助排序的列而已。
内容的提问来源于stack exchange,提问作者Single Mingle

