Mysql 比较日期时出现意外结果
我在MYSQL 5.7.26服务器上有一个表,其列类型为date(yyyy-mm-dd h:I:s) 当我这样询问时:Mysql 比较日期时出现意外结果,mysql,Mysql,我在MYSQL 5.7.26服务器上有一个表,其列类型为date(yyyy-mm-dd h:I:s) 当我这样询问时: SET @THIS_YEAR = "2019-01-01 00:00:00"; SELECT * FROM table WHERE `date` > year(@THIS_YEAR); 我期待所有日期为2019-01-01的参赛作品。 但我也收到了几年前的参赛作品 但这个查询的工作原理是: SELECT * FROM table WHERE `date` > "2
SET @THIS_YEAR = "2019-01-01 00:00:00";
SELECT * FROM table WHERE `date` > year(@THIS_YEAR);
我期待所有日期为2019-01-01的参赛作品。
但我也收到了几年前的参赛作品
但这个查询的工作原理是:
SELECT * FROM table WHERE `date` > "2019";
顺便说一句,此查询还返回错误的(或者更意外的)结果:
这些查询之间有什么区别?为什么它不适用于变量或将日期与整数进行比较?我想这是某种自动类型转换 根本问题是数据类型之一。 简而言之:口译员很难知道你的“2019”是字符串还是日期。因此,它按照它预期的那样进行。
如果将值存储到变量中,则会将其解析为字符串,因为此处需要字符串。如果直接比较,则需要一个日期值,因此MySQL会成功地尝试解析一个日期。
2019,与“2019”相反,显然是一个数字,而不是日期值。这就解释了这里的有趣行为。此查询将比较@This_year和
date的年份:
SET @THIS_YEAR = "2019-01-01 00:00:00";
SELECT * FROM table WHERE year(`date`) = year(@THIS_YEAR);
注意,date
被包装在year函数中。这意味着您现在正在比较年份()
这个查询有效
SELECT * FROM table WHERE `date` > "2019";
因为解释器将使用日期的字符表示法
并执行逐字符比较:“2019-”>“2019”
此查询不起作用:
SELECT * FROM table WHERE `date` > 2019;
出于同样的原因。解释器将使用date
字符表示,然后将第一个字符与2019进行比较。“2”<2019(就字符2的可读性和数字表示而言
此查询:
SET @THIS_YEAR = "2019-01-01 00:00:00";
SELECT * FROM table WHERE `date` > year(@THIS_YEAR);
也有同样的问题。year()返回一个数字,因此它将再次为:“2”>2019MySQLs隐式类型转换可能非常令人惊讶。如果您想了解查询的行为,可以尝试应用中所述的类型转换规则。但是-我没有为您的情况这样做。例如:对于两个表达式date>'2019'
和date>2019
,我将应用以下欠款规则:
如果其中一个参数是时间戳
或日期时间
列,则
另一个参数是常量,该常量被转换为时间戳
在执行比较之前
但情况并非如此,因为数字2019
和字符串'2019'
都不能转换为时态类型。下面是一个查询,它演示了一些隐式转换:
select '2019' + interval 0 day -- implicit cast to date(time)
, 2019 + interval 0 day
, 20190101 + interval 0 day
, 190101 + interval 0 day
, '2019*01*01' + interval 0 day
, '2019-01-01' + interval 0 day
, '2019-01-01' + 0 -- implicit cast to numeric
, date('2019-01-01') + 0
, date('2018-01-01') > 2019
, date('2018-01-01') > '2019'
;
结果:
Expression | Result
------------------------------|-----------
'2019' + interval 0 day | null
2019 + interval 0 day | null
20190101 + interval 0 day | 2019-01-01
190101 + interval 0 day | 2019-01-01
'2019*01*01' + interval 0 day | 2019-01-01
'2019-01-01' + interval 0 day | 2019-01-01
'2019-01-01' + 0 | 2019
date('2019-01-01') + 0 | 20190101
date('2018-01-01') > 2019 | 1
date('2018-01-01') > '2019' | 0
如您所见,当我们尝试将2019
或'2019'
转换为日期(或日期时间)时,我们得到了NULL
。因此条件也应该计算为NULL
,结果集将为空。但我们知道,情况并非如此。也许我错了,假设2019
和'2019'
是常量。但我不知道它们可能是什么意思
因此,我只能做出假设。我的假设是:每当一个比较器是数字时,另一个值也会转换为数字值。2019年以及今年的情况都是如此。在这种情况下,2018-01-01年的日期转换为20180101年的日期(见上表),它(在数字上下文中)大于2019年。因此,您可以得到2018年的行数
对于date>'2019'
我只能假设,这些值作为字符串进行比较。而'2018-01-01'
作为字符串被认为比2019
小
但即使这种行为被适当地记录下来,规则也很难记住,因为人们几乎看不到它们背后的任何逻辑(我不说——没有逻辑——我只是看不到任何逻辑)
所以我可以给你一个建议:如果你想比较两个不兼容的类型,一定要将它们转换成兼容的
WHERE year(date) >= year(@THIS_YEAR)
可以,因为您比较两个数值。但在您的情况下,这不是必需的,您可以使用
WHERE date >= @THIS_YEAR
因为2019-01-01 00:00:00
`SET @THIS_YEAR = "2019-01-01 00:00:00";`
是一个格式完美的日期时间字符串,可以认为与日期时间类型兼容。'2019-01-01'
也可以
请注意,如果将列包装到函数调用中(如year(date)
),您将失去在该列上使用索引的能力。一个好问题:您期望什么(以及为什么),当您比较两种不同的类型时?让我们从基础开始。您知道日期字段不是以字符串形式存储的吗?请参阅,您想要一个关于字符串和整数计算之间差异的冗长而复杂的解释,还是想解决您的问题?如果是后者,则选择*FROM table WHERE Date>'2019-01-01 00:00:00';
就足够了,或者哪一年(
日期)>@今年
口译员对价值一无所知,但会尝试以适合给定上下文的方式对其进行评估,因此2019-01-01可以解释为2017年(2019减1减1)和20190101年(2000万、19万和100)取决于上下文。“因此MySQL试图成功解析日期”-您如何成功解析到日期的'2019'
?您能举个例子吗?@Paul Spiegel Ok。这有点草率。老实说:MySQL隐式类型转换以神秘的方式工作:-)。”然后将第一个字符与2019进行比较。“2”<2019”-对不起,你在说什么?我不明白。这不可能是正确的,因为问题不同。请重新阅读问题。所有查询返回的日期都是2019年。但这两个“错误”查询还返回2019年之前的日期。2019年是一个整数值。解释器将基础日期解释为“2019-01-01”,这是一个字符串。在字符串与整数的比较中,它被视为一个字符串比较,整数代表t
`SET @THIS_YEAR = "2019-01-01 00:00:00";`