支援版本:目前 (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 列表中引用的臨時資料表。 在 FROM 中被引用多次的 WITH 查詢只會計算一次,除非使用 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 來明確指定消除重複的列。 請注意,即使 ALLSELECT 本身的預設行為,但 DISTINCT 在這裡也是預設行為。(請參閱下方的UNION 子句INTERSECT 子句EXCEPT 子句。)

  8. 如果指定了 ORDER BY 子句,則傳回的列會依指定的順序排序。 如果未給定 ORDER BY,則會以系統認為最快產生結果的任何順序傳回列。(請參閱下方的ORDER BY 子句。)

  9. 如果指定了 LIMIT(或 FETCH FIRST)或 OFFSET 子句,則 SELECT 陳述式只會傳回結果列的子集。(請參閱下方的LIMIT 子句。)

  10. 如果指定了 FOR UPDATEFOR NO KEY UPDATEFOR SHAREFOR KEY SHARE,則 SELECT 陳述式會鎖定選定的列,以防止並行更新。(請參閱下方的鎖定子句。)

您必須對 SELECT 命令中使用的每個欄位擁有 SELECT 權限。 使用 FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE 也需要 UPDATE 權限(至少針對每個選定的資料表中的一個欄位)。

參數

WITH 子句

WITH 子句允許您指定一個或多個子查詢,這些子查詢可以在主查詢中以名稱引用。這些子查詢實際上充當主查詢期間的臨時表或視窗。每個子查詢都可以是 SELECTTABLEVALUESINSERTUPDATEDELETEMERGE 語句。在 WITH 中編寫資料修改語句(INSERTUPDATEDELETEMERGE)時,通常包含 RETURNING 子句。形成臨時表並由主查詢讀取的是 RETURNING 的輸出,而非 語句修改的底層表。如果省略 RETURNING,該語句仍然會執行,但不產生任何輸出,因此無法作為表被主查詢引用。

必須為每個 WITH 查詢指定一個名稱(沒有綱要限定)。您可以選擇指定欄位名稱列表;如果省略此列表,則欄位名稱將從子查詢中推斷。

如果指定了 RECURSIVE,則允許 SELECT 子查詢按名稱引用自身。這樣的子查詢必須具有以下形式

non_recursive_term UNION [ ALL | DISTINCT ] recursive_term

遞迴自引用必須出現在 UNION 的右側。每個查詢僅允許一個遞迴自引用。不支援遞迴資料修改語句,但您可以在資料修改語句中使用遞迴 SELECT 查詢的結果。有關範例,請參閱第 7.8 節

RECURSIVE 的另一個效果是 WITH 查詢不必排序:一個查詢可以引用列表中稍後的另一個查詢。(但是,未實現循環引用或相互遞迴。)如果沒有 RECURSIVEWITH 查詢只能引用 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

現有表格或檢視表的名稱(可選擇性地使用 schema 限定)。如果在表格名稱之前指定了 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 數字或表達式。種子值可以是任何非 null 的浮點數值。如果表格在此期間沒有變更,則兩個指定相同種子和 argument 值的查詢將選擇相同的表格樣本。但是,不同的種子值通常會產生不同的樣本。如果未給定 REPEATABLE,則每次查詢都會根據系統產生的種子選擇一個新的隨機樣本。請注意,某些附加取樣方法不接受 REPEATABLE,並且每次使用都會始終產生新的樣本。

select

SELECT 可以出現在 FROM 子句中。這就像它的輸出被建立為此單個 SELECT 命令期間的暫存表格一樣。請注意,子 SELECT 必須用括號括起來,並且可以像表格一樣提供別名。此處也可以使用 VALUES 命令。

with_query_name

透過寫入 WITH 查詢的名稱來引用它,就像查詢的名稱是表格名稱一樣。(事實上,對於主要查詢的目的而言,WITH 查詢會隱藏任何同名的真實表格。如有必要,您可以透過 schema 限定表格的名稱來引用同名的真實表格。)可以像表格一樣提供別名。

function_name

函數呼叫可以出現在 FROM 子句中。(這對於傳回結果集的函數特別有用,但可以使用任何函數。)這就像函數的輸出被建立為此單個 SELECT 命令期間的暫存表格一樣。如果函數的結果類型是複合類型(包括具有多個 OUT 參數的函數的情況),則每個屬性都會成為隱含表格中的一個單獨欄位。

當將可選的 WITH ORDINALITY 子句新增到函數呼叫時,類型為 bigint 的附加欄位將附加到函數的結果欄位。此欄位會對函數結果集的列進行編號,從 1 開始。預設情況下,此欄位的名稱為 ordinality

可以像表格一樣提供別名。如果寫了別名,也可以寫入欄位別名清單,以提供函數的複合傳回類型(包括 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_conditionUSING (join_column [, ...])NATURAL 三者之一。有關含義,請參閱下文。

JOIN 子句組合了兩個 FROM 項目,為了方便起見,我們將它們稱為表格,但實際上它們可以是任何類型的 FROM 項目。如有必要,請使用括號來確定巢狀結構的順序。在沒有括號的情況下,JOIN 會從左到右巢狀排列。在任何情況下,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 Join 方式連接到 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 SETSROLLUPCUBE 作為分組元素存在,則整個 GROUP BY 子句定義了一些獨立的 grouping sets。 其效果等同於在子查詢之間建構一個 UNION ALL,其中每個子查詢的分組集合作為其 GROUP BY 子句。 可選的 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 UPDATEFOR UPDATEFOR SHAREFOR KEY SHAREGROUP BY 一起使用。

HAVING 子句

可選的 HAVING 子句具有以下一般形式:

HAVING condition

其中 conditionWHERE 子句中指定的條件相同。

HAVING 刪除不滿足條件的群組資料列。HAVINGWHERE 不同:WHERE 在應用 GROUP BY 之前篩選個別資料列,而 HAVING 篩選由 GROUP BY 建立的群組資料列。 condition 中引用的每個欄位都必須明確引用分組欄位,除非該參考出現在聚合函數中,或者未分組的欄位在功能上依賴於分組欄位。

即使沒有 GROUP BY 子句,HAVING 的存在也會將查詢轉換為分組查詢。 這與查詢包含聚合函數但沒有 GROUP BY 子句時發生的情況相同。 所有選定的資料列都被認為形成單一群組,並且 SELECT 清單和 HAVING 子句只能從聚合函數中引用資料表欄位。 如果 HAVING 條件為 true,則此類查詢將發出單個資料列;如果條件為 false,則發出零個資料列。

目前,無法將 FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHAREHAVING 一起使用。

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 子句時,它才能指定 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 相同;它將框架設定為從分割區的開頭到目前列的最後一個同層級(window 的 ORDER BY 子句認為與目前列等價的列;如果沒有 ORDER BY,則所有列都是同層級)。一般來說,UNBOUNDED PRECEDING 表示框架從分割區的第一列開始,類似地,UNBOUNDED FOLLOWING 表示框架以分割區的最後一列結束,無論是 RANGEROWS 還是 GROUPS 模式。在 ROWS 模式下,CURRENT ROW 表示框架從目前列開始或結束;但在 RANGEGROUPS 模式下,它表示框架以 ORDER BY 排序中目前列的第一個或最後一個同層級開始或結束。offset PRECEDINGoffset FOLLOWING 選項的含義因框架模式而異。在 ROWS 模式下,offset 是一個整數,表示框架從目前列之前或之後的多少列開始或結束。在 GROUPS 模式下,offset 是一個整數,表示框架從目前列的同層級群組之前或之後的多少個同層級群組開始或結束,其中同層級群組是根據 window 的 ORDER BY 子句等價的列群組。在 RANGE 模式下,使用 offset 選項需要 window 定義中只有一個 ORDER BY 欄位。然後,框架包含那些排序欄位值不超過 offset 小於(對於 PRECEDING)或大於(對於 FOLLOWING)目前列的排序欄位值的列。在這些情況下,offset 表達式的資料類型取決於排序欄位的資料類型。對於數值排序欄位,它通常與排序欄位的類型相同,但對於日期時間排序欄位,它是一個 interval。在所有這些情況下,offset 的值必須是非 null 且非負數。此外,雖然 offset 不必是簡單的常數,但它不能包含變數、聚合函數或 window 函數。

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 UPDATEFOR UPDATEFOR 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 標準,輸出列表中的表達式應在應用 DISTINCTORDER BYLIMIT 之前計算。這在使用 DISTINCT 時顯然是必要的,因為否則不清楚哪些值是不同的。但是,在許多情況下,如果在 ORDER BYLIMIT 之後計算輸出表達式會很方便;特別是如果輸出列表包含任何不穩定或昂貴的函數。在這種行為下,函數求值的順序更直觀,並且不會有對應於從未出現在輸出中的行的求值。PostgreSQL 將有效地在排序和限制之後評估輸出表達式,只要這些表達式未在 DISTINCTORDER BYGROUP BY 中引用即可。(作為一個反例,SELECT f(x) FROM tab ORDER BY 1 顯然必須在排序之前評估 f(x)。) 包含集合回傳函數的輸出表達式在排序之後和限制之前有效地進行評估,因此 LIMIT 將作用於截斷集合回傳函數的輸出。

注意

9.6 之前的 PostgreSQL 版本未提供有關輸出表達式與排序和限制的評估時間的任何保證;它取決於所選查詢計劃的形式。

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 UPDATEFOR UPDATEFOR SHAREFOR KEY SHAREDISTINCT 一起指定。

UNION 子句

UNION 子句具有以下一般形式

select_statement UNION [ ALL | DISTINCT ] select_statement

select_statement 是任何沒有 ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE 子句的 SELECT 語句。(如果子表達式用括號括起來,則可以将 ORDER BYLIMIT 附加到該子表達式。如果沒有括號,則這些子句將被視為應用於 UNION 的結果,而不是其右手輸入表達式。)

UNION 運算子計算所涉及的 SELECT 語句返回的列的集合聯集。如果列出現在至少一個結果集中,則該列位於兩個結果集的集合聯集中。代表 UNION 直接運算元的兩個 SELECT 語句必須產生相同數量的欄位,並且相應的欄位必須是相容的資料類型。

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

同一個 SELECT 語句中的多個 UNION 運算子從左到右評估,除非括號另有說明。

目前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE 不能為 UNION 的結果或 UNION 的任何輸入指定。

INTERSECT 子句

INTERSECT 子句具有以下一般形式

select_statement INTERSECT [ ALL | DISTINCT ] select_statement

select_statement 是任何沒有 ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR 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 UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE 不能為 INTERSECT 的結果或 INTERSECT 的任何輸入指定。

EXCEPT 子句

EXCEPT 子句具有以下一般形式

select_statement EXCEPT [ ALL | DISTINCT ] select_statement

select_statement 是任何沒有 ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE 子句的 SELECT 語句。

EXCEPT 運算子會計算出存在於左側 SELECT 語句的結果中,但不存在於右側語句結果中的列集合。

除非指定 ALL 選項,否則 EXCEPT 的結果不會包含任何重複的列。 使用 ALL 時,如果某列在左側表格中有 m 個重複項,在右側表格中有 n 個重複項,則該列在結果集中將出現 max(m-n,0) 次。 可以寫入 DISTINCT 來明確指定消除重複列的預設行為。

在同一個 SELECT 語句中,多個 EXCEPT 運算子會從左到右進行評估,除非使用括號另行指定。 EXCEPT 的優先順序與 UNION 相同。

目前,FOR NO KEY UPDATEFOR UPDATEFOR 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;

此功能的一個限制是,應用於 UNIONINTERSECTEXCEPT 子句結果的 ORDER BY 子句只能指定輸出列名稱或數字,而不能指定表達式。

如果 ORDER BY 表達式是一個簡單的名稱,它同時匹配輸出列名稱和輸入列名稱,則 ORDER BY 會將其解釋為輸出列名稱。 這與 GROUP BY 在相同情況下所做的選擇相反。 這種不一致是為了與 SQL 標準相容。

您可以選擇在 ORDER BY 子句中的任何表達式之後添加關鍵字 ASC (升序) 或 DESC (降序)。 如果未指定,則預設情況下會假定 ASC。 或者,可以在 USING 子句中指定特定的排序運算子名稱。 排序運算子必須是某些 B 樹運算子家族的小於或大於成員。 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 DESCORDER 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 是噪音詞,不會影響這些子句的效果。 根據標準,如果同時存在 OFFSET 子句和 FETCH 子句,則 OFFSET 子句必須位於 FETCH 子句之前;但是 PostgreSQL 比較寬鬆,允許任何一種順序。

使用 LIMIT 時,最好使用 ORDER BY 子句將結果列限制為唯一順序。 否則,您將獲得查詢列的不可預測的子集 — 您可能要求第十到第二十列,但在什麼順序中是第十到第二十列? 除非您指定 ORDER BY,否則您不知道什麼順序。

查詢規劃器在產生查詢計劃時會考慮 LIMIT,因此您很可能會獲得不同的計劃(產生不同的列順序),具體取決於您對 LIMITOFFSET 的使用方式。 因此,除非您使用 ORDER BY 強制執行可預測的結果順序,否則使用不同的 LIMIT/OFFSET 值來選擇查詢結果的不同子集將產生不一致的結果。 這不是一個錯誤;這是 SQL 不保證以任何特定順序傳遞查詢結果的固有結果,除非使用 ORDER BY 來限制順序。

如果沒有 ORDER BY 來強制選擇確定性的子集,即使是重複執行相同的 LIMIT 查詢,也可能會傳回表格列的不同子集。 同樣,這不是一個錯誤;在這種情況下,結果的確定性根本無法保證。

鎖定子句

FOR UPDATEFOR NO KEY UPDATEFOR SHAREFOR KEY SHARE鎖定子句;它們會影響 SELECT 如何在從表格中獲取列時鎖定這些列。

鎖定子句具有以下一般形式

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

其中 lock_strength 可以是以下之一

UPDATE
NO KEY UPDATE
SHARE
KEY SHARE

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

為了防止操作等待其他事務提交,請使用 NOWAITSKIP LOCKED 選項。 使用 NOWAIT,如果無法立即鎖定選定的列,則語句會報告錯誤,而不是等待。 使用 SKIP LOCKED,將跳過任何無法立即鎖定的選定列。 跳過鎖定的列會提供不一致的資料檢視,因此不適合一般用途,但可用於避免多個使用者存取類似佇列的表格時的鎖定爭用。 請注意,NOWAITSKIP LOCKED 僅適用於列級別鎖定 — 所需的 ROW SHARE 表格級別鎖定仍然以普通方式取得(請參閱第 13 章)。 如果您需要先取得表格級別鎖定而不等待,則可以首先將 LOCKNOWAIT 選項一起使用。

如果在鎖定子句中指定了特定表格,則僅鎖定來自這些表格的列;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

下一個範例顯示如何取得 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 節。)

此範例使用 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 標準中,當新的欄位名稱是有效的欄位名稱(即與任何保留關鍵字不同)時,可以在輸出欄位名稱之前省略可選的關鍵字 ASPostgreSQL 稍微更嚴格:如果新的欄位名稱與任何關鍵字匹配,無論是否保留,則需要 AS。建議的做法是使用 AS 或雙引號括住輸出欄位名稱,以防止與未來添加的關鍵字發生任何可能的衝突。

FROM 項目中,標準和 PostgreSQL 都允許在別名是未保留的關鍵字之前省略 AS。但是,由於語法上的歧義,這對於輸出欄位名稱來說是不切實際的。

省略 FROM 中的子 SELECT 別名

根據 SQL 標準,FROM 清單中的子 SELECT 必須具有別名。在 PostgreSQL 中,可以省略此別名。

ONLY 和繼承

SQL 標準要求在撰寫 ONLY 時,表格名稱周圍使用括號,例如 SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...PostgreSQL 認為這些括號是可選的。

PostgreSQL 允許撰寫尾隨的 *,以明確指定包含子表格的非 ONLY 行為。標準不允許這樣做。

(這些要點同樣適用於所有支援 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 BYORDER BY 可用的命名空間

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

SQL:1999 及之後的版本使用略有不同的定義,與 SQL-92 並非完全向上兼容。但在大多數情況下,PostgreSQL 對於 ORDER BYGROUP BY 表達式的解釋方式與 SQL:1999 相同。

函數依賴 (Functional Dependencies)

只有當資料表的主鍵包含在 GROUP BY 清單中時,PostgreSQL 才會識別函數依賴(允許從 GROUP BY 中省略欄位)。SQL 標準指定了應該識別的其他條件。

LIMITOFFSET

LIMITOFFSET 子句是 PostgreSQL 特有的語法,也被 MySQL 使用。SQL:2008 標準引入了 OFFSET ... FETCH {FIRST|NEXT} ... 子句來實現相同的功能,如上文 LIMIT 子句 中所示。這種語法也被 IBM DB2 使用。(為 Oracle 編寫的應用程式經常使用一種變通方法,涉及自動生成的 rownum 欄位,該欄位在 PostgreSQL 中不可用,以實現這些子句的效果。)

FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

儘管 FOR UPDATE 出現在 SQL 標準中,但標準只允許它作為 DECLARE CURSOR 的一個選項。PostgreSQL 允許它在任何 SELECT 查詢以及子查詢中,但這是一種擴展。FOR NO KEY UPDATEFOR SHAREFOR KEY SHARE 變體,以及 NOWAITSKIP LOCKED 選項,沒有出現在標準中。

WITH 子句中的資料修改語句

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

非標準子句

DISTINCT ON ( ... ) 是 SQL 標準的擴展。

ROWS FROM( ... ) 是 SQL 標準的擴展。

WITHMATERIALIZEDNOT MATERIALIZED 選項是 SQL 標準的擴展。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步說明的地方,請使用此表單來回報文件問題。