如何比较MySQL格式为dd.mm.yyyy的日期(varchar)?

And*_*dri 2 mysql varchar casting date

我希望能够在MySQL数据库中选择两个日期之间的所有日期,其中日期是varchar,格式为dd.mm.yyyy.

Database
date (varchar) | value
------------------------
31.01.2018     | 123
------------------------
28.02.2018     | 456
Run Code Online (Sandbox Code Playgroud)

这不起作用

Query
SELECT date,value from Database WHERE date BETWEEN '2018-01-01' AND '2018-01-31'
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用WHERE date LIKE '%.01.2018'整整几个月,但这还不够.

我可以在PHP中执行此操作,但不想这样做,因为这将花费太长时间.我想我可以使用这个CAST功能,但不知道如何.

在MySQL中执行此操作的最佳方法是什么?

Bil*_*win 5

在MySQL中执行此操作的最佳方法是避免将日期存储为DD.MM.YYYY格式的字符串.而是将日期存储在适当的DATE列中,因此它们与本机格式匹配:YYYY-MM-DD.

使用STR_TO_DATE()或其他功能的解决方案意味着您不能使用索引来优化比较.搜索将以较差的性能运行,因为它必须执行表扫描.


你的评论:

200万行不是一张大表.重组它不应该花费一两分钟.如果你等到桌子变大,那只会变得更难.

由于您的数据格式错误,因此您无法更改数据类型.这是我如何解决这个问题:

步骤1:添加一个适当DATE数据类型的新列:

ALTER TABLE MyTable ADD COLUMN myDate DATE;
Run Code Online (Sandbox Code Playgroud)

(顺便说一句,不要将你的表命名为"数据库"或你的列"日期".这些都是保留字,而不是描述.你是否将程序变量命名为"变量"?)

第2步:创建一个触发器,以便您的应用程序使用旧列自动复制到新列:

CREATE TRIGGER InsMyDate BEFORE INSERT ON MyTable
FOR EACH ROW 
SET NEW.myDate = COALESCE(NEW.myDate, STR_TO_DATE(NEW.oldDate, '%d.%m.%Y'));

CREATE TRIGGER UpdMyDate BEFORE UPDATE ON MyTable
FOR EACH ROW 
SET NEW.myDate = COALESCE(NEW.myDate, STR_TO_DATE(NEW.oldDate, '%d.%m.%Y'));
Run Code Online (Sandbox Code Playgroud)

COALESCE的原因很快就会清楚.

第3步:回填过去行中的所有值:

UPDATE MyTable
SET myDate = STR_TO_DATE(NEW.oldDate, '%d.%m.%Y')
WHERE myDate IS NULL;
Run Code Online (Sandbox Code Playgroud)

你只需要这样做一次.插入的任何新行将在您创建触发器后自动将正确的日期值复制到新列.在创建触发器之前插入的任何行在新列中都将为NULL,因此您需要更新它们,如上所示.

第4步:更改应用程序代码,以便对旧错误日期列的任何引用都使用新的日期列.解决引用日期的任何INSERT,UPDATE或SELECT.测试并部署此代码更改.

执行此操作后,任何INSERT或UPDATE都将在新日期列中指定一个值而不是NULL.这将使触发器有效地成为无操作,因为myDate中的非NULL值将优先于STR_TO_DATE()表达式.这允许您在方便时部署代码,数据库将继续使用您的数据做正确的事情.

第5步:删除触发器和旧的字符串日期列:

DROP TRIGGER InsMyDate;
DROP TRIGGER UpdMyDate;
ALTER TABLE MyTable DROP COLUMN oldDate;
Run Code Online (Sandbox Code Playgroud)

如果您担心每个ALTER TABLE将在表重组期间锁定表,您应该学会使用pt-online-schema-change.这允许您在不锁定的情况下执行ALTER TABLE(重组结束时的短暂时间除外).