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_id
和 WHERE 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
理论上可以将行加倍,因此不存在此保证。即使你我都知道这是不可能的,但优化器中没有逻辑。
这是自连接和反连接的组合。
- 自连接:table 连接到自身(这里连接到 ID 递减或递增 1 的行)。
- 反连接:一个左外连接,然后是一个
WHERE
子句,只保留外连接的行,从而保留从左 table 开始没有匹配的所有行。这是在年轻的 DBMS 上使用的一种相当普遍的技术,其中连接已经非常优化,而更直接的方法 NOT EXISTS
和 NOT IN
还没有。
这个查询的作用是:
- 查找没有直接前导的 ID。例如。对于 ID 1、2、4、5、6、8、10、12、23、24,我们将找到 1、4、8、10、12 和 23。
- 查找没有直接关注者的 ID。例如。对于 ID 1、2、4、5、6、8、10、12、23、24,我们将找到 2、6、8、10、12 和 24。
- 将前者与后者合并,其中前者 <= 后者:1-2、1-6、1-8、...、8-8、8-10、...、23-24 .
- 获取每个开始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
我想了解以下查询背后的连接逻辑?? 下面是正在使用的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_id
和 WHERE 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
理论上可以将行加倍,因此不存在此保证。即使你我都知道这是不可能的,但优化器中没有逻辑。
这是自连接和反连接的组合。
- 自连接:table 连接到自身(这里连接到 ID 递减或递增 1 的行)。
- 反连接:一个左外连接,然后是一个
WHERE
子句,只保留外连接的行,从而保留从左 table 开始没有匹配的所有行。这是在年轻的 DBMS 上使用的一种相当普遍的技术,其中连接已经非常优化,而更直接的方法NOT EXISTS
和NOT IN
还没有。
这个查询的作用是:
- 查找没有直接前导的 ID。例如。对于 ID 1、2、4、5、6、8、10、12、23、24,我们将找到 1、4、8、10、12 和 23。
- 查找没有直接关注者的 ID。例如。对于 ID 1、2、4、5、6、8、10、12、23、24,我们将找到 2、6、8、10、12 和 24。
- 将前者与后者合并,其中前者 <= 后者:1-2、1-6、1-8、...、8-8、8-10、...、23-24 .
- 获取每个开始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