如何使NOT IN子句为NULL安全?

时间:2018-05-07 11:46:21

标签: mysql sql

这是我的表结构:

// questions_and_answers
+----+-------------------+------+----------+
| id |       body        | type | related  |
+----+-------------------+------+----------+
| 1  | a question        | 0    | NULL     |
| 2  | my answer         | 1    | 1        |
| 3  | another answer    | 1    | 1        |
| 4  | another question  | 0    | NULL     |
| 5  | another answer    | 1    | 4        |
| 6  | another answer    | 1    | 1        |  
+----+-------------------+------+----------+
-- type column: it is either 0 for questions and 1 for answers.
-- related column: it is either null for questions and "the id of its question" for answers

现在我需要选择所有未答复的问题。这是我的疑问:

SELECT *
FROM questions_and_answers AS qa
WHERE
  type = 0 -- just questions
  AND
  qa.id NOT IN (SELECT q.related FROM qanda q WHERE q.type <> 0) -- unanswered ones

效果很好,一切都很好。

我的问题是什么?如果有这样的行,我的查询不匹配任何行:

| 7  | another answer    | 1    | NULL      |

请参阅? type的值为1,因此它是一个答案。但related的值为NULL,因此它没有指出任何问题。一般情况下,该行没有任何意义,但有时可能会发生(当问题被删除并且我们将related的答案设置为null时)。在这种情况下,我的查询结果是“no row selected”

为什么呢?如何在这种情况下使我的查询安全? (安全==忽略它们并仍然匹配未回答的问题)

2 个答案:

答案 0 :(得分:1)

使用not exists

where not exists (select 1 from quanda q where q.related = qa.id and q.type <> 0)

我强烈建议您永远不要将not in与子查询一起使用 - 特别是因为NULL问题。只需使用not exists即可。使用索引进行优化也更容易。

答案 1 :(得分:1)

您必须只从第二个SELECT中删除所有这些记录(相关= NULL),如此

SELECT *
FROM qa
WHERE type = 0 -- just questions
  AND id NOT IN 
    (SELECT related 
       FROM qa
       WHERE type <> 0
         AND related IS NOT NULL
    )