PSQL除外与全部除外

and*_*ish 0 sql postgresql

我有以下架构:

create table Took(
sID integer,
oID integer,
grade integer);



INSERT INTO Took VALUES
    (1, 1, 90),
    (1, 2, 100),
    (2, 1, 90),
    (2, 3, 80),
    (2, 4, 85)
;
Run Code Online (Sandbox Code Playgroud)

我也有以下查询:

(select sid from took) except all (select sid from took where grade < 90);
Run Code Online (Sandbox Code Playgroud)

1,1,2由于在这种情况下等级值> = 90 ,因此产生了预期的输出。但是,当我删除该all子句以

select sid from took) except (select sid from took where grade < 90);
Run Code Online (Sandbox Code Playgroud)

输出为1。我知道all确定是否存在重复项,因此在这种情况下,我希望输出1,2不是1。发生什么了?

小智 5

从PSQL文档中,单独使用EXCEPT时:

EXCEPT运算符计算左SELECT语句的结果中的行集,而不计算右SELECT语句的结果中的行集。

但是,当ALL与EXCEPT一起使用时:

除非指定了ALL选项,否则EXCEPT的结果将不包含任何重复的行。使用ALL,在左表中具有m个重复项并且在右表中具有n个重复项的行将在结果集中出现max(mn,0)次。

在您的示例中,左SELECT查询的结果将是所有行的sid。

test=# select sid from took;
 sid
-----
   1
   1
   2
   2
   2
(5 rows)
Run Code Online (Sandbox Code Playgroud)

并且,正确的SELECT查询的结果将是成绩<90的最后两行。

test=# select sid from took where grade < 90;
 sid
-----
   2
   2
(2 rows)
Run Code Online (Sandbox Code Playgroud)

现在,仅使用EXCEPT运行查询:

test=# (select sid from took) except (select sid from took where grade < 90);
 sid
-----
   1
(1 row)
Run Code Online (Sandbox Code Playgroud)

这里发生的是

  1. 我们采用左SELECT查询(5行)的结果。
  2. 然后,删除所有包含右SELECT查询结果的匹配行(即sid = 2),剩下2行,其中sid = 1。
  3. 现在,由于将没有重复项,因此最终结果将是1行且sid = 1。

这是对您得到的结果的解释。

现在,使用EXCEPT ALL运行查询:

test=# (select sid from took) except all (select sid from took where grade < 90);
 sid
-----
   1
   1
   2
(3 rows)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们只需从左SELECT查询的结果中删除右SELECT查询的结果即可。

希望这可以帮助。