SELECT, TABLE, WITH — 從表或檢視檢索行
[ WITH [ RECURSIVE ]with_query
[, ...] ] SELECT [ ALL | DISTINCT [ ON (expression
[, ...] ) ] ] [ { * |expression
[ [ AS ]output_name
] } [, ...] ] [ FROMfrom_item
[, ...] ] [ WHEREcondition
] [ GROUP BY [ ALL | DISTINCT ]grouping_element
[, ...] ] [ HAVINGcondition
] [ WINDOWwindow_name
AS (window_definition
) [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ]select
] [ ORDER BYexpression
[ ASC | DESC | USINGoperator
] [ NULLS { FIRST | LAST } ] [, ...] ] [ LIMIT {count
| ALL } ] [ OFFSETstart
[ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [count
] { ROW | ROWS } { ONLY | WITH TIES } ] [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OFfrom_reference
[, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ] wherefrom_item
can be one of: [ ONLY ]table_name
[ * ] [ [ AS ]alias
[ (column_alias
[, ...] ) ] ] [ TABLESAMPLEsampling_method
(argument
[, ...] ) [ REPEATABLE (seed
) ] ] [ LATERAL ] (select
) [ [ AS ]alias
[ (column_alias
[, ...] ) ] ]with_query_name
[ [ AS ]alias
[ (column_alias
[, ...] ) ] ] [ LATERAL ]function_name
( [argument
[, ...] ] ) [ WITH ORDINALITY ] [ [ AS ]alias
[ (column_alias
[, ...] ) ] ] [ LATERAL ]function_name
( [argument
[, ...] ] ) [ AS ]alias
(column_definition
[, ...] ) [ LATERAL ]function_name
( [argument
[, ...] ] ) AS (column_definition
[, ...] ) [ LATERAL ] ROWS FROM(function_name
( [argument
[, ...] ] ) [ AS (column_definition
[, ...] ) ] [, ...] ) [ WITH ORDINALITY ] [ [ AS ]alias
[ (column_alias
[, ...] ) ] ]from_item
join_type
from_item
{ ONjoin_condition
| USING (join_column
[, ...] ) [ ASjoin_using_alias
] }from_item
NATURALjoin_type
from_item
from_item
CROSS JOINfrom_item
andgrouping_element
can be one of: ( )expression
(expression
[, ...] ) ROLLUP ( {expression
| (expression
[, ...] ) } [, ...] ) CUBE ( {expression
| (expression
[, ...] ) } [, ...] ) GROUPING SETS (grouping_element
[, ...] ) andwith_query
is:with_query_name
[ (column_name
[, ...] ) ] AS [ [ NOT ] MATERIALIZED ] (select
|values
|insert
|update
|delete
|merge
) [ SEARCH { BREADTH | DEPTH } FIRST BYcolumn_name
[, ...] SETsearch_seq_col_name
] [ CYCLEcolumn_name
[, ...] SETcycle_mark_col_name
[ TOcycle_mark_value
DEFAULTcycle_mark_default
] USINGcycle_path_col_name
] TABLE [ ONLY ]table_name
[ * ]
SELECT
從零個或多個表中檢索行。 SELECT
的一般處理過程如下:
所有 WITH
列表中的查詢都將被計算。這些實際上充當臨時表,可以在 FROM
列表中引用。如果一個 WITH
查詢在 FROM
中被引用多次,則只計算一次,除非使用 NOT MATERIALIZED
明確指定。 (參見下面的 WITH 子句)。
所有 FROM
列表中的元素都將被計算。 ( FROM
列表中的每個元素都是真實或虛擬的表。) 如果 FROM
列表中指定了多個元素,則它們將進行交叉連線。 (參見下面的 FROM 子句)。
如果指定了 WHERE
子句,則所有不滿足條件的行都將從輸出中刪除。 (參見下面的 WHERE 子句)。
如果指定了 GROUP BY
子句,或者存在聚合函式呼叫,則輸出將合併為具有一個或多個相同值的行組,並計算聚合函式的結果。如果存在 HAVING
子句,則它將刪除不滿足給定條件的組。 (參見下面的 GROUP BY 子句 和 HAVING 子句)。雖然查詢輸出列名在下一步中名義上被計算,但它們也可以在 GROUP BY
子句中被引用 (按名稱或序號)。
對於每個選定的行或行組,實際的輸出行是透過 SELECT
輸出表達式計算的。 (參見下面的 SELECT 列表)。
SELECT DISTINCT
從結果中刪除重複的行。 SELECT DISTINCT ON
刪除在所有指定表示式上匹配的行。 SELECT ALL
(預設) 將返回所有候選行,包括重複項。 (參見下面的 DISTINCT 子句)。
使用 UNION
、INTERSECT
和 EXCEPT
運算子,可以將多個 SELECT
語句的輸出組合成一個單一的結果集。 UNION
運算子返回存在於一個或兩個結果集中的所有行。 INTERSECT
運算子返回嚴格存在於兩個結果集中的所有行。 EXCEPT
運算子返回存在於第一個結果集但不存在於第二個結果集中的行。在所有這三種情況下,除非指定了 ALL
,否則會刪除重複行。噪聲詞 DISTINCT
可以被新增以明確指定刪除重複行。請注意,DISTINCT
在這裡是預設行為,儘管 ALL
是 SELECT
本身的預設行為。 (參見下面的 UNION 子句, INTERSECT 子句, 和 EXCEPT 子句)。
如果指定了 ORDER BY
子句,則返回的行將按指定的順序排序。如果未給出 ORDER BY
,則系統會以最快的速度返回行。 (參見下面的 ORDER BY 子句)。
如果指定了 LIMIT
(或 FETCH FIRST
) 或 OFFSET
子句,則 SELECT
語句只返回結果行的一個子集。 (參見下面的 LIMIT 子句)。
如果指定了 FOR UPDATE
, FOR NO KEY UPDATE
, FOR SHARE
或 FOR KEY SHARE
,則 SELECT
語句將鎖定選定的行,防止併發更新。 (參見下面的 鎖定子句)。
您必須對 SELECT
命令中使用的每個列擁有 SELECT
許可權。使用 FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
或 FOR KEY SHARE
還需要 UPDATE
許可權 (至少對每個所選表的其中一列)。
WITH
子句WITH
子句允許您指定一個或多個子查詢,這些子查詢可以被主查詢引用。這些子查詢在主查詢的持續時間內有效地充當臨時表或檢視。每個子查詢都可以是 SELECT
, TABLE
, VALUES
, INSERT
, UPDATE
, DELETE
, 或 MERGE
語句。在 WITH
中編寫資料修改語句 (INSERT
, UPDATE
, DELETE
, 或 MERGE
) 時,通常會包含一個 RETURNING
子句。形成主查詢讀取的臨時表的是 RETURNING
的輸出,而不是語句修改的底層表。如果省略 RETURNING
,則語句仍會執行,但不會產生輸出,因此主查詢無法將其引用為表。
每個 WITH
查詢都必須指定一個名稱 (不帶模式限定)。可選地,可以指定一個列名列表;如果省略此項,則從子查詢推斷出列名。
如果指定了 RECURSIVE
,則允許 SELECT
子查詢按名稱引用自身。這樣的子查詢必須具有以下形式:
non_recursive_term
UNION [ ALL | DISTINCT ]recursive_term
其中遞迴自引用必須出現在 UNION
的右側。每個查詢只允許有一個遞迴自引用。不支援遞迴資料修改語句,但您可以在資料修改語句中使用遞迴 SELECT
查詢的結果。有關示例,請參見 第 7.8 節。
RECURSIVE
的另一個影響是 WITH
查詢不必排序:一個查詢可以引用列表中的另一個稍晚出現的查詢。 (但是,不支援迴圈引用或相互遞迴)。沒有 RECURSIVE
時,WITH
查詢只能引用 WITH
列表前面出現的同級 WITH
查詢。
當 WITH
子句中有多個查詢時,RECURSIVE
只需寫一次,緊跟在 WITH
之後。它適用於 WITH
子句中的所有查詢,儘管它對不使用遞迴或前向引用的查詢沒有影響。
可選的 SEARCH
子句會計算一個 搜尋序列列,該列可用於以廣度優先或深度優先順序對遞迴查詢的結果進行排序。提供的列名列表指定了用於跟蹤已訪問行的行鍵。一個名為 search_seq_col_name
的列將被新增到 WITH
查詢的結果列列表中。該列可以在外部查詢中按順序排列,以實現相應的排序。有關示例,請參見 第 7.8.2.1 節。
可選的 CYCLE
子句用於檢測遞迴查詢中的迴圈。提供的列名列表指定了用於跟蹤已訪問行的行鍵。一個名為 cycle_mark_col_name
的列將被新增到 WITH
查詢的結果列列表中。當檢測到迴圈時,該列將被設定為 cycle_mark_value
,否則設定為 cycle_mark_default
。此外,當檢測到迴圈時,遞迴聯合的處理將停止。 cycle_mark_value
和 cycle_mark_default
必須是常量,並且它們必須可轉換為公共資料型別,並且該資料型別必須具有不等號運算子。(SQL 標準要求它們是布林常量或字元字串,但 PostgreSQL 不要求這樣。) 預設情況下,使用 TRUE
和 FALSE
(型別為 boolean
)。此外,一個名為 cycle_path_col_name
的列將被新增到 WITH
查詢的結果列列表中。該列用於內部跟蹤已訪問的行。有關示例,請參見 第 7.8.2.2 節。
SEARCH
和 CYCLE
子句都只對遞迴 WITH
查詢有效。 with_query
必須是兩個 SELECT
(或等效) 命令的 UNION
(或 UNION ALL
) (不允許巢狀 UNION
)。如果同時使用這兩個子句,則 SEARCH
子句新增的列出現在 CYCLE
子句新增的列之前。
主查詢和 WITH
查詢都是 (名義上) 同時執行的。這意味著 WITH
中的資料修改語句的效果不能被查詢的其他部分看到,除了透過讀取其 RETURNING
輸出。如果兩個這樣的資料修改語句試圖修改同一行,則結果未定義。
WITH
查詢的一個關鍵屬性是,它們通常在主查詢的每次執行中只計算一次,即使主查詢多次引用它們。特別是,資料修改語句保證只執行一次,而不管主查詢是否讀取了它們全部或任何輸出。
但是,WITH
查詢可以被標記為 NOT MATERIALIZED
來移除此保證。在這種情況下,WITH
查詢可以被摺疊到主查詢中,就像它是主查詢 FROM
子句中的簡單子 SELECT
一樣。如果主查詢多次引用該 WITH
查詢,這會導致重複計算;但如果每次使用只需要 WITH
查詢總輸出中的幾行,NOT MATERIALIZED
可以透過允許查詢進行聯合最佳化來提供淨節省。如果 NOT MATERIALIZED
附加到一個遞迴的 WITH
查詢或不是無副作用的 (SELECT
包含無副作用函式) 查詢,則會忽略它。
預設情況下,無副作用的 WITH
查詢如果在主查詢的 FROM
子句中恰好使用一次,就會被摺疊到主查詢中。這允許在語義上不可見的情況下對兩個查詢級別進行聯合最佳化。然而,這種摺疊可以透過將 WITH
查詢標記為 MATERIALIZED
來阻止。例如,這可能很有用,因為 WITH
查詢被用作最佳化柵欄,以防止規劃器選擇一個糟糕的計劃。v12 之前的 PostgreSQL 版本從未進行過這種摺疊,因此為舊版本編寫的查詢可能依賴於 WITH
作為最佳化柵欄。
有關更多資訊,請參見 第 7.8 節。
FROM
子句FROM
子句為 SELECT
指定一個或多個源表。如果指定了多個源,則結果是所有源的笛卡爾積 (交叉連線)。但通常會新增限定條件 (透過 WHERE
) 來將返回的行限制為笛卡爾積的一個小子集。
FROM
子句可以包含以下元素:
table_name
現有表或檢視的名稱 (可選模式限定)。如果在表名前指定了 ONLY
,則只掃描該表。如果未指定 ONLY
,則掃描該表及其所有後代表 (如果有)。可選地,可以在表名後指定 *
來明確指示包含後代表。
alias
FROM
項的替代名稱,包含別名。別名用於簡潔或消除自連線 (其中同一個表被掃描多次) 的歧義。當提供別名時,它會完全隱藏表或函式的實際名稱;例如,給定 FROM foo AS f
,SELECT
的其餘部分必須將此 FROM
項稱為 f
而不是 foo
。如果寫了別名,也可以寫一個列別名列表來為表的一個或多個列提供替代名稱。
TABLESAMPLE sampling_method
( argument
[, ...] ) [ REPEATABLE ( seed
) ]
table_name
後面的 TABLESAMPLE
子句表示應使用指定的 sampling_method
來檢索該表中的一行子集。此取樣在應用任何其他過濾器 (如 WHERE
子句) 之前進行。標準的 PostgreSQL 發行版包含兩種取樣方法:BERNOULLI
和 SYSTEM
,並且可以透過擴充套件在資料庫中安裝其他取樣方法。
BERNOULLI
和 SYSTEM
取樣方法都接受一個 argument
,該引數是取樣表的比例,表示為 0 到 100 之間的百分比。此引數可以是任何 real
值表示式。(其他取樣方法可能接受更多或不同的引數。) 這兩種方法都返回一個隨機選擇的表樣本,該樣本將包含大約指定百分比的錶行。 BERNOULLI
方法掃描整個表,並以指定機率獨立選擇或忽略單個行。 SYSTEM
方法進行塊級取樣,每個塊都有指定的選擇機率;每個選定塊中的所有行都將被返回。當指定小的取樣百分比時,SYSTEM
方法比 BERNOULLI
方法快得多,但由於聚類效應,它可能會返回一個不太隨機的表樣本。
可選的 REPEATABLE
子句指定一個 seed
數字或表示式,用於在取樣方法中生成隨機數。種子值可以是任何非空浮點值。兩個具有相同種子和 argument
值的查詢將在表未更改的情況下選擇相同的表樣本。但不同的種子值通常會產生不同的樣本。如果未給出 REPEATABLE
,則每次查詢都會基於系統生成的種子選擇一個新的隨機樣本。請注意,某些附加取樣方法不接受 REPEATABLE
,並且在每次使用時都會生成新樣本。
select
FROM
子句中可以出現子 SELECT
。這就像在本次 SELECT
命令的持續時間內,其輸出被建立為一個臨時表。請注意,子 SELECT
必須用括號括起來,並且可以以與表相同的方式提供別名。這裡也可以使用 VALUES
命令。
with_query_name
WITH
查詢透過編寫其名稱來引用,就像該查詢的名稱是一個表名一樣。(實際上,WITH
查詢在主查詢的範圍內會隱藏同名的真實表。如有必要,您可以透過模式限定表名來引用同名的真實表。) 可以以與表相同的方式提供別名。
function_name
函式呼叫可以出現在 FROM
子句中。(這對於返回結果集的函式特別有用,但任何函式都可以使用。) 這就像在本次 SELECT
命令的持續時間內,函式輸出被建立為一個臨時表。如果函式的返回型別是複合型別 (包括具有多個 OUT
引數的函式),則每個屬性都成為隱式表中的一個獨立列。
當可選的 WITH ORDINALITY
子句新增到函式呼叫時,一個型別為 bigint
的附加列將被附加到函式的列結果中。此列對函式結果集的行進行編號,從 1 開始。預設情況下,此列命名為 ordinality
。
可以以與表相同的方式提供別名。如果寫了別名,也可以寫一個列別名列表,為函式複合返回型別的一個或多個屬性提供替代名稱,包括存在時的序數序數字段。
多個函式呼叫可以透過用 ROWS FROM( ... )
包圍來組合成一個 FROM
子句項。此類項的輸出是將每個函式的第一個行連線起來,然後是每個函式的第二個行,依此類推。如果某些函式產生的行數少於其他函式,則用 null 值替換缺失的資料,因此返回的總行數始終與生成行數最多的函式相同。
如果函式被定義為返回 record
資料型別,那麼必須存在一個別名或關鍵字 AS
,後面跟著一個形式為 (
的列定義列表。列定義列表必須匹配函式返回的實際列數和型別。column_name
data_type
[, ... ])
使用 ROWS FROM( ... )
語法時,如果其中一個函式需要列定義列表,則最好將列定義列表放在 ROWS FROM( ... )
中的函式呼叫之後。只有當只有一個函式且沒有 WITH ORDINALITY
子句時,才能在 ROWS FROM( ... )
構造之後放置列定義列表。
要將 ORDINALITY
與列定義列表一起使用,您必須使用 ROWS FROM( ... )
語法,並將列定義列表放在 ROWS FROM( ... )
內部。
join_type
以下之一:
[ INNER ] JOIN
LEFT [ OUTER ] JOIN
RIGHT [ OUTER ] JOIN
FULL [ OUTER ] JOIN
對於 INNER
和 OUTER
連線型別,必須指定一個連線條件,即 ON
, join_condition
USING (
, 或 join_column
[, ...])NATURAL
中的一個。有關含義,請參見下文。
JOIN
子句組合了兩個 FROM
項,為了方便起見,我們將它們稱為“表”,儘管實際上它們可以是任何型別的 FROM
項。如有必要,請使用括號確定巢狀順序。在沒有括號的情況下,JOIN
s 從左到右巢狀。無論如何,JOIN
的結合性比分隔 FROM
列表項的逗號更強。所有 JOIN
選項都只是一個方便的符號,因為它們不會做任何無法透過普通 FROM
和 WHERE
完成的事情。
LEFT OUTER JOIN
返回合格笛卡爾積中的所有行 (即,透過其連線條件的組合行),再加上左表中沒有右錶行滿足連線條件的每個行的副本。此左錶行透過插入右表列的 null 值來擴充套件到連線表的全部寬度。請注意,在決定哪些行匹配時,只考慮 JOIN
子句本身的條件。外部條件在之後應用。
相反,RIGHT OUTER JOIN
返回所有連線的行,再加上每個未匹配的右錶行的行 (在左側用 null 值擴充套件)。這只是一個方便的符號,因為您可以透過交換左右表將其轉換為 LEFT OUTER JOIN
。
FULL OUTER JOIN
返回所有連線的行,再加上每個未匹配的左錶行的行 (在右側用 null 值擴充套件),再加上每個未匹配的右錶行的行 (在左側用 null 值擴充套件)。
ON join_condition
join_condition
是一個求值為 boolean
型別結果的表示式 (類似於 WHERE
子句),它指定連線中的哪些行被視為匹配。
USING ( join_column
[, ...] ) [ AS join_using_alias
]
形式為 USING ( a, b, ... )
的子句是 ON left_table.a = right_table.a AND left_table.b = right_table.b ...
的簡寫。此外,USING
暗示只包含一對等效列中的一個,而不是兩個。
如果指定了 join_using_alias
名稱,它為連線列提供了一個表別名。只有 USING
子句中列出的連線列才能透過此名稱訪問。與常規 alias
不同,這不會隱藏查詢其餘部分的連線表的名稱。與常規 alias
也不同,您不能編寫列別名列表 — 連線列的輸出名稱與它們在 USING
列表中出現時相同。
NATURAL
NATURAL
是 USING
列表的簡寫,該列表提及兩個表中具有匹配名稱的所有列。如果沒有公共列名,NATURAL
等同於 ON TRUE
。
CROSS JOIN
CROSS JOIN
等同於 INNER JOIN ON (TRUE)
,即沒有行因條件而被移除。它們產生一個簡單的笛卡爾積,與在 FROM
的頂層列出兩個表時獲得的結果相同,但受到連線條件 (如果有) 的限制。
LATERAL
LATERAL
關鍵字可以放在子 SELECT
FROM
項之前。這允許子 SELECT
引用 FROM
列表中它之前出現的 FROM
項的列。(沒有 LATERAL
時,每個子 SELECT
都獨立評估,因此無法交叉引用任何其他 FROM
項。)
LATERAL
也可以放在函式呼叫 FROM
項之前,但在此情況下它是一個噪聲詞,因為函式表示式在任何情況下都可以引用前面的 FROM
項。
LATERAL
項可以出現在 FROM
列表的頂層,或者在 JOIN
樹中。在後一種情況下,它也可以引用位於其右側的 JOIN
的左側的任何項。
當 FROM
項包含 LATERAL
交叉引用時,評估過程如下:對於提供交叉引用列的 FROM
項的每一行,或提供列的多個 FROM
項的行集,LATERAL
項會使用該行或行集的值的列來計算。結果行將像往常一樣與它們被計算出的行進行連線。這會為列源表中的每一行或行集重複進行。
列源表必須是 INNER
或 LEFT
連線到 LATERAL
項,否則將不存在一個明確定義的行集來計算 LATERAL
項的每一組行。因此,雖然
這樣的構造在語法上是有效的,但實際上不允許 X
RIGHT JOIN LATERAL Y
Y
引用 X
。
WHERE
子句可選的 WHERE
子句具有通用形式:
WHERE condition
其中 condition
是任何求值為 boolean
型別的結果的表示式。任何不滿足此條件的行都將從輸出中消除。當將實際行值替換為任何變數引用時,如果行返回 true,則該行滿足條件。
GROUP BY
子句可選的 GROUP BY
子句具有通用形式:
GROUP BY [ ALL | DISTINCT ] grouping_element
[, ...]
GROUP BY
將共享分組表示式相同值的選定行合併為一行。在 grouping_element
中使用的 expression
可以是輸入列名,或者輸出列 (SELECT
列表項) 的名稱或序數號,或者由輸入列值形成的任意表達式。在有歧義的情況下,GROUP BY
名稱將被解釋為輸入列名稱而不是輸出列名稱。
如果 GROUPING SETS
, ROLLUP
或 CUBE
中的任何一個作為分組元素存在,那麼整個 GROUP BY
子句就定義了若干獨立的 grouping sets
。其效果等同於在具有單個分組集的子查詢之間構建 UNION ALL
。可選的 DISTINCT
子句在處理前刪除重複集;它 不會 將 UNION ALL
轉換為 UNION DISTINCT
。有關分組集的處理方式,請參見 第 7.2.4 節。
聚合函式 (如果有) 是在構成每個組的所有行上計算的,為每個組產生一個獨立的值。(如果存在聚合函式但沒有 GROUP BY
子句,則查詢被視為具有一個包含所有選定行的組。) 傳遞給每個聚合函式的行集可以透過將 FILTER
子句附加到聚合函式呼叫來進一步過濾;有關更多資訊,請參見 第 4.2.7 節。當存在 FILTER
子句時,只有匹配該子句的行才會被包含在該聚合函式的輸入中。
當存在 GROUP BY
或任何聚合函式時,SELECT
列表表示式引用未分組的列 (除非在聚合函式內或未分組列在函式上依賴於分組列) 是無效的,因為否則未分組列將有多個可能返回值。如果分組列 (或其子集) 是包含未分組列的表的主鍵,則存在函式依賴關係。
請注意,所有聚合函式都在計算 HAVING
子句或 SELECT
列表中的任何“標量”表示式之前進行計算。這意味著,例如,CASE
表示式不能用於跳過聚合函式的計算;請參閱 第 4.2.14 節。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能與 GROUP BY
一起指定。
HAVING
子句可選的 HAVING
子句具有通用形式:
HAVING condition
其中 condition
與 WHERE
子句指定的相同。
HAVING
刪除不滿足條件的組行。 HAVING
與 WHERE
不同:WHERE
在應用 GROUP BY
之前過濾單個行,而 HAVING
過濾由 GROUP BY
建立的組行。 condition
中引用的每個列都必須明確引用一個分組列,除非該引用出現在聚合函式內,或者未分組列在函式上依賴於分組列。
HAVING
的存在會將一個查詢變成一個分組查詢,即使沒有 GROUP BY
子句。這與查詢包含聚合函式但沒有 GROUP BY
子時發生的情況相同。所有選定的行被視為形成一個單一的組,並且 SELECT
列表和 HAVING
子句只能從聚合函式中引用表列。這樣的查詢將在 HAVING
條件為真時發出單行,如果條件為假則發出零行。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能與 HAVING
一起指定。
WINDOW
子句可選的 WINDOW
子句具有通用形式:
WINDOWwindow_name
AS (window_definition
) [, ...]
其中 window_name
是一個可以在 OVER
子句或後續視窗定義中引用的名稱,而 window_definition
是:
[existing_window_name
] [ PARTITION BYexpression
[, ...] ] [ ORDER BYexpression
[ ASC | DESC | USINGoperator
] [ NULLS { FIRST | LAST } ] [, ...] ] [frame_clause
]
如果指定了 existing_window_name
,它必須引用 WINDOW
列表中的早期條目;新視窗從該條目複製其分割槽子句,以及其排序子句 (如果存在)。在這種情況下,新視窗不能指定自己的 PARTITION BY
子句,並且只有在複製的視窗沒有排序子句時才能指定 ORDER BY
。新視窗始終使用自己的框架子句;複製的視窗不得指定框架子句。
PARTITION BY
列表的元素在很大程度上被解釋為類似於 GROUP BY
子句的元素,只是它們總是簡單的表示式,並且永遠不會是輸出列的名稱或編號。另一個區別是,這些表示式可以包含聚合函式呼叫,而這些呼叫在常規 GROUP BY
子句中是不允許的。它們在這裡是允許的,因為視窗化發生在分組和聚合之後。
類似地,ORDER BY
列表的元素在很大程度上被解釋為類似於語句級 ORDER BY
子句的元素,只是表示式始終被視為簡單表示式,而從不是輸出列的名稱或編號。
可選的 frame_clause
定義了查詢的每一行 (稱為 當前行) 的相關行集。 frame_clause
可以是以下之一:
{ RANGE | ROWS | GROUPS }frame_start
[frame_exclusion
] { RANGE | ROWS | GROUPS } BETWEENframe_start
ANDframe_end
[frame_exclusion
]
其中 frame_start
和 frame_end
可以是以下之一:
UNBOUNDED PRECEDINGoffset
PRECEDING CURRENT ROWoffset
FOLLOWING UNBOUNDED FOLLOWING
而 frame_exclusion
可以是以下之一:
EXCLUDE CURRENT ROW EXCLUDE GROUP EXCLUDE TIES EXCLUDE NO OTHERS
如果省略 frame_end
,則預設為 CURRENT ROW
。限制是 frame_start
不能是 UNBOUNDED FOLLOWING
,frame_end
不能是 UNBOUNDED PRECEDING
,並且 frame_end
的選擇在上述 frame_start
和 frame_end
選項列表中不能出現在 frame_start
選擇之前 — 例如,不允許 RANGE BETWEEN CURRENT ROW AND
。offset
PRECEDING
預設的框架選項是 RANGE UNBOUNDED PRECEDING
,它等同於 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
;它將框架設定為從分割槽開始到當前行最後一個 對等行 (一個行,其視窗的 ORDER BY
子句認為它與當前行等效;如果不存在 ORDER BY
,則所有行都是對等行) 的所有行。通常,UNBOUNDED PRECEDING
意味著框架從分割槽的第一個行開始,同樣 UNBOUNDED FOLLOWING
意味著框架以分割槽的最後一個行結束,無論 RANGE
, ROWS
或 GROUPS
模式如何。在 ROWS
模式下,CURRENT ROW
意味著框架以當前行開始或結束;但在 RANGE
或 GROUPS
模式下,它意味著框架以當前行的第一個或最後一個對等行開始或結束。 offset
PRECEDING
和 offset
FOLLOWING
選項的含義取決於框架模式。在 ROWS
模式下,offset
是一個整數,表示框架相對於當前行開始或結束 offset
行。在 GROUPS
模式下,offset
是一個整數,表示框架相對於當前行的對等組開始或結束 offset
個對等組,其中 對等組 是根據視窗的 ORDER BY
子句等效的行組。在 RANGE
模式下,使用 offset
選項要求視窗定義中只有一列 ORDER BY
。然後,框架包含那些排序列值不大於 (對於 PRECEDING
) 或不小於 (對於 FOLLOWING
) 當前行排序列值的行。在這些情況下,offset
表示式的資料型別取決於排序列的資料型別。對於數字排序列,它通常與排序列是同一型別,但對於日期時間排序列,它是 interval
。在所有這些情況下,offset
的值必須是非空且非負的。此外,儘管 offset
不一定是簡單的常量,但它不能包含變數、聚合函式或視窗函式。
frame_exclusion
選項允許將當前行周圍的行從框架中排除,即使它們根據框架開始和框架結束選項被包含在內。EXCLUDE CURRENT ROW
將當前行從框架中排除。EXCLUDE GROUP
將當前行及其排序對等行從框架中排除。EXCLUDE TIES
從框架中排除當前行的任何對等行,但排除當前行本身。EXCLUDE NO OTHERS
僅明確指定不排除當前行或其對等行的預設行為。
請注意,如果在 ORDER BY
排序不唯一地對行進行排序時,ROWS
模式可能會產生不可預測的結果。RANGE
和 GROUPS
模式旨在確保根據 ORDER BY
排序對等處理的行被視為相同:給定對等組的所有行都將在框架內或被排除在框架之外。
WINDOW
子句的目的是指定查詢的 SELECT
列表 或 ORDER BY
子句中出現的 視窗函式 的行為。這些函式可以透過名稱在它們的 OVER
子句中引用 WINDOW
子句條目。 WINDOW
子句條目不必在任何地方被引用;如果它在查詢中未被使用,它將被簡單地忽略。可以完全不使用 WINDOW
子句就使用視窗函式,因為視窗函式呼叫可以直接在其 OVER
子句中指定其視窗定義。但是,當相同的視窗定義需要用於多個視窗函式時,WINDOW
子句可以節省輸入。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能與 WINDOW
一起指定。
SELECT
列表SELECT
列表 (在關鍵字 SELECT
和 FROM
之間) 指定構成 SELECT
語句輸出行的表示式。這些表示式可以 (而且通常會) 引用在 FROM
子句中計算出的列。
正如在表中一樣,SELECT
的每個輸出列都有一個名稱。在簡單的 SELECT
中,這個名稱只是用於標記列以供顯示,但當 SELECT
是一個更大查詢的子查詢時,名稱對於大查詢來說是該子查詢產生的虛擬表的列名。要指定輸出列使用的名稱,請在列的表示式後寫入 AS
output_name
。(您可以省略 AS
,但前提是所需的輸出名稱不匹配任何 PostgreSQL 關鍵字 (請參閱 附錄 C)。為防止將來可能新增關鍵字,建議您始終編寫 AS
或對輸出名稱加雙引號。) 如果您未指定列名,PostgreSQL 會自動選擇一個名稱。如果列的表示式是簡單的列引用,則選定的名稱與該列的名稱相同。在更復雜的情況下,可以使用函式或型別名稱,或者系統可能會回退到生成名稱,例如 ?column?
。
輸出列的名稱可以在 ORDER BY
和 GROUP BY
子句中引用該列的值,但在 WHERE
或 HAVING
子句中不能使用;在那裡您必須寫出表示式。
代替表示式,*
可以在輸出列表中作為所有選定行列的簡寫。此外,您也可以寫
作為僅來自該表的列的簡寫。在這些情況下,無法使用 table_name
.*AS
指定新名稱;輸出列名稱將與表列的名稱相同。
根據 SQL 標準,輸出列表中的表示式應在應用 DISTINCT
, ORDER BY
, 或 LIMIT
之前進行計算。這在使用 DISTINCT
時顯然是必要的,因為否則就不清楚哪些值正在被區分。然而,在許多情況下,如果輸出表達式在 ORDER BY
和 LIMIT
之後進行計算會很方便;特別是當輸出列表包含任何易變或昂貴的函式時。有了這種行為,函式求值的順序就更直觀了,也不會有與永遠不會出現在輸出中的行相對應的求值。 PostgreSQL 將有效地在排序和限制之後計算輸出表達式,只要這些表示式未在 DISTINCT
, ORDER BY
或 GROUP BY
中引用。(作為反例,SELECT f(x) FROM tab ORDER BY 1
顯然必須在排序之前計算 f(x)
。) 包含集合返回函式的輸出表達式有效地在排序後和限制前計算,因此 LIMIT
將作用於截斷集合返回函式的輸出。
PostgreSQL 9.6 之前的版本未對輸出表達式與排序和限制的求值時序提供任何保證;這取決於所選查詢計劃的形式。
DISTINCT
子句如果指定了 SELECT DISTINCT
,則從結果集中刪除所有重複的行 (從每個重複組中保留一行)。 SELECT ALL
指定相反的操作:保留所有行;這是預設行為。
SELECT DISTINCT ON (
只保留給定表示式求值相等的行集中第一個行。 expression
[, ...] )DISTINCT ON
表示式的解釋規則與 ORDER BY
相同 (參見上文)。請注意,除非使用 ORDER BY
來確保所需的行首先出現,否則每個集合的“第一行”是不可預測的。例如:
SELECT DISTINCT ON (location) location, time, report FROM weather_reports ORDER BY location, time DESC;
檢索每個地點的最新天氣報告。但是,如果我們沒有使用 ORDER BY
來強制每個地點的按時間降序排列,那麼我們會為每個地點獲得一個不可預測時間的報告。
DISTINCT ON
表示式必須與最左邊的 ORDER BY
表示式匹配。 ORDER BY
子句通常包含額外的表示式,這些表示式決定了每個 DISTINCT ON
組內行的期望優先順序。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能與 DISTINCT
一起指定。
UNION
子句UNION
子句具有此通用形式:
select_statement
UNION [ ALL | DISTINCT ]select_statement
select_statement
是任何沒有 ORDER BY
, LIMIT
, FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
, 或 FOR KEY SHARE
子句的 SELECT
語句。(如果子表示式被括在括號中,則可以為其附加 ORDER BY
和 LIMIT
。沒有括號時,這些子句將被視為應用於 UNION
的結果,而不是其右側輸入表示式。)
UNION
運算子計算參與的 SELECT
語句返回的行的集合並集。一個行存在於兩個結果集的集合並集中,如果它存在於至少一個結果集中。代表 UNION
直接運算元的兩個 SELECT
語句必須產生相同數量的列,並且對應的列必須是相容的資料型別。
除非指定了 ALL
選項,否則 UNION
的結果不包含任何重複行。 ALL
阻止消除重複項。(因此,UNION ALL
通常比 UNION
快得多;如果可以,請使用 ALL
。) 可以編寫 DISTINCT
來明確指定刪除重複行的預設行為。
同一個 SELECT
語句中的多個 UNION
運算子按從左到右的順序進行計算,除非另有指示 (例如透過括號)。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能用於 UNION
結果或 UNION
的任何輸入。
INTERSECT
子句INTERSECT
子句具有此通用形式:
select_statement
INTERSECT [ ALL | DISTINCT ]select_statement
select_statement
是任何沒有 ORDER BY
, LIMIT
, FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
, 或 FOR KEY SHARE
子句的 SELECT
語句。
INTERSECT
運算子計算參與的 SELECT
語句返回的行的集合交集。一個行存在於兩個結果集的交集中,如果它存在於兩個結果集中。
除非指定了 ALL
選項,否則 INTERSECT
的結果不包含任何重複行。使用 ALL
時,在左表中具有 m
次重複並在右表中具有 n
次重複的行將在結果集中出現 min(m
,n
) 次。可以編寫 DISTINCT
來明確指定刪除重複行的預設行為。
同一個 SELECT
語句中的多個 INTERSECT
運算子按從左到右的順序進行計算,除非括號另有規定。 INTERSECT
的結合性比 UNION
更強。也就是說,A UNION B INTERSECT C
將被讀作 A UNION (B INTERSECT C)
。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能用於 INTERSECT
結果或 INTERSECT
的任何輸入。
EXCEPT
子句EXCEPT
子句具有此通用形式:
select_statement
EXCEPT [ ALL | DISTINCT ]select_statement
select_statement
是任何沒有 ORDER BY
, LIMIT
, FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
, 或 FOR KEY SHARE
子句的 SELECT
語句。
EXCEPT
運算子計算左 SELECT
語句的結果中存在但不在右側結果中存在的行集。
除非指定了 ALL
選項,否則 EXCEPT
的結果不包含任何重複行。使用 ALL
時,在左表中具有 m
次重複並在右表中具有 n
次重複的行將在結果集中出現 max(m
-n
,0) 次。可以編寫 DISTINCT
來明確指定刪除重複行的預設行為。
同一個 SELECT
語句中的多個 EXCEPT
運算子按從左到右的順序進行計算,除非括號另有規定。 EXCEPT
的結合性與 UNION
相同。
目前,FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
和 FOR KEY SHARE
不能用於 EXCEPT
結果或 EXCEPT
的任何輸入。
ORDER BY
子句可選的 ORDER BY
子句具有此通用形式:
ORDER BYexpression
[ ASC | DESC | USINGoperator
] [ NULLS { FIRST | LAST } ] [, ...]
ORDER BY
子句導致結果行根據指定的表示式進行排序。如果兩行根據最左邊的表示式相等,則根據下一個表示式進行比較,依此類推。如果它們根據所有指定的表示式都相等,則它們將以實現定義的方式返回。
每個 expression
可以是輸出列 ( SELECT
列表項) 的名稱或序數號,或者它可以是輸入列值構成的任意表達式。
序數號指的是輸出列的序數 (從左到右) 位置。此功能使得可以基於沒有唯一名稱的列來定義排序。這從來都不是絕對必需的,因為使用 AS
子句總是可以將名稱分配給輸出列。
ORDER BY
子句中也可以使用任意表達式,包括未出現在 SELECT
輸出列表中的列。因此,以下語句是有效的:
SELECT name FROM distributors ORDER BY code;
此功能的一個限制是,應用於 UNION
, INTERSECT
, 或 EXCEPT
子句結果的 ORDER BY
子句只能指定輸出列名稱或編號,而不能指定表示式。
如果 ORDER BY
表示式是一個簡單的名稱,它同時匹配輸出列名稱和輸入列名稱,ORDER BY
會將其解釋為輸出列名稱。這與 GROUP BY
在同一情況下會做的選擇相反。這種不一致是為了與 SQL 標準相容。
可選地,您可以在任何 ORDER BY
子句的表示式後新增關鍵字 ASC
(升序) 或 DESC
(降序)。如果未指定,則預設假定為 ASC
。或者,可以在 USING
子句中指定一個特定的排序運算子名稱。排序運算子必須是某個 B-tree 運算子族的“小於”或“大於”成員。 ASC
通常等同於 USING <
,而 DESC
通常等同於 USING >
。(但使用者定義資料型別的建立者可以確切地定義預設排序順序,並且它可能對應於其他名稱的運算子。)
如果指定了 NULLS LAST
,則 null 值排序在所有非 null 值之後;如果指定了 NULLS FIRST
,則 null 值排序在所有非 null 值之前。如果未指定,則當指定或隱含 ASC
時,預設行為是 NULLS LAST
,當指定 DESC
時,預設行為是 NULLS FIRST
(因此,預設行為就像 null 值比非 null 值大)。使用 USING
時,預設的 null 排序取決於運算子是“小於”還是“大於”運算子。
請注意,排序選項僅適用於它們後面的表示式;例如 ORDER BY x, y DESC
並不意味著 ORDER BY x DESC, y DESC
。
字串資料根據適用於被排序列的排序規則進行排序。如有需要,可以透過在 expression
中包含 COLLATE
子句來覆蓋,例如 ORDER BY mycolumn COLLATE "en_US"
。有關更多資訊,請參閱 第 4.2.10 節 和 第 23.2 節。
LIMIT
子句LIMIT
子句由兩個獨立子句組成:
LIMIT {count
| ALL } OFFSETstart
引數 count
指定要返回的最大行數,而 start
指定在開始返回行之前要跳過的行數。當兩者都指定時,在開始計算要返回的 count
行之前,將跳過 start
行。
如果 count
表示式求值為 NULL,則將其視為 LIMIT ALL
,即無限制。如果 start
求值為 NULL,則其處理方式與 OFFSET 0
相同。
SQL:2008 引入了一種不同的語法來實現相同的結果,PostgreSQL 也支援它。它是:
OFFSETstart
{ ROW | ROWS } FETCH { FIRST | NEXT } [count
] { ROW | ROWS } { ONLY | WITH TIES }
在此語法中,標準要求 start
或 count
值必須是字面量常量、引數或變數名;作為 PostgreSQL 擴充套件,允許使用其他表示式,但通常需要用括號將其括起來以避免歧義。如果在 FETCH
子句中省略了 count
,則預設為 1。 WITH TIES
選項用於返回根據 ORDER BY
子句在結果集中並列的任何其他行;在這種情況下,ORDER BY
是必需的,並且不允許 SKIP LOCKED
。 ROW
和 ROWS
以及 FIRST
和 NEXT
是噪聲詞,不會影響這些子句的效果。根據標準,如果 OFFSET
和 FETCH
子句都存在,則 OFFSET
子句必須出現在 FETCH
子句之前;但 PostgreSQL 比較寬鬆,允許任何順序。
使用 LIMIT
時,最好使用 ORDER BY
子句來約束結果行以獲得唯一順序。否則,您將獲得查詢行的一個不可預測的子集——您可能正在請求第 10 到第 20 行,但按什麼順序?除非您指定 ORDER BY
,否則您不知道是什麼順序。
查詢規劃器在生成查詢計劃時會考慮 LIMIT
,因此您很可能會根據 LIMIT
和 OFFSET
的使用情況獲得不同的計劃 (產生不同的行順序)。因此,使用不同的 LIMIT
/OFFSET
值選擇查詢結果的不同子集 將導致不一致的結果,除非您使用 ORDER BY
來強制執行可預測的結果順序。這不是一個錯誤;這是 SQL 不保證按任何特定順序返回查詢結果 (除非使用 ORDER BY
來約束順序) 的固有後果。
如果沒有 ORDER BY
來強制選擇確定性子集,重複執行相同的 LIMIT
查詢甚至可能返回錶行的不同子集。同樣,這不是一個錯誤;在這種情況下,結果的確定性只是不被保證。
FOR UPDATE
, FOR NO KEY UPDATE
, FOR SHARE
和 FOR KEY SHARE
是 鎖定子句;它們影響 SELECT
在從表中獲取行時如何鎖定行。
鎖定子句具有通用形式:
FORlock_strength
[ OFfrom_reference
[, ...] ] [ NOWAIT | SKIP LOCKED ]
其中 lock_strength
可以是以下之一:
UPDATE NO KEY UPDATE SHARE KEY SHARE
from_reference
必須是 FROM
子句中引用的表 alias
或非隱藏 table_name
。有關每種行級鎖模式的更多資訊,請參閱 第 13.3.2 節。
為防止操作等待其他事務提交,請使用 NOWAIT
或 SKIP LOCKED
選項。使用 NOWAIT
時,如果選定的行無法立即鎖定,則該語句會報告錯誤,而不是等待。使用 SKIP LOCKED
時,任何無法立即鎖定的選定行都會被跳過。跳過鎖定的行會提供不一致的資料檢視,因此不適用於通用工作,但可用於避免多個使用者訪問類似佇列的表時發生鎖爭用。請注意,NOWAIT
和 SKIP LOCKED
僅適用於行級鎖 — 所需的 ROW SHARE
表級鎖仍以常規方式獲取(參見 第 13 章)。如果需要獲取表級鎖而不等待,可以首先使用帶 NOWAIT
選項的 LOCK
。
如果在鎖定子句中命名了特定的表,那麼只會鎖定來自這些表的行;在 SELECT
中使用的任何其他表都將像平常一樣被讀取。沒有表列表的鎖定子句會影響語句中使用的所有表。如果鎖定子句應用於檢視或子查詢,則它會影響檢視或子查詢中使用的所有表。但是,這些子句不適用於主查詢引用的 WITH
查詢。如果要使行鎖定發生在 WITH
查詢內,請在 WITH
查詢中指定一個鎖定子句。
如果需要為不同的表指定不同的鎖定行為,可以編寫多個鎖定子句。如果同一表被一個或多個鎖定子句提及(或隱式影響),則它被處理為僅由最強的子句指定。同樣,如果影響某個表的子句中指定了 NOWAIT
,則該表將按 NOWAIT
處理。否則,如果影響該表的子句中指定了 SKIP LOCKED
,則該表將按 SKIP LOCKED
處理。
鎖定子句不能在無法將返回的行明確標識為單個錶行的情況下使用;例如,它們不能與聚合一起使用。
當鎖定子句出現在 SELECT
查詢的頂層時,被鎖定的行正是由查詢返回的行;對於聯接查詢,被鎖定的行是那些為返回的聯接行做出貢獻的行。此外,作為查詢快照滿足查詢條件的行將被鎖定,即使它們在快照之後被更新並且不再滿足查詢條件,它們也不會被返回。如果使用了 LIMIT
,則鎖定會一直進行,直到返回足夠多的行來滿足限制(但請注意,由 OFFSET
跳過的行將被鎖定)。同樣,如果在遊標的查詢中使用鎖定子句,則只會鎖定實際被遊標獲取或越過的行。
當鎖定子句出現在子 SELECT
中時,被鎖定的行是子查詢返回給外部查詢的行。這可能涉及比單獨檢查子查詢所暗示的更少的行,因為外部查詢的條件可能被用於最佳化子查詢的執行。例如,
SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;
將只鎖定 col1 = 5
的行,即使該條件在文字上不在子查詢內。
早期版本未能保留由後續儲存點升級的鎖。例如,此程式碼
BEGIN; SELECT * FROM mytable WHERE key = 1 FOR UPDATE; SAVEPOINT s; UPDATE mytable SET ... WHERE key = 1; ROLLBACK TO s;
在 ROLLBACK TO
之後將無法保留 FOR UPDATE
鎖。此問題已在 9.3 版本中修復。
在 READ COMMITTED
事務隔離級別下執行的 SELECT
命令,如果使用了 ORDER BY
和鎖定子句,可能會返回亂序的行。這是因為 ORDER BY
先被應用。該命令對結果進行排序,但隨後可能會在嘗試獲取一個或多個行的鎖時阻塞。一旦 SELECT
解除阻塞,一些排序列的值可能已被修改,導致這些行看起來亂序(儘管它們在原始列值方面是排序的)。可以透過將 FOR UPDATE/SHARE
子句放在子查詢中來解決此問題,例如
SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;
請注意,這將導致鎖定 mytable
的所有行,而頂層的 FOR UPDATE
只會鎖定實際返回的行。這可能會導致顯著的效能差異,特別是當 ORDER BY
與 LIMIT
或其他限制結合使用時。因此,只有在預期排序列會發生併發更新並且需要嚴格排序的結果時,才推薦使用此技術。
在 REPEATABLE READ
或 SERIALIZABLE
事務隔離級別下,這會導致序列化失敗(SQLSTATE
為 '40001'
),因此在這些隔離級別下不會出現行亂序的情況。
TABLE
命令命令
TABLE name
等同於
SELECT * FROM name
它可以作為頂級命令使用,也可以作為複雜的查詢中的節省空間的語法變體。只有 WITH
、UNION
、INTERSECT
、EXCEPT
、ORDER BY
、LIMIT
、OFFSET
、FETCH
和 FOR
鎖定子句可以與 TABLE
一起使用;不能使用 WHERE
子句和任何形式的聚合。
聯接表 films
和表 distributors
SELECT f.title, f.did, d.name, f.date_prod, f.kind FROM distributors d JOIN films f USING (did); title | did | name | date_prod | kind -------------------+-----+--------------+------------+---------- The Third Man | 101 | British Lion | 1949-12-23 | Drama The African Queen | 101 | British Lion | 1951-08-11 | Romantic ...
對所有電影的 len
列求和,並按 kind
分組
SELECT kind, sum(len) AS total FROM films GROUP BY kind; kind | total ----------+------- Action | 07:34 Comedy | 02:58 Drama | 14:28 Musical | 06:42 Romantic | 04:38
對所有電影的 len
列求和,按 kind
分組,並顯示總數小於 5 小時的組
SELECT kind, sum(len) AS total FROM films GROUP BY kind HAVING sum(len) < interval '5 hours'; kind | total ----------+------- Comedy | 02:58 Romantic | 04:38
以下兩個示例是根據第二列(name
)的內容對單個結果進行排序的相同方法
SELECT * FROM distributors ORDER BY name; SELECT * FROM distributors ORDER BY 2; did | name -----+------------------ 109 | 20th Century Fox 110 | Bavaria Atelier 101 | British Lion 107 | Columbia 102 | Jean Luc Godard 113 | Luso films 104 | Mosfilm 103 | Paramount 106 | Toho 105 | United Artists 111 | Walt Disney 112 | Warner Bros. 108 | Westward
下一個示例展示瞭如何獲取表 distributors
和 actors
的並集,並將結果限制為每個表中以字母 W 開頭的那些。只需要不重複的行,因此省略了關鍵字 ALL
。
distributors: actors: did | name id | name -----+-------------- ----+---------------- 108 | Westward 1 | Woody Allen 111 | Walt Disney 2 | Warren Beatty 112 | Warner Bros. 3 | Walter Matthau ... ... SELECT distributors.name FROM distributors WHERE distributors.name LIKE 'W%' UNION SELECT actors.name FROM actors WHERE actors.name LIKE 'W%'; name ---------------- Walt Disney Walter Matthau Warner Bros. Warren Beatty Westward Woody Allen
此示例展示瞭如何在 FROM
子句中使用函式,有或沒有列定義列表
CREATE FUNCTION distributors(int) RETURNS SETOF distributors AS $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE SQL; SELECT * FROM distributors(111); did | name -----+------------- 111 | Walt Disney CREATE FUNCTION distributors_2(int) RETURNS SETOF record AS $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE SQL; SELECT * FROM distributors_2(111) AS (f1 int, f2 text); f1 | f2 -----+------------- 111 | Walt Disney
這裡有一個帶有順序性列的函式的示例
SELECT * FROM unnest(ARRAY['a','b','c','d','e','f']) WITH ORDINALITY; unnest | ordinality --------+---------- a | 1 b | 2 c | 3 d | 4 e | 5 f | 6 (6 rows)
此示例演示瞭如何使用簡單的 WITH
子句
WITH t AS ( SELECT random() as x FROM generate_series(1, 3) ) SELECT * FROM t UNION ALL SELECT * FROM t; x -------------------- 0.534150459803641 0.520092216785997 0.0735620250925422 0.534150459803641 0.520092216785997 0.0735620250925422
請注意,WITH
查詢僅計算了一次,因此我們獲得了三組相同的隨機值。
此示例使用 WITH RECURSIVE
從一個僅顯示直接下屬的表中,查詢員工 Mary 的所有(直接或間接)下屬及其間接級別
WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS ( SELECT 1, employee_name, manager_name FROM employee WHERE manager_name = 'Mary' UNION ALL SELECT er.distance + 1, e.employee_name, e.manager_name FROM employee_recursive er, employee e WHERE er.employee_name = e.manager_name ) SELECT distance, employee_name FROM employee_recursive;
請注意遞迴查詢的典型形式:初始條件,然後是 UNION
,然後是查詢的遞迴部分。請確保遞迴部分最終不返回任何元組,否則查詢將無限迴圈。(有關更多示例,請參見 第 7.8 節。)
此示例使用 LATERAL
為 manufacturers
表的每一行應用一個返回集合的函式 get_product_names()
SELECT m.name AS mname, pname FROM manufacturers m, LATERAL get_product_names(m.id) pname;
當前沒有任何產品的製造商將不會出現在結果中,因為這是一個內連線。如果我們希望在結果中包含此類製造商的名稱,我們可以這樣做
SELECT m.name AS mname, pname FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true;
當然,SELECT
語句與 SQL 標準相容。但有一些擴充套件和一些缺失的功能。
FROM
子句PostgreSQL 允許省略 FROM
子句。它用於計算簡單表示式結果的直接用途
SELECT 2+2; ?column? ---------- 4
一些其他SQL資料庫除了引入一個虛擬的單行表來執行 SELECT
之外,無法做到這一點。
SELECT
列表SELECT
後面的輸出表達式列表可以為空,產生一個零列結果表。根據 SQL 標準,這不是有效語法。PostgreSQL 允許這樣做是為了與允許零列表保持一致。但是,當使用 DISTINCT
時,不允許使用空列表。
AS
關鍵字在 SQL 標準中,當新的列名是有效列名(即不與任何保留關鍵字相同)時,輸出列名之前的可選關鍵字 AS
可以被省略。PostgreSQL 稍微嚴格一些:如果新的列名與任何關鍵字(無論是否保留)匹配,則需要 AS
。建議的做法是使用 AS
或雙引號括起輸出列名,以防止與未來關鍵字添加發生任何可能的衝突。
在 FROM
項中,標準和 PostgreSQL 都允許在未保留關鍵字的別名前省略 AS
。但由於語法上的歧義,這對於輸出列名來說是不切實際的。
FROM
中省略子 SELECT
別名根據 SQL 標準,FROM
列表中的子 SELECT
必須有一個別名。在 PostgreSQL 中,可以省略此別名。
ONLY
和繼承SQL 標準要求在編寫 ONLY
時將表名括在括號中,例如 SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...
。PostgreSQL 認為這些括號是可選的。
PostgreSQL 允許在末尾新增 *
來顯式指定非 ONLY
行為,即包含子表。PostgreSQL 不允許這樣做。
(這些要點同樣適用於所有支援 ONLY
選項的 SQL 命令。)
TABLESAMPLE
子句限制TABLESAMPLE
子句目前僅在常規表和物化檢視上接受。根據 SQL 標準,它應該可以應用於任何 FROM
項。
FROM
中的函式呼叫PostgreSQL 允許將函式呼叫直接作為 FROM
列表的成員編寫。在 SQL 標準中,有必要將此類函式呼叫包裝在子 SELECT
中;也就是說,語法 FROM
大致等同於 func
(...) alias
FROM LATERAL (SELECT
。請注意,func
(...)) alias
LATERAL
被認為是隱式的;這是因為標準要求 FROM
中的 UNNEST()
項具有 LATERAL
語義。PostgreSQL 將 UNNEST()
與其他返回集合的函式視為相同。
GROUP BY
和 ORDER BY
可用的名稱空間在 SQL-92 標準中,ORDER BY
子句只能使用輸出列名或數字,而 GROUP BY
子句只能使用基於輸入列名的表示式。PostgreSQL 擴充套件了這兩個子句,允許使用另一種選擇(但如果存在歧義,它會使用標準的解釋)。PostgreSQL 還允許這兩個子句指定任意表達式。請注意,表示式中出現的名稱始終被視為輸入列名,而不是輸出列名。
SQL:1999 及更高版本使用稍有不同的定義,該定義與 SQL-92 不完全向後相容。但在大多數情況下,PostgreSQL 會像 SQL:1999 一樣解釋 ORDER BY
或 GROUP BY
表示式。
PostgreSQL 僅當表的 [主鍵](primary-key.html) 包含在 GROUP BY
列表中時,才識別函式依賴(允許從 GROUP BY
中省略列)。SQL 標準規定了應識別的附加條件。
LIMIT
和 OFFSET
LIMIT
和 OFFSET
子句是 PostgreSQL 特有的語法,MySQL 也使用它。SQL:2008 標準引入了 OFFSET ... FETCH {FIRST|NEXT} ...
子句來實現相同的功能,如上文 LIMIT Clause 所示。此語法也由 IBM DB2 使用。(為 Oracle 編寫的應用程式經常使用涉及自動生成的 rownum
列的變通方法,該列在 PostgreSQL 中不可用,以實現這些子句的效果。)
FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
, FOR KEY SHARE
雖然 FOR UPDATE
出現在 SQL 標準中,但標準僅允許將其作為 DECLARE CURSOR
的選項。PostgreSQL 允許將其用於任何 SELECT
查詢以及子 SELECT
s 中,但這是一種擴充套件。FOR NO KEY UPDATE
、FOR SHARE
和 FOR KEY SHARE
變體,以及 NOWAIT
和 SKIP LOCKED
選項,均未出現在標準中。
WITH
中的資料修改語句PostgreSQL 允許將 INSERT
、UPDATE
、DELETE
和 MERGE
用作 WITH
查詢。這在 SQL 標準中找不到。
DISTINCT ON ( ... )
是 SQL 標準的擴充套件。
ROWS FROM( ... )
是 SQL 標準的擴充套件。
WITH
的 MATERIALIZED
和 NOT MATERIALIZED
選項是 SQL 標準的擴充套件。
如果您在文件中看到任何不正確、與您對特定功能的使用經驗不符或需要進一步說明的內容,請使用 此表單 報告文件問題。