【问题标题】:NOT EXISTS on empty table returning falseNOT EXISTS 在返回 false 的空表上
【发布时间】:2012-07-17 21:06:17
【问题描述】:

我有一个跨 2 个未返回任何结果的表的 SELECT 查询,我不知道为什么不返回。这是不返回任何行的查询:

SELECT b.name, b.description, b.badge_id 
FROM badges AS b 
WHERE b.type = 'have' AND b.brand_id = 'zTR7wH5FMl' AND ISNULL(b.series_id) AND b.amount <= 89 
AND NOT EXISTS (SELECT date_earned 
                FROM users_badges AS ub 
                WHERE ub.user_id = 'fMcBBx' AND ub.badge_id = b.badge_id)

如果我只是在最后去掉 AND NOT EXISTS 子句以检查他们是否还没有获得徽章,我会得到这些结果:

name            description                                             badge_id
Baker's Dozen   Add 13 items to your Johnny Cupcakes shelf.             sdfKHJkun7
Cupcaker        Have 82 items on your Johnny Cupcakes shelf.            4MeoheBdik
Freshly Baked   Have your first item on your Johnny Cupcakes shelf...   kdJGH98NdI

这正是我期望得到的。 AND NOT EXISTS 检查是唯一的区别。 users_badges 表中还没有数据,所以我不明白为什么它会返回 false。在我看来,它将无法返回错误。为什么它会使整个查询无效?

【问题讨论】:

  • 在 EXISTS 选择中将“date_earned”替换为 *...
  • 如果我没记错的话,SQL 实际上并没有检查 EXISTS 中的 SELECT 条件,所以没关系。

标签: mysql subquery not-exists


【解决方案1】:

在表格中添加一行似乎已经解决了。我猜如果表是空的,SQL 甚至不会检查 EXISTS 条件并且总是返回 false,因为该行不可能存在于表中。

【讨论】:

  • 这听起来像是一个严重的错误。是的,当子查询中的表为空时,对于带有 NOT EXISTS (correlated subquery) 的查询,MySQL 有时会在 EXPLAIN 输出中显示 no matching row in const tableImpossible WHERE noticed after reading const tables。 (至少,对于 InnoDB 是这样)。但这根本不能解释为什么 MySQL 返回不正确的结果。 (空表不是 MySQL 返回错误结果的借口。)
  • 我注意到,如果我删除了多余的行以使表格再次为空,它仍然可以正确返回。它只是在表中插入任何数据之前错误地返回。如果您将问题的标题复制到 google 中,则第 3 或第 4 个结果是一个错误报告,其中 mysql 开发团队说它不是错误。我不明白他们为什么这么说。
  • 这是一个严重的缺陷。我看到了错误报告,它被关闭是因为报告错误的方式存在缺陷,而不是因为 MySQL 的行为是正确的。我检查了文档,我发现对 EXISTS 谓词的唯一引用在 13.2.9.6 http://dev.mysql.com/doc/refman/5.1/en/exists-and-not-exists-subqueries.html 中。规格非常苗条。 “如果 sq 返回一行,则 EXISTS sq 为 TRUE,NOT EXISTS sq 为 FALSE”。所以从技术上讲,当没有行返回时,规范不会禁止“NOT EXISTS sq is FALSE”。如果规范允许,那么它就是规范中的严重缺陷。
【解决方案2】:

尝试将NOT EXISTS 替换为LEFT JOIN / IS NULL

SELECT    b.name, b.description, b.badge_id 
FROM      badges b 
LEFT JOIN user_badges ub ON b.badge_id = ub.badge_id AND ub.user_id = 'fMcBBx'
WHERE     b.type = 'have' AND 
          b.brand_id = 'zTR7wH5FMl' AND 
          b.amount <= 89 AND
          b.series_id IS NULL AND 
          ub.badge_id IS NULL

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 2021-07-03
    相关资源
    最近更新 更多