PostgreSQL 資料庫中 DISTINCT 關鍵字的 4 種用法
大家好,我是隻談技術不剪髮的 Tony 老師。PostgreSQL 不但高度相容 SQL 標準,同時還對很多語法進行了擴充套件,可以用於實現一些特殊的功能。今天我們就來介紹一下 PostgreSQL 資料庫中 DISTINCT 關鍵字的 4 種不同用法。
本文示例資料點此下載,如果覺得文章有用,歡迎評論?、點贊?、推薦?
DISTINCT
按照 SQL 標準,SELECT DISTINCT
可以在返回查詢結果之前去除重複的記錄,每個重複的資料組中只保留一條記錄。例如:
SELECT DISTINCT dept_id, sex
FROM employee;
dept_id|sex|
-------|---|
4|男 |
1|男 |
4|女 |
5|男 |
3|女 |
2|男 |
以上語句中的 DISTINCT 表示返回不同部門 id 和性別的組合值。我們也可以使用 GROUP BY 實現相同的結果:
SELECT dept_id, sex
FROM employee
GROUP BY dept_id, sex;
?按照 SQL 標準,多個 NULL 值對於 DISTINCT 而言屬於相同的分組。
DISTINCT ON
考慮一個問題:每個部門中月薪最高的員工都是誰?這個問題可以使用多種實現方法:
-- 子查詢
SELECT dept_id, emp_name,salary
FROM employee
WHERE (dept_id, salary) IN ( SELECT dept_id, MAX(salary)
FROM employee
GROUP BY dept_id );
dept_id|emp_name|salary |
-------|--------|--------|
1|劉備 |30000.00|
2|諸葛亮 |24000.00|
3|孫尚香 |12000.00|
4|趙雲 |15000.00|
5|法正 |10000.00|
-- 視窗函式
WITH ranked_employee AS (
SELECT dept_id, emp_name, salary, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) rn
FROM employee
)
SELECT *
FROM ranked_employee
WHERE rn = 1;
dept_id|emp_name|salary |rn|
-------|--------|--------|--|
1|劉備 |30000.00| 1|
2|諸葛亮 |24000.00| 1|
3|孫尚香 |12000.00| 1|
4|趙雲 |15000.00| 1|
5|法正 |10000.00| 1|
其中,第一個語句使用了子查詢;第二個語句使用了視窗函式,除了 ROW_NUMBER 之外,也可以使用 RANK 或者 DENSE_RANK 等函式。這兩者都是 SQL 標準實現。
除此之外,PostgreSQL 提供了擴充套件的 DISTINCT ON 子句,可以更加方便地實現以上結果:
SELECT DISTINCT ON (dept_id) dept_id, emp_name, salary
FROM employee
ORDER BY dept_id, salary DESC;
dept_id|emp_name|salary |rn|
-------|--------|--------|--|
1|劉備 |30000.00| 1|
2|諸葛亮 |24000.00| 1|
3|孫尚香 |12000.00| 1|
4|趙雲 |15000.00| 1|
5|法正 |10000.00| 1|
其中,DISTINCT ON (dept_id) 表示部門 id 相同的資料組,返回其中的第一條記錄;ORDER BY 子句確保了返回的是每個部分中月薪最高的記錄。DISTINCT ON 中的欄位或表示式(可能多個)必須和 ORDER BY 最左側的幾個欄位或表示式相同。
IS DISTINCT FROM
空值(NULL)是資料庫中的一個特殊值,通常用於表示缺失值或者不適用的值。空值的比較是一個比較容易出錯的問題。例如:
WITH t AS (
SELECT 1 AS a, 1 AS b
UNION ALL
SELECT 1, 2
UNION ALL
SELECT NULL, 1
UNION ALL
SELECT NULL, NULL )
SELECT a, b, a = b "a=b"
FROM t;
a |b |a=b |
----|----|-----|
1 |1 |true |
1 |2 |false|
NULL|1 |NULL |
NULL|NULL|NULL |
當我們使用比較運算子(=、<>、<、> 等)與 NULL 進行比較時,結果既不是真也不是假,而是未知;因為 NULL 表示未知,也就意味著可能是任何值;我們不能說兩個未知的值相同,也不能說它們不相同。
為了比較 NULL 值,SQL 定義了兩個專用的運算子:IS NULL
和IS NOT NULL
。例如:
SELECT 1 IS NULL "1 IS NULL",
1 IS NOT NULL "1 IS NOT NULL",
NULL IS NULL "NULL IS NULL",
NULL IS NOT NULL "NULL IS NOT NULL";
1 IS NULL|1 IS NOT NULL|NULL IS NULL|NULL IS NOT NULL|
---------|-------------|------------|----------------|
false |true |true |false |
因此,對於兩個可能為空的欄位進行比較的完整方法如下:
WITH t AS (
SELECT 1 AS a, 1 AS b
UNION ALL
SELECT 1, 2
UNION ALL
SELECT NULL, 1
UNION ALL
SELECT NULL, NULL )
SELECT a, b,
(a IS NULL AND b IS NULL)
OR
(a IS NOT NULL AND b IS NOT NULL AND a = b) "a=b"
FROM t;
a |b |a=b |
----|----|-----|
1 |1 |true |
1 |2 |false|
NULL|1 |false|
NULL|NULL|true |
以上語句返回了我們期望的結果,但是讀寫都很不方便;為此,PostgreSQL 提供了擴充套件的 IS [NOT] DISTINCT FROM 運算子,支援 NULL 值的比較。例如:
WITH t AS (
SELECT 1 AS a, 1 AS b
UNION ALL
SELECT 1, 2
UNION ALL
SELECT NULL, 1
UNION ALL
SELECT NULL, NULL )
SELECT a, b, a IS NOT DISTINCT FROM b "a=b"
FROM t;
a |b |a=b |
----|----|-----|
1 |1 |true |
1 |2 |false|
NULL|1 |false|
NULL|NULL|true |
注意,IS NOT DISTINCT FROM 表示判斷兩個資料是否相同,IS DISTINCT FROM 表示判斷兩個資料是否不同;它們都將 NULL 看作已知的一個特殊值,而不是 SQL 標準中的未知值。顯然這種語法更加言簡意賅。
另外,PostgreSQL 還提供了一個配置變數 transform_null_equals,該引數預設為 off;如果設定為 on,PostgreSQL 會自動執行 convert x = NULL 到 x IS NULL 的轉換。建議不要依賴這個引數的設定,而是應該修改應用程式
?關於 SQL 空值的詳細討論以及它們在 MySQL、Oracle、SQL Server、PostgreSQL、SQLite 中的具體實現,可以參考這篇文章。
聚合函式與 DISTINCT
聚合函式(aggregate function)針對一組資料行進行運算,並且返回一條結果。PostgreSQL 支援的聚合函式包括 AVG、COUNT、MAX/MIN、SUM、STRING_AGG、ARRAY_AGG 等。例如:
SELECT dept_id, count(*), avg(salary), string_agg(emp_name, ',' ORDER BY salary DESC)
FROM employee
GROUP BY dept_id
ORDER BY dept_id;
dept_id|count|avg |string_agg |
-------|-----|----------------------|--------------------------------------|
1| 3| 26666.666666666667|劉備,關羽,張飛 |
2| 3|13166.6666666666666667|諸葛亮,黃忠,魏延 |
3| 2| 9000.0000000000000000|孫尚香,孫丫鬟 |
4| 9| 7577.7777777777777778|趙雲,周倉,關興,關平,趙氏,廖化,張苞,趙統,馬岱|
5| 8| 5012.5000000000000000|法正,簡雍,孫乾,糜竺,黃權,龐統,鄧芝,蔣琬 |
以上語句返回了每個部門的員工人數、平均月薪以及所有員工姓名的連線字串(按照月薪從高到低)。
PostgreSQL 不僅實現了分組聚合操作,還支援聚合函式中的 DISTINCT 選項,可以在進行彙總之前去除每個分組中的重複記錄。例如:
SELECT dept_id, string_agg(sex, ','), string_agg(DISTINCT sex, ',') string_agg_distinct
FROM employee
GROUP BY dept_id
ORDER BY dept_id;
dept_id|string_agg |string_agg_distinct|
-------|-----------------------|-------------------|
1|男,男,男 |男 |
2|男,男,男 |男 |
3|女,女 |女 |
4|男,女,男,男,男,男,男,男,男|女,男 |
5|男,男,男,男,男,男,男,男 |男 |
相關文章
- 資料庫SQL語句中關於explain關鍵字的用法資料庫SQLAI
- 資料庫關鍵詞 drop、truncate和delete的用法資料庫delete
- Java中的各種關鍵字Java
- 21、super關鍵字的用法
- 資料庫Delete的多種用法資料庫delete
- 4關鍵字
- 詳解C++的模板中typename關鍵字的用法C++
- Python+資料庫測試常用關鍵字Python資料庫
- SQL資料庫中Truncate的用法SQL資料庫
- Python標準庫datetime中4種基本物件的用法Python物件
- 【PostgreSQL 】PostgreSQL 15對distinct的優化SQL優化
- 探討PostgreSQL例項中資料庫之間的關係SQL資料庫
- ABAP關鍵字 IS BOUND, IS NOT INITIAL和IS ASSIGNED的用法辨析
- 資料庫的主外來鍵關係資料庫
- 【資料庫】PostgreSQL中使用`SELECT DISTINCT`和`SUBSTRING`函式實現去重查詢資料庫SQL函式
- 【PG管理】postgresql資料庫管理相關SQL資料庫
- Mac電腦中delete鍵的七種用法!Macdelete
- C++11 noexcept 關鍵字用法學習C++
- 一文徹底弄懂this關鍵字用法
- sql - distinct 去重複的用法SQL
- mysql 中的explain關鍵字MySqlAI
- java中的instanceof關鍵字Java
- java中的static關鍵字Java
- java中this關鍵字Java
- Java:synchronized關鍵字引出的多種鎖Javasynchronized
- 埋在 MYSQL 資料庫應用中的17個關鍵問題!MySql資料庫
- 帶你瞭解資料庫中group by的用法資料庫
- 帶你瞭解資料庫中JOIN的用法資料庫
- 在MySQL資料庫中,這4種方式可以避免重複的插入資料!MySql資料庫
- Java開發筆記(五十五)關鍵字static的用法Java筆記
- 從鍵盤鍵入String型別的資料插入資料庫中型別資料庫
- PostgreSQL:資料庫的選擇SQL資料庫
- HGDB怎麼獲取資料庫中關鍵系統資訊資料庫
- 完全理解JavaScript中的this關鍵字JavaScript
- Java中transient關鍵字的作用Java
- java中static關鍵字的作用Java
- 在Java中this關鍵字的使用Java
- C++中的 const 關鍵字C++