交叉申请中的分组依据

时间:2019-04-11 07:46:43

标签: sql sql-server postgresql lateral-join

让我们有两个表

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

按如下所示返回预期结果

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

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

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 Server和PostgreSQL上进行测试(使用cross join lateral而不是cross apply)。为什么group by使行消失?似乎cross apply在第一种情况下表现为外部联接,在后一种情况下表现为内部联接。但是,我不清楚为什么。

2 个答案:

答案 0 :(得分:3)

分别查看内部查询的结果时可以看到以下内容:

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

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

,因此交叉联接不会返回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

我不知道在SQL Server中相当于left join lateral的情况。
on true需要写成on 1=1

答案 1 :(得分:1)

它的发生是因为:

  • GROUP BYA.fkb = 2
  • 时不返回任何内容
  • GROUP BY返回NULL

因此,您的查询CROSS APPLY返回了不同的结果。

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