【问题标题】:SQL filter LEFT TABLE before left join左连接之前的SQL过滤LEFT TABLE
【发布时间】:2017-07-06 10:31:24
【问题描述】:

我已经阅读了 SO 的一些帖子,并且我了解在 where 子句和 on 子句中过滤之间的区别。但是这些示例中的大多数都在 RIGHT 表上进行过滤(使用左连接时)。如果我有如下查询:

select * from tableA A left join tableB B on A.ID = B.ID and A.ID = 20

返回值不是我所期望的。我会认为它首先过滤左表并仅获取 ID = 20 的行,然后与 tableB 进行左连接。

当然,这在技术上应该和做的一样:

select * from tableA A left join table B on A.ID = B.ID where A.ID = 20

但我认为如果您可以在进行联接之前过滤表,性能会更好。有人可以告诉我这个 SQL 是如何处理的,并帮助我彻底理解这一点。

【问题讨论】:

    标签: sql oracle left-join


    【解决方案1】:

    left join 遵循一个简单的规则。它保留第一个表中的所有行。列的取决于on 子句。如果不匹配,则对应表的列为NULL——无论是第一表还是第二表。

    所以,对于这个查询:

    select *
    from tableA A left join
         tableB B
         on A.ID = B.ID and A.ID = 20;
    

    A 中的所有行都在结果集中,无论是否匹配。当 id 不是 20 时,行和列仍然取自A。但是,条件为假,所以B 中的列是NULL。这是一个简单的规则。它不取决于条件是在第一个表还是第二个表上。

    对于这个查询:

    select *
    from tableA A left join
         tableB B
         on A.ID = B.ID 
    where A.ID = 20;
    

    from 子句保留A 中的所有行。但随后where 子句产生了效果。它会过滤行,因此结果集中只有 id 20s。

    使用left join时:

    • 第一个表的过滤条件放在where 子句中。
    • 后续表的过滤条件放在on 子句中。

    【讨论】:

    • 感谢您的回复,但您能否详细说明一下“当 id 不是 20 时,列值为 NULL”。您的意思是tableB的ID不是20,那么tableB中的所有列都将为空?有这个用例吗?还是应该对第一个表进行过滤总是去 where 子句?
    • @TFK 。 . .我修正了措辞。
    【解决方案2】:

    在您的第一个 SQL 语句中,A.ID=20 在技术上并未加入任何内容。连接用于将两个单独的表连接在一起,ON 语句通过将列关联为键来连接它们。

    WHERE 语句允许过滤数据,方法是减少仅在该特定列下可以找到该值的情况下返回的行数。

    【讨论】:

      【解决方案3】:

      如果你有来自 tablea,你可以放置一个子查询,比如 from (select x.* from tablea X where x.value=20) TA

      然后像之前的 tablea 一样参考 TA。

      查询优化器可能会为您执行此操作。

      Oracle 应该有办法显示查询计划。将“解释计划”放在 sql 语句之前。双向查看计划,看看它的作用。

      【讨论】:

      • 您在逻辑上是正确的,但优化器不会这样重写它;它是一个 OUTER JOIN 运算符。
      猜你喜欢
      • 2013-02-11
      • 2019-05-02
      • 1970-01-01
      • 2021-12-25
      • 2017-03-10
      • 1970-01-01
      • 2019-07-02
      • 2011-02-01
      • 2013-01-19
      相关资源
      最近更新 更多