2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

SELECT

SELECT, TABLE, WITH — 從表或檢視檢索行

概要

[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    [ { * | expression [ [ AS ] output_name ] } [, ...] ]
    [ FROM from_item [, ...] ]
    [ WHERE condition ]
    [ GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] ]
    [ HAVING condition ]
    [ WINDOW window_name AS ( window_definition ) [, ...] ]
    [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
    [ LIMIT { count | ALL } ]
    [ OFFSET start [ ROW | ROWS ] ]
    [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES } ]
    [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF from_reference [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]

where from_item can be one of:

    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
                [ TABLESAMPLE sampling_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 { ON join_condition | USING ( join_column [, ...] ) [ AS join_using_alias ] }
    from_item NATURAL join_type from_item
    from_item CROSS JOIN from_item

and grouping_element can be one of:

    ( )
    expression
    ( expression [, ...] )
    ROLLUP ( { expression | ( expression [, ...] ) } [, ...] )
    CUBE ( { expression | ( expression [, ...] ) } [, ...] )
    GROUPING SETS ( grouping_element [, ...] )

and with_query is:

    with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( select | values | insert | update | delete | merge )
        [ SEARCH { BREADTH | DEPTH } FIRST BY column_name [, ...] SET search_seq_col_name ]
        [ CYCLE column_name [, ...] SET cycle_mark_col_name [ TO cycle_mark_value DEFAULT cycle_mark_default ] USING cycle_path_col_name ]

TABLE [ ONLY ] table_name [ * ]

描述

SELECT 從零個或多個表中檢索行。 SELECT 的一般處理過程如下:

  1. 所有 WITH 列表中的查詢都將被計算。這些實際上充當臨時表,可以在 FROM 列表中引用。如果一個 WITH 查詢在 FROM 中被引用多次,則只計算一次,除非使用 NOT MATERIALIZED 明確指定。 (參見下面的 WITH 子句)。

  2. 所有 FROM 列表中的元素都將被計算。 ( FROM 列表中的每個元素都是真實或虛擬的表。) 如果 FROM 列表中指定了多個元素,則它們將進行交叉連線。 (參見下面的 FROM 子句)。

  3. 如果指定了 WHERE 子句,則所有不滿足條件的行都將從輸出中刪除。 (參見下面的 WHERE 子句)。

  4. 如果指定了 GROUP BY 子句,或者存在聚合函式呼叫,則輸出將合併為具有一個或多個相同值的行組,並計算聚合函式的結果。如果存在 HAVING 子句,則它將刪除不滿足給定條件的組。 (參見下面的 GROUP BY 子句HAVING 子句)。雖然查詢輸出列名在下一步中名義上被計算,但它們也可以在 GROUP BY 子句中被引用 (按名稱或序號)。

  5. 對於每個選定的行或行組,實際的輸出行是透過 SELECT 輸出表達式計算的。 (參見下面的 SELECT 列表)。

  6. SELECT DISTINCT 從結果中刪除重複的行。 SELECT DISTINCT ON 刪除在所有指定表示式上匹配的行。 SELECT ALL (預設) 將返回所有候選行,包括重複項。 (參見下面的 DISTINCT 子句)。

  7. 使用 UNIONINTERSECTEXCEPT 運算子,可以將多個 SELECT 語句的輸出組合成一個單一的結果集。 UNION 運算子返回存在於一個或兩個結果集中的所有行。 INTERSECT 運算子返回嚴格存在於兩個結果集中的所有行。 EXCEPT 運算子返回存在於第一個結果集但不存在於第二個結果集中的行。在所有這三種情況下,除非指定了 ALL,否則會刪除重複行。噪聲詞 DISTINCT 可以被新增以明確指定刪除重複行。請注意,DISTINCT 在這裡是預設行為,儘管 ALLSELECT 本身的預設行為。 (參見下面的 UNION 子句, INTERSECT 子句, 和 EXCEPT 子句)。

  8. 如果指定了 ORDER BY 子句,則返回的行將按指定的順序排序。如果未給出 ORDER BY,則系統會以最快的速度返回行。 (參見下面的 ORDER BY 子句)。

  9. 如果指定了 LIMIT (或 FETCH FIRST) 或 OFFSET 子句,則 SELECT 語句只返回結果行的一個子集。 (參見下面的 LIMIT 子句)。

  10. 如果指定了 FOR UPDATE, FOR NO KEY UPDATE, FOR SHAREFOR KEY SHARE,則 SELECT 語句將鎖定選定的行,防止併發更新。 (參見下面的 鎖定子句)。

您必須對 SELECT 命令中使用的每個列擁有 SELECT 許可權。使用 FOR NO KEY UPDATE, FOR UPDATE, FOR SHAREFOR 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_valuecycle_mark_default 必須是常量,並且它們必須可轉換為公共資料型別,並且該資料型別必須具有不等號運算子。(SQL 標準要求它們是布林常量或字元字串,但 PostgreSQL 不要求這樣。) 預設情況下,使用 TRUEFALSE (型別為 boolean)。此外,一個名為 cycle_path_col_name 的列將被新增到 WITH 查詢的結果列列表中。該列用於內部跟蹤已訪問的行。有關示例,請參見 第 7.8.2.2 節

SEARCHCYCLE 子句都只對遞迴 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 fSELECT 的其餘部分必須將此 FROM 項稱為 f 而不是 foo。如果寫了別名,也可以寫一個列別名列表來為表的一個或多個列提供替代名稱。

TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ]

table_name 後面的 TABLESAMPLE 子句表示應使用指定的 sampling_method 來檢索該表中的一行子集。此取樣在應用任何其他過濾器 (如 WHERE 子句) 之前進行。標準的 PostgreSQL 發行版包含兩種取樣方法:BERNOULLISYSTEM,並且可以透過擴充套件在資料庫中安裝其他取樣方法。

BERNOULLISYSTEM 取樣方法都接受一個 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

對於 INNEROUTER 連線型別,必須指定一個連線條件,即 ON join_condition, USING (join_column [, ...]), 或 NATURAL 中的一個。有關含義,請參見下文。

JOIN 子句組合了兩個 FROM 項,為了方便起見,我們將它們稱為“表”,儘管實際上它們可以是任何型別的 FROM 項。如有必要,請使用括號確定巢狀順序。在沒有括號的情況下,JOINs 從左到右巢狀。無論如何,JOIN 的結合性比分隔 FROM 列表項的逗號更強。所有 JOIN 選項都只是一個方便的符號,因為它們不會做任何無法透過普通 FROMWHERE 完成的事情。

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

NATURALUSING 列表的簡寫,該列表提及兩個表中具有匹配名稱的所有列。如果沒有公共列名,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 項會使用該行或行集的值的列來計算。結果行將像往常一樣與它們被計算出的行進行連線。這會為列源表中的每一行或行集重複進行。

列源表必須是 INNERLEFT 連線到 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, ROLLUPCUBE 中的任何一個作為分組元素存在,那麼整個 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 SHAREFOR KEY SHARE 不能與 GROUP BY 一起指定。

HAVING 子句

可選的 HAVING 子句具有通用形式:

HAVING condition

其中 conditionWHERE 子句指定的相同。

HAVING 刪除不滿足條件的組行。 HAVINGWHERE 不同:WHERE 在應用 GROUP BY 之前過濾單個行,而 HAVING 過濾由 GROUP BY 建立的組行。 condition 中引用的每個列都必須明確引用一個分組列,除非該引用出現在聚合函式內,或者未分組列在函式上依賴於分組列。

HAVING 的存在會將一個查詢變成一個分組查詢,即使沒有 GROUP BY 子句。這與查詢包含聚合函式但沒有 GROUP BY 子時發生的情況相同。所有選定的行被視為形成一個單一的組,並且 SELECT 列表和 HAVING 子句只能從聚合函式中引用表列。這樣的查詢將在 HAVING 條件為真時發出單行,如果條件為假則發出零行。

目前,FOR NO KEY UPDATE, FOR UPDATE, FOR SHAREFOR KEY SHARE 不能與 HAVING 一起指定。

WINDOW 子句

可選的 WINDOW 子句具有通用形式:

WINDOW window_name AS ( window_definition ) [, ...]

其中 window_name 是一個可以在 OVER 子句或後續視窗定義中引用的名稱,而 window_definition 是:

[ existing_window_name ]
[ PARTITION BY expression [, ...] ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [ 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 } BETWEEN frame_start AND frame_end [ frame_exclusion ]

其中 frame_startframe_end 可以是以下之一:

UNBOUNDED PRECEDING
offset PRECEDING
CURRENT ROW
offset FOLLOWING
UNBOUNDED FOLLOWING

frame_exclusion 可以是以下之一:

EXCLUDE CURRENT ROW
EXCLUDE GROUP
EXCLUDE TIES
EXCLUDE NO OTHERS

如果省略 frame_end,則預設為 CURRENT ROW。限制是 frame_start 不能是 UNBOUNDED FOLLOWINGframe_end 不能是 UNBOUNDED PRECEDING,並且 frame_end 的選擇在上述 frame_startframe_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, ROWSGROUPS 模式如何。在 ROWS 模式下,CURRENT ROW 意味著框架以當前行開始或結束;但在 RANGEGROUPS 模式下,它意味著框架以當前行的第一個或最後一個對等行開始或結束。 offset PRECEDINGoffset 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 模式可能會產生不可預測的結果。RANGEGROUPS 模式旨在確保根據 ORDER BY 排序對等處理的行被視為相同:給定對等組的所有行都將在框架內或被排除在框架之外。

WINDOW 子句的目的是指定查詢的 SELECT 列表ORDER BY 子句中出現的 視窗函式 的行為。這些函式可以透過名稱在它們的 OVER 子句中引用 WINDOW 子句條目。 WINDOW 子句條目不必在任何地方被引用;如果它在查詢中未被使用,它將被簡單地忽略。可以完全不使用 WINDOW 子句就使用視窗函式,因為視窗函式呼叫可以直接在其 OVER 子句中指定其視窗定義。但是,當相同的視窗定義需要用於多個視窗函式時,WINDOW 子句可以節省輸入。

目前,FOR NO KEY UPDATE, FOR UPDATE, FOR SHAREFOR KEY SHARE 不能與 WINDOW 一起指定。

視窗函式在 第 3.5 節, 第 4.2.8 節, 和 第 7.2.5 節 中有詳細描述。

SELECT 列表

SELECT 列表 (在關鍵字 SELECTFROM 之間) 指定構成 SELECT 語句輸出行的表示式。這些表示式可以 (而且通常會) 引用在 FROM 子句中計算出的列。

正如在表中一樣,SELECT 的每個輸出列都有一個名稱。在簡單的 SELECT 中,這個名稱只是用於標記列以供顯示,但當 SELECT 是一個更大查詢的子查詢時,名稱對於大查詢來說是該子查詢產生的虛擬表的列名。要指定輸出列使用的名稱,請在列的表示式後寫入 AS output_name。(您可以省略 AS,但前提是所需的輸出名稱不匹配任何 PostgreSQL 關鍵字 (請參閱 附錄 C)。為防止將來可能新增關鍵字,建議您始終編寫 AS 或對輸出名稱加雙引號。) 如果您未指定列名,PostgreSQL 會自動選擇一個名稱。如果列的表示式是簡單的列引用,則選定的名稱與該列的名稱相同。在更復雜的情況下,可以使用函式或型別名稱,或者系統可能會回退到生成名稱,例如 ?column?

輸出列的名稱可以在 ORDER BYGROUP BY 子句中引用該列的值,但在 WHEREHAVING 子句中不能使用;在那裡您必須寫出表示式。

代替表示式,* 可以在輸出列表中作為所有選定行列的簡寫。此外,您也可以寫 table_name.* 作為僅來自該表的列的簡寫。在這些情況下,無法使用 AS 指定新名稱;輸出列名稱將與表列的名稱相同。

根據 SQL 標準,輸出列表中的表示式應在應用 DISTINCT, ORDER BY, 或 LIMIT 之前進行計算。這在使用 DISTINCT 時顯然是必要的,因為否則就不清楚哪些值正在被區分。然而,在許多情況下,如果輸出表達式在 ORDER BYLIMIT 之後進行計算會很方便;特別是當輸出列表包含任何易變或昂貴的函式時。有了這種行為,函式求值的順序就更直觀了,也不會有與永遠不會出現在輸出中的行相對應的求值。 PostgreSQL 將有效地在排序和限制之後計算輸出表達式,只要這些表示式未在 DISTINCT, ORDER BYGROUP 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 SHAREFOR 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 BYLIMIT。沒有括號時,這些子句將被視為應用於 UNION 的結果,而不是其右側輸入表示式。)

UNION 運算子計算參與的 SELECT 語句返回的行的集合並集。一個行存在於兩個結果集的集合並集中,如果它存在於至少一個結果集中。代表 UNION 直接運算元的兩個 SELECT 語句必須產生相同數量的列,並且對應的列必須是相容的資料型別。

除非指定了 ALL 選項,否則 UNION 的結果不包含任何重複行。 ALL 阻止消除重複項。(因此,UNION ALL 通常比 UNION 快得多;如果可以,請使用 ALL。) 可以編寫 DISTINCT 來明確指定刪除重複行的預設行為。

同一個 SELECT 語句中的多個 UNION 運算子按從左到右的順序進行計算,除非另有指示 (例如透過括號)。

目前,FOR NO KEY UPDATE, FOR UPDATE, FOR SHAREFOR 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 SHAREFOR 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 SHAREFOR KEY SHARE 不能用於 EXCEPT 結果或 EXCEPT 的任何輸入。

ORDER BY 子句

可選的 ORDER BY 子句具有此通用形式:

ORDER BY expression [ ASC | DESC | USING operator ] [ 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 }
OFFSET start

引數 count 指定要返回的最大行數,而 start 指定在開始返回行之前要跳過的行數。當兩者都指定時,在開始計算要返回的 count 行之前,將跳過 start 行。

如果 count 表示式求值為 NULL,則將其視為 LIMIT ALL,即無限制。如果 start 求值為 NULL,則其處理方式與 OFFSET 0 相同。

SQL:2008 引入了一種不同的語法來實現相同的結果,PostgreSQL 也支援它。它是:

OFFSET start { ROW | ROWS }
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }

