【问题标题】:How to get rid of NOT EXISTS如何摆脱不存在
【发布时间】:2012-03-27 01:30:48
【问题描述】:

我有一个不是很复杂但足够混乱的 sql,我质疑我有一个等价的或巧合的计数是相同的。

SQL1:

SELECT a, b
FROM table1
WHERE NOT EXISTS(
  SELECT a, c
  FROM TABLE2
  WHERE table2.a != table1.a)

SQL2

SELECT table1.a, table1.b
FROM table1
LEFT JOIN table2 ON table2.a = table1.a
WHERE table2.a IS NULL

两者的计数相同,但不确定这是否是偶然的,我想确保转换不会改变原始功能。

【问题讨论】:

  • 不确定我是否获得了 SQL1 的功能。您想从 table1 中获取 a、b,其中 a 是 table2.a 的唯一值?
  • 我认为关键是从table1中获取table2中没有对应条目的行。
  • @Dave 是的,我认为这是最初的预期目的。但我不能 100% 确定,我正在尝试对其进行优化,使其运行得更快。
  • 第一个查询的编写方式似乎是从 table1 获取所有行,这样 table2 中不存在不匹配的行。而且我认为只有 all table2 中的行与 table1.aone 值完全匹配时才有效
  • @Churk,你没有提到你正在使用什么 RDBMS。我在 Oracle 中尝试了这两种语句,我发现如果 table2 上有一个索引,WHERE EXISTS 版本将使用索引,但带有 != 的连接条件(如下所示)不会。换句话说,假设一个索引,至少在 Oracle 中,你最好使用 NOT EXISTS。但是,您当然不需要在子查询中使用“SELECT a,c”;您可以只使用“SELECT 1”或“SELECT 'X'”。

标签: sql join left-join inner-join not-exists


【解决方案1】:

这看起来不一样 - 但很接近。您的 LEFT JOIN 语法与以下内容相同:

SELECT a, b
FROM table1
WHERE NOT EXIST(
  SELECT a, c
  FROM TABLE2
  WHERE table2.a = table1.a)

请注意“=”而不是“!=”。你确定那不是你所拥有的吗?

您的实际查询转换为“不存在不匹配的行”之类的内容,这很奇怪,但可以通过更改 JOIN 条件来表达:

SELECT a, b
FROM table1
LEFT JOIN table2 ON table2.a != table1.a
WHERE table2.a IS NULL

【讨论】:

  • 第一个 sql 是我拥有的,第二个 sql 是我可以更改的。所以你说的是连接条件,我应该在连接列上使用 != ,但这不会导致另一个问题本身吗?
  • @Churk:我看到的唯一问题是它令人困惑——但比原始查询要少。这是一个奇怪的检查条件,并且不适合(至少我的)标准集思维 - 但如果你 100% 肯定这就是你所拥有的,我会选择 LEFT JOIN 和大量为什么类型 cmets。
【解决方案2】:

如您所见,第一个查询返回 TABLE1 的所有行,其中 a 匹配 TABLE2 中 a 的所有值。因此,它将返回零行,除非在 TABLE2 中a 有一个非空值,并且该值存在于 TABLE1 中。在这种情况下,它将返回与 TABLE1 中的行一样多的行,其值为a

第二个查询完全不同。它只会返回 TABLE1 的所有行,其中 a 在 TABLE2 中不存在。

所以它是“匹配所有”(查询 1)与“不匹配任何”(查询 2)。您获得相同数量的行的事实纯属巧合。

如果您在第一个查询中将!= 更改为=,您的查询将是等效的,如下所示:

SELECT a, b
FROM table1
WHERE NOT EXISTS(
  SELECT a, c
  FROM TABLE2
  WHERE table2.a = table1.a)

这会为您提供 table1 中不存在于 table2 的 a 值。这与以下内容完全相同:

SELECT table1.a, b
FROM table1
LEFT JOIN table2 ON table2.a = table1.a
WHERE table2.a IS NULL

尽管如此,但它们并不等同。您必须在第一个中将 != 更改为 = 才能使它们如此。

【讨论】:

  • 第一个查询不能改变,这是我正在转换的。所以在排序中,这两个查询是不等价的,只是巧合的是计数返回相同。
  • 第一个查询不是有效的语法(提示:EXIST),第二个查询也不是(提示:SELECT 子句中的a 不明确),它们也不等价!跨度>
  • @onedaywhen 我基本上不得不重新输入查询,所以请原谅拼写错误。但这不是我遇到的问题,也不是问题所在。
  • @Churk,你是对的。请看看我的编辑现在是否回答了您的问题。
  • 谢谢,这就是我害怕的,因为它没有意义,但是两者的计数结果相等让我失望。
【解决方案3】:

对于第一个查询,即

SELECT a, b
FROM table1
WHERE NOT EXISTS(
  SELECT a, c
  FROM TABLE2
  WHERE table2.a != table1.a)

table1a 的所有值都是相同的一个值并且table2 中的所有行都与table1 相同的一个值或table2 为空时,这将返回所有行放。否则,结果将是空集。

与您的第二个查询不能相同。

【讨论】:

  • 谢谢你的进一步解释,我现在明白你的意思了。
【解决方案4】:
SELECT a, b, c , d
FROM table1 t1
WHERE NOT EXISTS( SELECT * FROM table2 nx
  WHERE nx.y = t1.a
  )
  ;

这种(“相关子查询”)方法有一个很大的优势:表 table2 从外部查询中是不可见的,不会污染它,也不会混淆你的思维。子查询只产生一点信息:要么存在,要么不存在。 成为或不成为......
在这方面,LEFT JOIN 习惯用法更糟糕,因为您必须在外部查询中检查xxx IS NULL 条件,而 xxx 从内部查询中引用 table2。

从技术上讲,没有区别。

【讨论】:

    猜你喜欢
    • 2020-09-18
    • 2011-07-30
    • 1970-01-01
    • 2014-01-28
    • 2013-10-31
    • 2020-10-19
    • 2019-12-01
    • 2013-01-14
    • 1970-01-01
    相关资源
    最近更新 更多