我有以下查询:
SELECT
NULLIF(MAX(t.date),'2019-01-15') AS ended
FROM
totals t
此查询正确输出日期:
> 2019-01-01
但是如果我在子查询中引用此查询,如下所示:
SELECT * FROM
(SELECT
NULLIF(MAX(t.date),'2019-01-15') AS ended
FROM
totals t) AS a
此版本错误地产生了截断的结果:
> 201
有人可以帮助我了解这种行为以及如何最好地解决它吗?
附加说明: 我正在运行MySQL版本:“ 5.7.25 MySQL Community Server”
对于想要进行此测试的任何人,下面是受此问题影响的简单测试表的示例:
CREATE TABLE `totals` (
`date` date NOT NULL,
`value` decimal(10,0) DEFAULT NULL,
PRIMARY KEY (`date`)
);
INSERT INTO `totals` VALUES ('2018-01-01',2000000),('2019-01-01',3000000);
答案 0 :(得分:0)
我的猜测是正在发生隐式数据类型转换。
作为一种解决方法,我将从NULLIF
函数中获取返回值并将其转换/广播回DATE
数据类型。最简单的方法是将其包装在DATE()
函数中。
SELECT
DATE( NULLIF(MAX(t.date),'2019-01-15') ) AS ended
^^^^^ ^
我们还可以尝试转换字符串文字,将其转换为DATE,看看是否可以解决问题:
SELECT
NULLIF(MAX(t.date), DATE('2019-01-15') ) AS ended
^^^^^ ^
或者我们都可以做:
SELECT
DATE( NULLIF(MAX(t.date), DATE('2019-01-15') ) ) AS ended
^^^^^ ^
^^^^^ ^
我们还可以使用其他表达式进行数据类型转换,例如CAST()
,CONVERT()
或STR_TO_DATE()
。
或者我们可以仅使用简单的+ INTERVAL 0 DAY
技巧。例如
SELECT
NULLIF(MAX(t.date),'2019-01-15' + INTERVAL 0 DAY ) + INTERVAL 0 DAY AS ended
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
答案 1 :(得分:0)
这里的问题似乎是在NULLIF
内发生的一个微妙的转换/广播问题。首先,这是您的查询实际上可以按预期运行的版本:
SELECT *
FROM
(
SELECT NULLIF(MAX(t.date), STR_TO_DATE('2019-01-15', '%Y-%m-%d') AS ended
FROM totals t
) AS a
您当前的查询正在发生的事情是MySQL正在将对MAX(t.date)
的调用转换为文本,以匹配文本文字'2015-01-15'
。通过确保NULLIF
的两个参数都是日期类型,即可获得所需的行为。
关于为什么,我们看到201
是调用NULLIF
的字符串结果,我没有解释。但是,我可以在这里引用NULLIF
的{{3}}:
如果expr1 = expr2为true,则返回NULL,否则返回expr1。与expr1 = expr2 THEN NULL ELSE expr1 END时的情况相同。
在SQL中,一条通用规则是CASE
表达式的if和else分支应始终具有相同的类型。实际上,如果我们违反此规则,则在大多数数据库中,CASE
表达式甚至不会编译。将其应用于NULLIF
意味着我们应始终确保两个参数都具有相同的类型。违反此规则可能可以在MySQL上运行(类似于在关闭全模式的情况下执行不符合ANSI的GROUP BY
),但是如果可以避免的话,这不是我们应该选择的东西。 / p>