在此語法中,標準要求 startcount 值必須是字面量常量、引數或變數名;作為 PostgreSQL 擴充套件,允許使用其他表示式,但通常需要用括號將其括起來以避免歧義。如果在 FETCH 子句中省略了 count,則預設為 1。 WITH TIES 選項用於返回根據 ORDER BY 子句在結果集中並列的任何其他行;在這種情況下,ORDER BY 是必需的,並且不允許 SKIP LOCKEDROWROWS 以及 FIRSTNEXT 是噪聲詞,不會影響這些子句的效果。根據標準,如果 OFFSETFETCH 子句都存在,則 OFFSET 子句必須出現在 FETCH 子句之前;但 PostgreSQL 比較寬鬆,允許任何順序。

使用 LIMIT 時,最好使用 ORDER BY 子句來約束結果行以獲得唯一順序。否則,您將獲得查詢行的一個不可預測的子集——您可能正在請求第 10 到第 20 行,但按什麼順序?除非您指定 ORDER BY,否則您不知道是什麼順序。

查詢規劃器在生成查詢計劃時會考慮 LIMIT,因此您很可能會根據 LIMITOFFSET 的使用情況獲得不同的計劃 (產生不同的行順序)。因此,使用不同的 LIMIT/OFFSET 值選擇查詢結果的不同子集 將導致不一致的結果,除非您使用 ORDER BY 來強制執行可預測的結果順序。這不是一個錯誤;這是 SQL 不保證按任何特定順序返回查詢結果 (除非使用 ORDER BY 來約束順序) 的固有後果。

