为什么WHERE和HAVING之间的MySQL行为IS TRUE,IS NOT TRUE,IS FALSE,IS NOT FALSE的行为不同

时间:2019-01-22 07:35:29

标签: mysql sql

考虑两个表:

表1

id
1
2
3

表2

id, deleted
2, 0
3, 1

假设我要从表1中获得所有未在表2中标记为“已删除”的行,即行1和2。 考虑以下SQL(在MySQL中):

SELECT id
FROM table1
LEFT JOIN table2 USING (id)
WHERE deleted <> 1

此SQL显然仅返回id = 2的行。

我可以做这样的变态:

SELECT id
FROM table1
LEFT JOIN table2 USING (id)
WHERE COALESCE(deleted, 0) = 0

然后我将获得第1行和第2行。

但是我想要一种更优雅的方式。 MySQL对布尔值,IS TRUE,IS NOT TRUE,IS FALSE,IS NOT FALSE进行了很好的检查,这些检查考虑了NULL值。所以考虑一下:

SELECT id, deleted, deleted IS NOT TRUE
FROM table1
LEFT JOIN table2 USING (id)

结果:

id, deleted, deleted IS NOT TRUE
1, NULL, TRUE
2, 0, TRUE
3, 1, FALSE

看起来不错,对吧?现在,如果我将其放入WHERE子句中:

SELECT id
FROM table1
LEFT JOIN table2 USING (id)
WHERE deleted IS NOT TRUE

哦,不!我又回到了第2行!

但是,如果我将条件放入HAVING子句中,它将开始工作:

SELECT id
FROM table1
LEFT JOIN table2 USING (id)
HAVING deleted IS NOT TRUE

我得到第1行和第2行。

完全令人困惑。好像是MySQL中的错误。

2 个答案:

答案 0 :(得分:1)

正如我所怀疑的那样,正如@BillKarwin指出的那样,这是MySQL中的一个古老的2012年错误:(

“哪里var is not TRUE产生的值太少”(https://bugs.mysql.com/bug.php?id=67732

答案 1 :(得分:0)

我认为您只想要NOT EXISTS

SELECT t1.id
FROM table1 t1 
WHERE NOT EXISTS (SELECT 1
                  FROM table2 t2
                  WHERE t1.id = t2.id AND t2.is_deleted = 1
                 );