【问题标题】:Sql query LEFT JOIN / NULL joining logicSql 查询 LEFT JOIN / NULL 连接逻辑
【发布时间】:2021-04-25 02:20:05
【问题描述】:

我想了解以下查询背后的连接逻辑?? 下面是正在使用的表格

on t1.log_id-1 = t2.log_id
    where t2.log_id is null

完整查询:-

select start_id, min(end_id) as end_id
from (
    select t1.log_id as start_id
    from logs as t1
    left join logs as t2
        on t1.log_id-1 = t2.log_id
    where t2.log_id is null
) tt_start
join (
    select t1.log_id as end_id
    from logs as t1
    left join logs as t2
        on t1.log_id+1 = t2.log_id
    where t2.log_id is null
) tt_end
where start_id<=end_id
group by start_id

表:-

Log_id
1
2
3
7
8
10

【问题讨论】:

  • 请格式化您的 SQL,使其更具可读性。
  • 你的问题到底是什么?
  • 这能回答你的问题吗? How to Join to first row
  • @RakshaSaini 几乎完全不相关。这是一个不存在的语法,不是顶级 1
  • 请始终使用您正在使用的 DBMS 标记 SQL 请求。这可能非常重要,因为 SQL 方言有时会有很大差异。

标签: sql left-join not-exists


【解决方案1】:

这是自联接和反联接的组合。

  1. 自连接:表连接到自身(此处连接到 ID 减或加 1 的行)。
  2. 反连接:左外连接和WHERE 子句仅保留外连接行,从而保留左表中没有匹配的所有行。这是一种在年轻 DBMS 上使用的相当常见的技术,其中连接已经非常优化,而更直接的方法 NOT EXISTSNOT IN 还没有。

这个查询的作用是:

  1. 查找没有直接前任的 ID。例如。对于 ID 1、2、4、5、6、8、10、12、23、24,我们将找到 1、4、8、10、12 和 23。
  2. 查找没有直接追随者的 ID。例如。对于 ID 1、2、4、5、6、8、10、12、23、24,我们将找到 2、6、8、10、12 和 24。
  3. 将前者与后者连接,其中前者
  4. 获取每个起始 ID 的最小结束 ID:1-2、4-6、8-8、10-10、12-12、23-24。

查询因此找到数字范围。 1、2、4、5、6、8、10、12、23、24 = 1-2、4-6、8、10、12、23-24。

这种任务称为间隙和孤岛问题。大多数情况下,这些问题可以通过窗口函数来解决:

select min(log(id), max(log_id)
from
(
  select
    log_id,
    log_id - row_number() over (order by log_id) as grp
  from logs
) grouped
group by grp
order by grp;

演示:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=3eaeb881c8e5498a02fa0ff34f4cffc3

【讨论】:

    【解决方案2】:

    这是一种not exists 逻辑。仅当过滤列不能为空如果有匹配的行时才有效。

    直接使用not exists会好很多,因为优化器可以更好的理解,直接转化为反连接。例如:

    where not exists (select 1
        from logs as t2
        where t1.log_id-1 = t2.log_id)
    

    left join 构造通常由不了解情况的人使用,因为在大多数优化器实现中,该构造并没有得到很好的理解。

    例如,在 SQL Server 中,保证只有一行的查询计划子树对于某些优化非常有用。由于left join 理论上可以将行加倍,因此不存在此保证。尽管你我都知道这是不可能的,但优化器中并没有对此的逻辑。

    【讨论】:

      【解决方案3】:

      where 不是连接逻辑的一部分,它是一个仅在连接逻辑之后应用的过滤器。

      在我看来 ON t1.log_id-1 = t2.log_idWHERE t2.log_id IS NULL 的组合应该给你零行。如果t2.log_id 的值为空,则它也不能比t1.log_id 小一。

      【讨论】:

      • 解释是这是一个outer连接。没有 t2 匹配的 t1 行与空的 t2 列连接。 where t2.log_id is null 然后删除所有匹配项并仅保留 t1 没有匹配项的行。这种方法称为反连接。正如 Charlieface 在他们的回答中解释的那样,这是一种相当模糊的方式,只是说 where not exists ...
      猜你喜欢
      • 2015-01-10
      • 2018-08-02
      • 2013-05-22
      • 1970-01-01
      • 1970-01-01
      • 2015-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多