MSSQL 无法理解操作发生了什么 "having count(*) lesser than <some field of other table>"

MSSQL can't understand what's happening with the action "having count(*) lesser than <some field of other table>"

我试图理解我正在做的练习的某些部分,但就是听不懂。

有一部分选择了 'T',按 'a' 分组,然后重定向到“having count(*) < T3.a”, 我不知道如何处理它。

我试过用谷歌搜索这类东西,看看是否有类似的例子,但所有其他例子都使用常规数字作为例子:“having count(*) < 5”而不是用于比较的整个字段。

练习是这样的:

MSSQL exercise

create table T(a int, b int);
insert into T values(1,2);
insert into T values(1,1);
insert into T values(2,3);
insert into T values(2,4);
insert into T values(3,4);
insert into T values(4,5);

select T3.b, (select count(T5.a) 
              from T T5 
              where T5.a = T3.b)
from (select T1.a as a, T2.b as b 
      from T T1, T T2 
      where T1.b < T2.a) as T3
where not exists (select T4.a 
                  from T T4
                  group by T4.a
                  having count(*) < T3.a);

我认为 having count(*) 正在将每行中分组的每个值与 T3.a 的每个值进行比较,如果所有行都符合标准而不是选择该值,但我以某种方式得到不同的结果。

有人可以向我解释一下这个“having count(*) < T3.a”操作背后到底发生了什么吗?

提前谢谢你。

重复评论,HAVING 就像聚合函数的 WHERE。您不能在 WHERE 中使用聚合函数,例如 WHERE SUM(SomeColumn) > 5,因此您需要在 HAVING 中使用它们:HAVING SUM(SomeColumn) > 5。这将 returns 列 SomeColumnSUM 在组中大于 5 的任何行。

对于您的表达式,HAVING COUNT(*) < T3.a 它只会显示 return 行,其中 COUNT(*) 的值小于 T3.a 的值。

让我们把它分解成单独的部分。

首先是FROM

from (select T1.a as a, T2.b as b 
      from T T1, T T2 
      where T1.b < T2.a) as T3

这使用旧式的已弃用的交叉连接语法。可以改写为普通连接:

from (select T1.a as a, T2.b as b 
      from T T1
      join T T2 on T1.b < T2.a
) as T3

如果我们分析它的作用,我们就会意识到它实际上就是所谓的三角连接:每一行都自连接到比它低的每一行。当 window 聚合不可用时,通常会这样做。


WHERE

where not exists (select T4.a 
                  from T T4
                  group by T4.a
                  having count(*) < T3.a);

这是一个相关子查询:T3.a是对外部查询的引用。

这个谓词的意思是:对于这个特定的行,子查询中必须没有行

子查询本身说:获取 T 中的所有行,按 a 对它们进行分组并计数,然后只包括计数小于外部引用 a 的行.

请注意,因为它是 EXIST,所以不会使用实际选择的值。我怀疑这可能不是本意。


SELECT

select T3.b, (select count(T5.a) 
              from T T5 
              where T5.a = T3.b)

然后我们从第一个连接中获取 b,并从所有匹配的 T 行的子查询中获取计数。同样,当 window 聚合不可用时,这很常见。


所以整个事情可以重写如下:

select T2.b, (select count(T5.a) 
              from T T5 
              where T5.a = T3.b)
from (
    select *, count(*) over (partition by a) as cnt
    from T
) T1
join T T2 on T1.b < T2.a
where T1.cnt < T1.a;

你的查询逻辑有些不太对,但不知道初衷是什么,也没有看到table和列名,我不能说。特别是三角形连接看起来很可疑。