《PostgreSQL 開發指南》 第 19 篇 集合操作

數據庫中的表(table)本質上就是由行(row)組成的集合。因此,PostgreSQL 同樣支持集合論中的集合操作,包括並集(UNION)、交集(INTERSECT)和差集(EXCEPT):

  • UNION操作符用於將兩個查詢結果合併成一個結果集,返回出現在第一個查詢或者出現在第二個查詢中的數據;
  • INTERSECT操作符用於返回兩個查詢結果中的共同部分,即同時出現在第一個查詢結果和第二個查詢結果中的數據;
  • EXCEPT操作符用於返回出現在第一個查詢結果中,但不在第二個查詢結果中的數據。

這三個操作符的作用如下圖所示:

set
集合操作符要求參與運算的兩個查詢結果具有相同數量的列,以及對應列的類型必須匹配或兼容。

UNION

UNION操作符用於將兩個查詢結果合併成一個結果集,返回出現在第一個查詢或者出現在第二個查詢中的數據:

SELECT column1, column2
  FROM table1 
 UNION [DISTINCT | ALL]
SELECT col1, col2
  FROM table2;

其中,DISTINCT表示將合併後的結果集進行去重;ALL表示保留結果集中的重複記錄;如果省略,默認爲DISTINCT。例如:

select * from (values(1),(2)) t1(n)
union
select * from (values(1),(3)) t2(n);
n|
-|
1|
2|
3|

select * from (values(1),(2)) t1(n)
union all
select * from (values(1),(3)) t2(n);
n|
-|
1|
2|
1|
3|

第一個查詢結果中只有一個數字 1;第二個查詢結果中保留了重複的數字 1。

INTERSECT

INTERSECT操作符用於返回兩個查詢結果中的共同部分,即同時出現在第一個查詢結果和第二個查詢結果中的數據:

SELECT column1, column2
  FROM table1 
INTERSECT [DISTINCT | ALL]
SELECT col1, col2
  FROM table2;

其中,DISTINCT表示將合併後的結果集進行去重;ALL表示保留結果集中的重複記錄;如果省略,默認爲DISTINCT。例如:

select * from (values(1),(2)) t1(n)
intersect
select * from (values(1),(3)) t2(n);
n|
-|
1|

select * from (values(1),(1),(2)) t1(n)
intersect all
select * from (values(1),(3)) t2(n);
n|
-|
1|

select * from (values(1),(1),(2)) t1(n)
intersect all
select * from (values(1),(1),(3)) t2(n);
n|
-|
1|
1|

第一個查詢結果中只有一個數字 1;第二個查詢雖然使用了 ALL 選項,結果也只有一個1;第三個查詢結果中有兩個 1。

EXCEPT

EXCEPT操作符用於返回出現在第一個查詢結果中,但不在第二個查詢結果中的數據:

SELECT column1, column2
  FROM table1 
EXCEPT [DISTINCT | ALL]
SELECT col1, col2
  FROM table2;

其中,DISTINCT表示將合併後的結果集進行去重;ALL表示保留結果集中的重複記錄;如果省略,默認爲DISTINCT。例如:

select * from (values(1),(1),(2)) t1(n)
except
select * from (values(1),(3)) t2(n);
n|
-|
2|

select * from (values(1),(1),(2)) t1(n)
except all
select * from (values(1),(3)) t2(n);
n|
-|
1|
2|

第一個查詢結果中沒有數字 1;第二個查詢結果中保留了一個數字 1。

分組與排序

對於分組操作,集合操作符中的每個查詢都可以包含一個GROUP BY,不過它們只針對各自進行分組;如果想要對最終結果進行分組,需要在外層嵌套一個 SELECT 語句:

select n, count(*) from (
  select * from (values(1),(2)) t1(n)
  union all
  select * from (values(1),(3)) t2(n)) t
group by n;
n|count|
-|-----|
1|    2|
2|    1|
3|    1|

如果要對集合運算的數據進行排序,需要將ORDER BY子句寫在最後;集合操作符中的第一個查詢中不能出現排序操作:

select * from (values(1),(2)) t1(n)
order by n
union all
select * from (values(1),(3)) t2(n);
SQL Error [42601]: ERROR: syntax error at or near "union"
  Position: 50

select * from (values(1),(2)) t1(n)
union all
select * from (values(1),(3)) t2(n)
order by n;
n|
-|
1|
1|
2|
3|

集合操作優先級

PostgreSQL 支持同時使用多個集合操作符,此時我們需要注意它們的優先級:

SELECT column1, column2
  FROM table1 
 UNION [DISTINCT | ALL]
SELECT col1, col2
  FROM table2
INTERSECT [DISTINCT | ALL]
SELECT c1, c2
  FROM table3;

多個集合操作符使用以下執行順序:

  • 相同的集合操作符按照從左至右的順序執行;
  • INTERSECT的優先級高於UNIONEXCEPT
  • 使用括號可以修改集合操作的執行順序。

以下示例使用了兩個UNION操作符,其中一個增加了 ALL 選項:

select * from (values(1)) t1(n)
union all
select * from (values(1)) t2(n)
union
select * from (values(1)) t3(n);
n|
-|
1|

查詢最終的結果只有一個數字 1,因爲最後的UNION去除了重複的數據。

以下示例使用了兩個不同的集合操作符:

select * from (values(1)) t1(n)
union all
select * from (values(1)) t2(n)
intersect
select * from (values(1)) t3(n);
n|
-|
1|
1|

查詢最終的結果包含了兩個數字 1,因爲INTERSECT先執行,最後的UNION ALL保留了重複的數據。

我們最後看一個使用括號的示例:

(
select * from (values(1)) t1(n)
union all
select * from (values(1)) t2(n)
)
intersect
select * from (values(1)) t3(n);
n|
-|
1|

歡迎關注❤️、點贊👍、轉發📣

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章