交叉应用中的 GROUP BY

GROUP BY in CROSS APPLY

让我们有两个表

create table A (
  fkb int,
  groupby int
);

create table B (
  id int,
  search int
);

insert into A values (1, 1);
insert into B values (1, 1);
insert into B values (2, 1);

然后是下面的查询

select B.id, t.max_groupby - B.search diff
from B
cross apply ( 
  select max(A.groupby) max_groupby
  from A 
  where A.fkb = B.id 
) t

return预期结果如下

id  diff
---------
1   0
2   NULL

但是,当我将 group by A.fkb 添加到交叉应用中时,相应 A.fkb 不存在的 B 行消失了。

select B.id, t.max_groupby - B.search diff
from B
cross apply ( 
  select max(A.groupby) max_groupby
  from A 
  where A.fkb = B.id 
  group by A.fkb
) t

我在 SQL 服务器和 PostgreSQL 上进行测试(使用 cross join lateral 而不是 cross apply)。为什么 group by 使该行消失? cross apply 似乎在第一种情况下表现为外部连接,在后一种情况下表现为内部连接。但是,我不清楚为什么。

发生这种情况是因为:

  • GROUP BY returns A.fkb = 2
  • 什么都没有
  • 没有 GROUP BY returns NULL

所以你的查询 CROSS APPLY returns 不同的结果。

select B.id, t.max_groupby - B.search diff
from B
outer apply ( 
  select max(A.groupby) max_groupby
  from A 
  where A.fkb = B.id 
  group by A.fkb
) t

输出:

id  diff
1   0
2   NULL

单独看内层查询结果可以看到:

select max(A.groupby) max_groupby
from A 
where A.fkb = 2;

returns 单行 max_groupby = null:

max_groupby
-----------
     (null)

然而,由于没有包含 A.fkb = 2 分组的行,它会产生一个空结果,您可以在 运行:

时看到
select max(A.groupby) max_groupby
from A 
where A.fkb = 2
group by A.fkb

因此交叉联接不会 return return 行 fkb = 2

您需要使用外部联接才能包含来自 B 的行。

在 Postgres 中你必须这样写:

select B.id, t.max_groupby - B.search diff
from B
  left join lateral ( 
    select max(A.groupby) max_groupby
    from A 
    where A.fkb = B.id 
    group by A.fkb
  ) t on true

我不知道 left join lateral 在 SQL 服务器中的等价物是什么。
on true 需要写成 on 1=1 .