Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 比较日期时出现意外结果_Mysql - Fatal编程技术网

Mysql 比较日期时出现意外结果

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

我在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` > "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”>2019

MySQLs隐式类型转换可能非常令人惊讶。如果您想了解查询的行为,可以尝试应用中所述的类型转换规则。但是-我没有为您的情况这样做。例如:对于两个表达式
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";`