【问题标题】:Difficulty to understand SQLite exists and its subquery难以理解 SQLite 存在及其子查询
【发布时间】:2016-05-04 01:59:19
【问题描述】:

假设有一个名为 Temp 的表,它的架构和数据都被列出来了

表温度:

A         B       
----      ----

1         1        # Row 1 
1         5        # Row 2 
2         2        # Row 3  

SQLite 查询:

1) DELETE FROM Temp WHERE EXISTS (SELECT 1 FROM Temp AS IL2 WHERE Temp.A = IL2.A AND Temp.B = 1 AND IL2.B = 5)
2) DELETE FROM Temp WHERE EXISTS (SELECT 1 FROM Temp AS IL2 WHERE Temp.A = IL2.A AND Temp.B = 5 AND IL2.B = 1)

问题 1) “Temp.A = IL2.A”是什么意思? IL2 是 Temp 的别名,它和自己比较?我在这里迷路了。

问题 2) 查询 1 和 2 分别通过实验删除第 1 行和第 2 行。 在我看来,子查询“(SELECT 1 FROM AS IL2 WHERE Temp.A = IL2.A AND Temp.B = 5 AND IL2.B = 1)”的返回值由“ IL2.B”。我认为这个子查询会返回第 2 行和第 3 行。

【问题讨论】:

    标签: sql sqlite subquery exists


    【解决方案1】:

    这是另一个答案,逐步解释了查询中发生的情况。让我们查询 #2:

    DELETE FROM Temp 
    WHERE EXISTS 
    (
      SELECT 1 
      FROM Temp AS IL2 
      WHERE Temp.A = IL2.A 
        AND Temp.B = 5 
        AND IL2.B = 1
    );
    

    该语句应该在表 Temp 中查找记录并删除它们。所以让我们从第一条记录开始,看看它是否符合 where 子句中给出的条件:

    第 1 行:A=1,B=1

    我们在同一个表中寻找存在,我们称之为 IL2(就像它是不同的表一样)。因此,每当我们引用我们可能想要删除或不删除的刚刚读取的记录时,我们使用限定符 Temp,并且我们读取表 IL2 记录的记录,以便将它们与 Temp 记录进行比较。所以让我们看看是否找到匹配项:

    一个 |乙|温度.A = IL2.A? |温度 B = 5? | IL2.B = 1? --+---+--------------------------------+---------- ---------+------------ 1 | 1 |是的,两条记录的 A=1。 |不,Temp.B 为 1。是的。 1 | 5 |是的,两条记录的 A=1。 |不,Temp.B 为 1。不,是5。 2 | 2 |不,Temp.A 为 1,IL2.A 为 2。不,Temp.B 为 1。不,是2。

    如你所见,Temp.B = 5?总是错误的(并且总是正确的,因为我们查看了第二个记录行#2),因为尽管条件在 EXISTS 子查询中,但它实际上是指经受考验的记录。这就是为什么我建议将此标准移到 EXISTS 子句之外以提高可读性。此查询 100% 等效,但更易于阅读:

    DELETE FROM Temp 
    WHERE B = 5 
    AND EXISTS 
    (
      SELECT 1 
      FROM Temp AS IL2 
      WHERE IL2.A = Temp.A
        AND IL2.B = 1
    );
    

    现在让我们看看这个查询。我们再次从 Temp 中读取第一行。 B 为 1,因此不匹配 WHERE B = 5。不满足条件,记录不会被删除。

    下一条记录(第 2 行)。 B = 5。好吧,让我们看看exists子句并再次检查记录:

    一个 |乙|温度.A = IL2.A? | IL2.B = 1? --+---+--------------------------------+---------- -- 1 | 1 |是的,两条记录的 A=1。 |是的。 1 | 5 |是的,两条记录的 A=1。 |不,是5。 2 | 2 |不,Temp.A 为 1,IL2.A 为 2。不,是2。

    啊哈。第一条记录匹配,因此满足 EXISTS 条件。 (DBMS 必须找到至少一个匹配项。一旦找到匹配项,它就不必读取剩余的记录。所以我们可以在找到第 1 行作为匹配项之后停止。)所有条件都是 TRUE;调查的 Temp 记录(第 2 行)将被删除。

    现在到最后一条记录。 B 是 2,所以 WHERE B = 5 不匹配。不满足条件,记录不会被删除。

    我希望这能阐明 EXISTS 的工作原理。 (至于“选定”数据:在 EXISTS 中选择什么并不重要;这三个都一样:where exists (select 1 from ...)where exists (select * from ...)where exists (select 'yes, there exists a row' from ...)。)

    【讨论】:

      【解决方案2】:

      delete 语句在同一个表中查找具有相同 A,但另一个 B(1 对 5)的记录。为了做到这一点,需要一个表别名 (IL2) 来区分一条记录和另一条记录。不过,这些查询有点模糊。某些条件隐藏在它不真正属于的子查询中。更好的是:

      delete from temp 
      where b = 1 
      and exists (select 1 from temp as il2 where il2.a = temp.a and il2.b = 5);
      
      delete from temp 
      where b = 5 
      and exists (select 1 from temp as il2 where il2.a = temp.a and il2.b = 1);
      

      附注:第二个语句当然不会找到(因此删除)任何东西,因为所有存在 b5 的 b1 都已被删除。为了规避这一点并删除两条记录,即 b1 和 b5,请结合两个语句:

      delete from temp
      where b in (1,5)
      and exists
      (
        select *
        from temp other
        where other.b in (1,5)
          and other.a =  temp.a
          and other.b <> temp.b
      );
      

      【讨论】:

      • 非常感谢您重构 Sql 查询。
      【解决方案3】:

      WHERE EXISTS 表示将删除所有 Rows,其中子查询 (SELECT 1 FROM Temp AS IL2 WHERE Temp.A = IL2.A AND Temp.B = 1 AND IL2.B = 5) 获得超过 0 个结果。

      所以看看子查询。基本上它会第二次从 temp 中选择所有值。

      • DELETE FROM Temp -> 第一次(引用为Temp
      • SELECT 1 FROM temo AS IL2 -> 第二次(引用为IL2

      现在子查询有自己的 where 子句,在其中比较两个表(TempIL2):

      • 在 Temp 和 IL2 中,A 必须相等
      • 在 Temp 中,B 必须为 1
      • 在 IL2 中,B 必须为 5

      只有 2 行,其中这些子句为真(因此返回):第 1 行和第 2 行。

      【讨论】:

      • 谢谢。我对子查询有相同的想法(第 1 行和第 2 行将返回),但实验表明只有第 1 行返回“(SELECT 1 FROM Temp AS IL2 WHERE Temp.A = IL2.A AND Temp .B = 1 AND IL2.B = 5)”,我明白。
      • @Zhongkun Ma:第一条语句返回第1行,因为它的B为1,并且表中存在A相同且B = 5的记录。第二条语句返回第 2 行,因为它的 B 为 5,并且表中存在一条具有相同 A 且 B = 1 的记录(前提是您尚未运行第一条语句并删除了该记录)。同一个表被查询了两次,这不应该让您感到困惑。也许它有助于想象真的存在另一个名为 IL2 的表具有完全相同的数据。
      • @ThorstenKettner:我想我明白了,但要确认一件事。 “(select 1 from Temp)”表示从Temp表中选择结果,“Temp.B = 1”表示选择结果表Temp中的B字段必须为1。我正确吗?
      • @Zhongkun Ma:我已经写了一个额外的答案来逐步解释整个过程。
      • @ThorstenKettner:我衷心感谢你。这对我来说非常清楚。
      猜你喜欢
      • 2015-10-13
      • 1970-01-01
      • 2020-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多