如果沒有 ORDER BY 來強制選擇確定性子集,重複執行相同的 LIMIT 查詢甚至可能返回錶行的不同子集。同樣,這不是一個錯誤;在這種情況下,結果的確定性只是不被保證。

鎖定子句

FOR UPDATE, FOR NO KEY UPDATE, FOR SHAREFOR KEY SHARE鎖定子句;它們影響 SELECT 在從表中獲取行時如何鎖定行。

鎖定子句具有通用形式:

FOR lock_strength [ OF from_reference [, ...] ] [ NOWAIT | SKIP LOCKED ]

其中 lock_strength 可以是以下之一:

UPDATE
NO KEY UPDATE
SHARE
KEY SHARE

from_reference 必須是 FROM 子句中引用的表 alias 或非隱藏 table_name。有關每種行級鎖模式的更多資訊,請參閱 第 13.3.2 節

為防止操作等待其他事務提交,請使用 NOWAITSKIP LOCKED 選項。使用 NOWAIT 時,如果選定的行無法立即鎖定,則該語句會報告錯誤,而不是等待。使用 SKIP LOCKED 時,任何無法立即鎖定的選定行都會被跳過。跳過鎖定的行會提供不一致的資料檢視,因此不適用於通用工作,但可用於避免多個使用者訪問類似佇列的表時發生鎖爭用。請注意,NOWAITSKIP 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 BYLIMIT 或其他限制結合使用時。因此,只有在預期排序列會發生併發更新並且需要嚴格排序的結果時,才推薦使用此技術。

