PostgreSQL 13 新特性之 FETCH FIRST WITH TIES
作者: 不剪發(fā)的Tony老師
畢業(yè)于北京航空航天大學,十多年數(shù)據(jù)庫管理與開發(fā)經(jīng)驗,目前在一家全球性的金融公司從事數(shù)據(jù)庫架構(gòu)設(shè)計。CSDN學院簽約講師以及GitChat專欄作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net
文章目錄
測試數(shù)據(jù)
PostgreSQL 12 之前的實現(xiàn)
PostgreSQL 13 的增強功能
注意事項
總結(jié)
大家好,我是只談技術(shù)不剪發(fā)的 Tony 老師。
PostgreSQL 全球開發(fā)組于 2020 年 9 月 24 日宣布 PostgreSQL 13 正式發(fā)布。接下來我會通過一系列文章為大家解析這個新版本帶來的功能增強,本文先給大家介紹一個與 SQL 開發(fā)相關(guān)的新特性:FETCH FIRST 子句增加了 WITH TIES 選項,可以用于返回更多排名相同的數(shù)據(jù)行。
如果覺得文章有用,歡迎關(guān)注??、評論??、點贊??
測試數(shù)據(jù)
首先,我們創(chuàng)建一個簡單的測試表 t 并插入一些數(shù)據(jù):
CREATE TABLE t(name varchar(20), score int);
INSERT INTO t VALUES('張三', 80), ('李四', 77), ('王五', 80), ('趙六', 90), ('孫七', 80);
SELECT * FROM t;
name |score|
-----|-----|
張三 | 80|
李四 | 77|
王五 | 80|
趙六 | 90|
孫七 | 80|
該表中只包含姓名和分數(shù) 2 個字段,其中有 3 個學生的分數(shù)相同。
PostgreSQL 12 之前的實現(xiàn)
PostgreSQL 12 以及之前的版本實現(xiàn)了 SQL 標準中的 FETCH 子句:
OFFSET start { ROW | ROWS }
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY
其中,OFFSET 表示跳過指定的 start 行數(shù), 默認為 0;FETCH 表示最多返回 count 行結(jié)果,默認為 1;ROW 和 ROWS 是同義詞,F(xiàn)IRST 和 NEXT 是同義詞;ONLY 表示不返回更多的數(shù)據(jù)。
例如,以下語句返回了分數(shù)最高的 2 個學生:
SELECT *
FROM t
ORDER BY score DESC
FETCH FIRST 2 ROWS ONLY;
name |score|
-----|-----|
趙六 | 90|
張三 | 80|
雖然的確返回了分數(shù)最高的兩條記錄,但是從表中的數(shù)據(jù)可以看出分數(shù)為 80 的還有兩名同學,如果計算排名的話他們也應(yīng)該是第二名。
另外需要注意,如果沒有指定 ORDER BY 子句,查詢將會返回隨機的 2 行記錄:
SELECT *
FROM t
FETCH FIRST 2 ROWS ONLY;
name |score|
-----|-----|
張三 | 80|
李四 | 77|
??PostgreSQL 還支持另一種限定查詢結(jié)果數(shù)量的子句:LIMIT { count | ALL } OFFSET start,也可以實現(xiàn)相同的功能。
PostgreSQL 13 的增強功能
為了解決返回排名相同的數(shù)據(jù)問題,PostgreSQL 13 對 FETCH FIRST 子句進行了增強:
OFFSET start { ROW | ROWS }
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }
其中,WITH TIES 選項表示返回排名和最后一行相同的額外數(shù)據(jù)行,而且必須同時指定 ORDER BY 子句。例如,以下語句返回了分數(shù)排名前 2 的所有學生:
SELECT *
FROM t
ORDER BY score DESC
FETCH FIRST 2 ROWS WITH TIES;
name |score|
-----|-----|
趙六 | 90|
張三 | 80|
王五 | 80|
孫七 | 80|
如果使用 WITH TIES 選項時沒有指定 ORDER BY 子句,將會返回錯誤:
SELECT *
FROM t
FETCH FIRST 2 ROWS WITH TIES;
RROR: WITH TIES cannot be specified without ORDER BY clause
注意事項
使用 WITH TIES 選項時需要注意一點,F(xiàn)ETCH FIRST 語句返回的結(jié)果數(shù)量不再是確定值。例如在上面的語句中,雖然指定了 count 為 2,但實際返回了 4 行數(shù)據(jù)。如果我們基于這個功能實現(xiàn)分頁查詢,需要記錄每次實際返回的行數(shù);對應(yīng)上面的示例,第一頁返回 4 行數(shù)據(jù),查詢第二頁時的語句如下:
SELECT *
FROM t
ORDER BY score
OFFSET 4
FETCH FIRST 2 ROWS WITH TIES;
其中,OFFSET 4 是上一頁實際返回的行數(shù)。
另外,這種情況下的 ORDER BY 子句中不能出現(xiàn)其他用于排序顯示的字段。假如我們想要找出分數(shù)前 2 名的所有學生,同時對于分數(shù)相同的學生按照姓名拼音進行排序:
SELECT *
FROM t
ORDER BY score DESC, name COLLATE "zh_CN"
FETCH FIRST 2 ROWS WITH TIES;
name |score|
-----|-----|
趙六 | 90|
孫七 | 80|
由于 name 字段出現(xiàn)在 ORDER BY 中,其他分數(shù)為 80 的學生不再被認為是排名相同的數(shù)據(jù),除非他們的姓名也叫做“孫七”。為了解決這個問題,可以增加一個子查詢或者使用通用表表達式(WITH 子句):
WITH d AS (
SELECT *
FROM t
ORDER BY score DESC
FETCH FIRST 2 ROWS WITH TIES
)
SELECT *
FROM d
ORDER BY score DESC, name COLLATE "zh_CN";
name |score|
-----|-----|
趙六 | 90|
孫七 | 80|
王五 | 80|
張三 | 80|
其中,第一個 ORDER BY 用于分數(shù)排名,第二個 ORDER BY 用于最終的排序顯示。
??按照 SQL 標準,除了可以使用 count 限定返回的行數(shù)之外,還可以使用 N PERCENT 按照百分比限定返回的行數(shù)。PostgreSQL 目前沒有實現(xiàn)這一功能。
總結(jié)
作為世界上最先進的開源數(shù)據(jù)庫,PostgreSQL 新版本增加了 FETCH FIRST 子句對于 WITH TIES 的支持,為應(yīng)用程序開發(fā)提供了更多的便利。關(guān)于 PostgreSQL 13 新特性的更多內(nèi)容,可以參考這篇文章。