我希望能够在MySQL数据库中选择两个日期之间的所有日期,其中日期是varchar,格式为dd.mm.yyyy。
Database
date (varchar) | value
------------------------
31.01.2018 | 123
------------------------
28.02.2018 | 456
这不起作用
Query
SELECT date,value from Database WHERE date BETWEEN '2018-01-01' AND '2018-01-31'
我知道我可以整整使用WHERE date LIKE '%.01.2018'
但这还不够。
我可以在PHP中执行此操作,但不想这样做,因为这将花费太长时间。
我想我可以使用CAST
函数,但不知道如何。
在MySQL中执行此操作的最佳方法是什么?
答案 0 :(得分:5)
在MySQL中执行此操作的最佳方法是避免将日期存储为DD.MM.YYYY格式的字符串。相反,请将日期存储在正确的DATE
列中,以便它们与原始格式匹配:YYYY-MM-DD。
使用STR_TO_DATE()
或其他功能的解决方案意味着您无法使用索引来优化比较。搜索将以较差的性能运行,因为它必须进行表扫描。
重新评论:
200万行不是一张大表。重组它不应该花费一两分钟以上的时间。如果你等到桌子变大,情况就会变得更难。
由于您的数据格式错误,因此您无法更改数据类型。以下是我如何解决这个问题:
第1步:添加适当的DATE
数据类型的新列:
ALTER TABLE MyTable ADD COLUMN myDate DATE;
(顺便说一句,不要为你的桌子命名"数据库"或你的专栏"日期"。这些都是保留字,反正不是描述性的。你命名程序变量"变量"?)
第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'));
COALESCE的原因很快就会清楚。
第3步:回填过去行中的所有值:
UPDATE MyTable
SET myDate = STR_TO_DATE(NEW.oldDate, '%d.%m.%Y')
WHERE myDate IS NULL;
你只需要这样做一次。插入的任何新行将在您创建触发器后自动将正确的日期值复制到新列。在创建触发器之前插入的任何行在新列中都将为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;
如果您担心每个ALTER TABLE将在表重组期间锁定表,您应该学会使用pt-online-schema-change。这允许您在不锁定的情况下执行ALTER TABLE(重组结束时的短暂时间除外)。
答案 1 :(得分:3)
您可以使用STR_TO_DATE()
:
WHERE STR_TO_DATE(date, '%d.%m.%Y') BETWEEN '2018-01-01' AND '2018-01-31'
答案 2 :(得分:0)
您可以选择revo的解决方案,或者选择此解决方案
SELECT date,value from Database WHERE (not (date is null)) and CHAR_LENGTH(date) = 10 (CONCAT(SUBSTRING(date, 7), '-', SUBSTRING(date, 4, 2), '-', SUBSTRING(date, 1, 2))) BETWEEN '2018-01-01' AND '2018-01-31'
在这里,我们检查日期是否为空并且具有所需的长度,因此当程序满足非常规值时,程序不会崩溃。