Sql查询LEFT JOIN/NULL连接逻辑

Sql query LEFT JOIN / NULL joining logic

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

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

Table:-

Log_id
1
2
3
7
8
10

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

在我看来,ON t1.log_id-1 = t2.log_idWHERE t2.log_id IS NULL 的组合应该为您提供零行。如果 t2.log_id 的值为 null,则它也不能比 t1.log_id.

小一

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

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

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

left join 构造经常被不太了解的人使用,因为在大多数优化器实现中,这个构造没有被很好地理解。

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

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

  1. 自连接:table 连接到自身(这里连接到 ID 递减或递增 1 的行)。
  2. 反连接:一个左外连接,然后是一个 WHERE 子句,只保留外连接的行,从而保留从左 table 开始没有匹配的所有行。这是在年轻的 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. 将前者与后者合并,其中前者 <= 后者:1-2、1-6、1-8、...、8-8、8-10、...、23-24 .
  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。

这种任务称为间隙和孤岛问题。大多数情况下,这些都是用 window 函数解决的:

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