用于Solar日期但其类型为varchar的列我想选择(1395-02)间隔中的所有行,但我只从2行获得1行 这是我试过的
SELECT * FROM `products_records`
WHERE Date_FORMAT(`products_records`.`Inserted_Date`,'%Y-%m')='1395-02'
注意:数据库中的一些日期LIKE 1395-02-30已更改为0000-00-00,这就是为什么我使用Varchare代替此列的日期
答案 0 :(得分:0)
首先,请注意您在预期目的之外使用DATE_FORMAT()
。 DATE_FORMAT()
的第一个参数应该是一个日期时间值 - 而不是一个字符串 - 但MySQL的隐式转换是非常慷慨的,所以它允许你逃避技术上不是有效使用的功能完全。您实际上是隐式地将字符串转换为日期,然后使用期望日期的函数...但是您的某些日期无效,因此隐式转换可能会失败。运行查询后,SHOW WARNINGS;
可能会显示此信息。
理论上,您应该使用STR_TO_DATE()
将字符串转换为正确的日期时间,然后使用其结果作为DATE_FORMAT()
的第一个参数。
但是,这仍然是错误的解决方案,因为它违反了一个基本规则,即您不希望将列用作WHERE
子句中大多数函数的参数...因为当您这样做时,服务器必须为表中的每一行计算该表达式,并且您的索引不能用于优化查询。你失去了所谓的“sargability”,随着你的桌子大小增加,查询会慢慢爬行。这是RDBMS的一般限制,而不仅仅是MySQL。
更好的是使用常量WHERE inserted_date >= '1395-02-01' AND inserted_date < '1395-03-01'
。这样,如果索引可用,它可以显着提高您的性能。
几乎有趣,因为你的日期是yyyy-mm-dd格式,它们的词汇顺序恰好也是按时间顺序排列,所以即使上面的查询会在你当前的设置中使用字符串比较进行评估,答案仍然是正确,查询计划将是最佳的。如果日期实际存储为日期,这仍然是首选形式 - 不使用WHERE
中的函数。
但是,如果您想使用无效日期,则您的服务器需要ALLOW_INVALID_DATES
中包含@@SQL_MODE
。那么任何一个月都可以有31天。我不知道为什么这实际上是一个功能,但它是:
服务器要求月和日值合法,而不仅仅分别在1到12和1到31的范围内。禁用严格模式后,“2004-04-31”等无效日期将转换为“0000-00-00”,并生成警告。启用严格模式后,无效日期会生成错误。要允许此类日期,请启用
ALLOW_INVALID_DATES.
http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_allow_invalid_dates
虽然我从来没有理由使用无效日期,但是理所当然日期/时间函数也会阻塞它们,但是这个设置可能是你需要的,以便允许这些值按预期工作