REPEATABLE READSERIALIZABLE 事務隔離級別下,這會導致序列化失敗(SQLSTATE'40001'),因此在這些隔離級別下不會出現行亂序的情況。

TABLE 命令

命令

TABLE name

等同於

SELECT * FROM name

它可以作為頂級命令使用,也可以作為複雜的查詢中的節省空間的語法變體。只有 WITHUNIONINTERSECTEXCEPTORDER BYLIMITOFFSETFETCHFOR 鎖定子句可以與 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

下一個示例展示瞭如何獲取表 distributorsactors 的並集,並將結果限制為每個表中以字母 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 節。)

此示例使用 LATERALmanufacturers 表的每一行應用一個返回集合的函式 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 語義。PostgreSQLUNNEST() 與其他返回集合的函式視為相同。

GROUP BYORDER BY 可用的名稱空間

在 SQL-92 標準中,ORDER BY 子句只能使用輸出列名或數字,而 GROUP BY 子句只能使用基於輸入列名的表示式。PostgreSQL 擴充套件了這兩個子句,允許使用另一種選擇(但如果存在歧義,它會使用標準的解釋)。PostgreSQL 還允許這兩個子句指定任意表達式。請注意,表示式中出現的名稱始終被視為輸入列名,而不是輸出列名。

SQL:1999 及更高版本使用稍有不同的定義,該定義與 SQL-92 不完全向後相容。但在大多數情況下,PostgreSQL 會像 SQL:1999 一樣解釋 ORDER BYGROUP BY 表示式。

函式依賴

PostgreSQL 僅當表的 [主鍵](primary-key.html) 包含在 GROUP BY 列表中時,才識別函式依賴(允許從 GROUP BY 中省略列)。SQL 標準規定了應識別的附加條件。

LIMITOFFSET

LIMITOFFSET 子句是 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 查詢以及子 SELECTs 中,但這是一種擴充套件。FOR NO KEY UPDATEFOR SHAREFOR KEY SHARE 變體,以及 NOWAITSKIP LOCKED 選項,均未出現在標準中。

WITH 中的資料修改語句

PostgreSQL 允許將 INSERTUPDATEDELETEMERGE 用作 WITH 查詢。這在 SQL 標準中找不到。

非標準子句

DISTINCT ON ( ... ) 是 SQL 標準的擴充套件。

ROWS FROM( ... ) 是 SQL 標準的擴充套件。

WITHMATERIALIZEDNOT MATERIALIZED 選項是 SQL 標準的擴充套件。

提交更正

如果您在文件中看到任何不正確、與您對特定功能的使用經驗不符或需要進一步說明的內容,請使用 此表單 報告文件問題。