日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

重要

本文中含有需要您注意的重要提示信息,忽略該信息可能對您的業(yè)務造成影響,請務必仔細閱讀。

本文介紹了如何通過SELECT語句從表或視圖檢索行。

語法

    [ WITH [ RECURSIVE ] with_query [, ...] ]
    SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
        [ * | expression [ [ AS ] output_name ] [, ...] ]
        [ FROM from_item [, ...] ]
        [ WHERE condition ]
        [ GROUP BY 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 table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]

    其中 from_item 可以是以下之一:

        [ 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 [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]

    并且 grouping_element 可以是以下之一:

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

    并且 with_query 是:

        with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( select | values | insert | update | delete )

    TABLE [ ONLY ] table_name [ * ]

說明

SELECT語句支持在單個或多個表中檢索目標行。 SELECT的通常處理如下:

  1. WITH列表中的所有查詢都會被計算。這些查詢實際充當了在FROM列表中可以引用的臨時表。在 FROM中被引用多次的WITH查詢只會被計算一次,除非另有說明,否則NOT MATERIALIZED

  2. FROM列表中的所有元素都會被計算( FROM中的每一個元素都是一個真實表或者虛擬表)。 如果在FROM列表中指定了多于一個元素,它們會被交叉連接在一起。

  3. 如果指定了WHERE子句,所有不滿足該條件的行都會被從輸出中消除。

  4. 如果指定了GROUP BY子句或者如果有聚集函數(shù),輸出會被組合成由在一個或者多個值上匹配的行構(gòu)成的分組,并且在其上計算聚集函數(shù)的結(jié)果。如果出現(xiàn)了HAVING子句,它會消除不滿足給定條件的分組。

  5. 對于每一個被選中的行或者行組,會使用SELECT 輸出表達式計算實際的輸出行。

  6. SELECT DISTINCT從結(jié)果中消除重復的行。 SELECT DISTINCT ON消除在所有指定表達式上匹配的行。SELECT ALL(默認)將返回所有候選行, 包括重復的行。

  7. 通過使用操作符UNIONINTERSECTEXCEPT,多于一個SELECT語句的輸出可以被整合形成結(jié)果集。UNION操作符返回位于一個或者兩個結(jié)果集中的全部行。INTERSECT操作符返回同時位于兩個結(jié)果集中的所有行。EXCEPT操作符返回位于第一個結(jié)果集但不在第二個結(jié)果集中的行。在所有三種情況下, 重復行都會被消除(除非指定ALL)。可以增加噪聲詞DISTINCT來顯式地消除重復行。注意雖然 ALLSELECT自身的默認行為, 但這里DISTINCT是默認行為。

  8. 如果指定了ORDER BY子句,被返回的行會以指定的順序排序。如果沒有給定ORDER BY,系統(tǒng)會以能最快產(chǎn)生行的順序返回它們。

  9. 如果指定了LIMIT(或FETCH FIRST) 或者OFFSET子句,SELECT 語句只返回結(jié)果行的一個子集。

  10. 如果指定了FOR UPDATEFOR NO KEY UPDATEFOR SHARE 或者FOR KEY SHARESELECT語句會把被選中的行鎖定而不讓并發(fā)更新訪問它們。

說明

您必須擁有在一個SELECT命令中使用的每一列上的 SELECT特權(quán)。FOR NO KEY UPDATEFOR UPDATEFOR SHARE或者FOR KEY SHARE 還要求(對這樣選中的每一個表至少一列的)UPDATE 特權(quán)。

參數(shù)說明

WITH 子句

WITH子句允許指定一個或者多個在主查詢中可以對其名稱引用的子查詢。在主查詢期間子查詢實際扮演了臨時表或者視圖的角色。每一個子查詢都可以是一個SELECTTABLEVALUESINSERTUPDATE或者 DELETE語句。

WITH中寫一個數(shù)據(jù)修改語句(INSERTUPDATE或者 DELETE)時,通常要包括一個 RETURNING子句。構(gòu)成被主查詢讀取的臨時表的是 RETURNING的輸出,而不是該語句修改的底層表。如果省略RETURNING,該語句仍會被執(zhí)行,但是它不會產(chǎn)生輸出,因此它不能作為一個表從主查詢引用。

對于每一個WITH查詢,都必須指定一個名稱(無需模式限定)。可選的,可以指定一個列名列表。如果省略該列表,會從該子查詢中推導列名。

如果指定了RECURSIVE,則允許 SELECT子查詢使用名稱引用自身。 這樣子查詢的形式必須為:

non_recursive_term UNION [ ALL | DISTINCT ] recursive_term

其中遞歸自引用必須出現(xiàn)在UNION的右手邊。每個查詢中只允許一個遞歸自引用。不支持遞歸數(shù)據(jù)修改語句,但支持在數(shù)據(jù)查詢語句中使用遞歸SELECT查詢的結(jié)果。

RECURSIVE的另一個效果是 WITH查詢不需要被排序:一個查詢可以引用另一個在列表中比它靠后的查詢(循環(huán)引用或者互遞歸沒有實現(xiàn))。 如果沒有RECURSIVEWITH 查詢只能引用在WITH列表中位置更前面的兄弟 WITH查詢。

WITH子句中有多個查詢時,RECURSIVE應只編寫一次,緊跟在WITH之后。 它適用于WITH子句中的所有查詢,盡管它對不使用遞歸或前向引用的查詢沒有影響。

主查詢以及WITH查詢?nèi)浚ɡ碚撋希┰谕粫r間被執(zhí)行。這意味著從該查詢的任何部分都無法看到 WITH中的一個數(shù)據(jù)修改語句的效果,不過可以讀取其RETURNING輸出。如果兩個這樣的數(shù)據(jù)修改語句嘗試修改相同的行,結(jié)果將無法確定。

WITH查詢的一個關(guān)鍵屬性是,即使主查詢多次引用它們,它們通常每次執(zhí)行主查詢只計算一次。 特別是,數(shù)據(jù)修改語句確保執(zhí)行一次而且只執(zhí)行一次,而與主查詢是否讀取它們的全部或任何輸出無關(guān)。

但是,WITH查詢可以標記為NOT MATERIALIZED以移除此保證。 在這種情況下,WITH查詢可以折疊到主查詢中,就好像它是主查詢的FROM子句中的簡單的 sub-SELECT。 如果主查詢多次引用WITH查詢,則會導致重復計算。但是,如果每次此類使用只需要WITH查詢的總輸出中的幾行,NOT MATERIALIZED可以通過允許查詢聯(lián)合優(yōu)化來節(jié)省開銷。 NOT MATERIALIZED被忽略,如果它被附加到一個遞歸的WITH查詢,或者不是邊際效應無關(guān)的(也就是說,不是包含非易失性函數(shù)的普通的SELECT)。

默認情況下,如果查詢在主查詢的FROM子句中僅一次使用,則邊際效應無關(guān)的WITH查詢將折疊到主查詢中。 這允許在語義不可見的情況下兩個查詢級別的聯(lián)合優(yōu)化。 但是,通過將WITH查詢標記為MATERIALIZED,可以防止此類折疊。 這可能很有用,例如,如果WITH查詢被用作優(yōu)化圍欄,以防止規(guī)劃者選擇錯誤計劃。

FROM 子句

FROM子句為SELECT 指定一個或者更多源表。如果指定了多個源表,結(jié)果將是所有源表的笛卡爾積(交叉連接)。但是通常會增加限定條件(通過 WHERE)來把返回的行限制為該笛卡爾積的一個小子集。

FROM子句可以包含下列元素:

  • table_name一個現(xiàn)有表或視圖的名稱(可以是模式限定的)。如果在表名前指定了 ONLY,則只會掃描該表。如果沒有指定 ONLY,該表及其所有后代表(如果有)都會被掃描。可選的,可以在表名后指定來顯式地指示包括后代表。

  • alias一個包含別名的FROM項的替代名稱。別名被用于讓書寫簡潔或者消除自連接中的混淆(其中同一個表會被掃描多次)。當提供一個別名時,表或者函數(shù)的實際名稱會被隱藏。例如,給定FROM foo AS fSELECT的剩余部分就必須以 f而不是foo來引用這個 FROM項。如果寫了一個別名,還可以寫一個列別名列表來為該表的一個或者多個列提供替代名稱。

  • TABLESAMPLEsampling_method(argument[, ...] ) [ REPEATABLE (seed) ]table_name之后的 TABLESAMPLE子句表示應該用指定的 sampling_method 來檢索表中行的子集。這種采樣優(yōu)先于任何其他過濾器(例如 WHERE子句)。標準發(fā)布包括兩種采樣方法:BERNOULLISYSTEM, 其他采樣方法可以通過擴展安裝在數(shù)據(jù)庫中。

    BERNOULLI以及SYSTEM采樣方法都接受一個 參數(shù),它表示要采樣的表的分數(shù),表示為一個0到100之間的百分數(shù)。這個參數(shù)可以是任意的 實數(shù)值表達式(其他的采樣方法可能接受更多或者不同的參數(shù))。這兩種方法都返回一個隨機選取的該表采樣,其中包含了指定百分數(shù)的表行。BERNOULLI方法掃描整個表并且用指定的幾率選擇或者忽略行。SYSTEM方法會做塊層的采樣,每個塊都有指定的機會能被選中,被選中塊中的所有行都會被返回。在指定較小的采樣百分數(shù)時,SYSTEM 方法要比BERNOULLI方法快很多,但是前者可能由于聚簇效應返回隨機性較差的表采樣。

    可選的REPEATABLE子句指定一個用于產(chǎn)生采樣方法中隨機數(shù)的 種子數(shù)或表達式。種子值可以是任何非空浮點值。如果查詢時表沒有被更改,指定相同種子和 argument值的兩個查詢將會選擇該表相同的采樣。但是不同的種子值通常將會產(chǎn)生不同的采樣。如果沒有給出REPEATABLE,則會基于一個系統(tǒng)產(chǎn)生的種子為每一個查詢選擇一個新的隨機采樣。注意有些擴展采樣方法不接受REPEATABLE,并且將總是為每一次使用產(chǎn)生新的采樣。

  • select一個子SELECT可以出現(xiàn)在 FROM子句中。這就好像把它的輸出創(chuàng)建為一個存在于該SELECT命令期間的臨時表。子-SELECT必須用圓括號包圍,并且 必須為它提供一個別名。也可以在這里使用一個 VALUES 命令。

  • with_query_name可以通過寫一個WITH查詢的名稱來引用它,就好像該查詢的名稱是一個表名(實際上,該WITH查詢會為主查詢隱藏任何具有相同名稱的真實表。如果必要,你可以使用帶模式限定的方式以相同的名稱來引用真實表)。可以像表一樣, 以同樣的方式提供別名。

  • function_name函數(shù)調(diào)用可以出現(xiàn)在FROM子句中(對于返回結(jié)果集合的函數(shù)特別有用,但是可以使用任何函數(shù))。這就好像把該函數(shù)的輸出創(chuàng)建為一個存在于該SELECT命令期間的臨時表。當為該函數(shù)調(diào)用增加可選的 WITH ORDINALITY子句時,會在該函數(shù)的輸出列之后追加一個新的列來為每一行編號。

    可以用和表一樣的方式提供一個別名。如果寫了一個別名,還可以寫一個列別名列表來為該函數(shù)的組合返回類型的一個或者多個屬性提供替代名稱, 包括由ORDINALITY(如果有)增加的新列。

    通過把多個函數(shù)調(diào)用包圍在ROWS FROM( ... )中可以把它們整合在單個FROM-子句項中。這樣一個項的輸出是把每一個函數(shù)的第一行串接起來,然后是每個函數(shù)的第二行,以此類推。如果有些函數(shù)產(chǎn)生的行比其他函數(shù)少,則在缺失數(shù)據(jù)的地方放上空值,這樣被返回的總行數(shù)總是和產(chǎn)生最多行的函數(shù)一樣。

    如果函數(shù)被定義為返回record數(shù)據(jù)類型,那么必須出現(xiàn)一個別名或者關(guān)鍵詞AS,后面跟上形為 (column_namedata_type[, ...])的列定義列表。列定義列表必須匹配該函數(shù)返回的列的實際數(shù)量和類型。

    在使用ROWS FROM( ... )語法時,如果函數(shù)之一要求一個列定義列表,最好把該列定義列表放在ROWS FROM( ... )中該函數(shù)的調(diào)用之后。當且僅當正好只有一個函數(shù)并且沒有WITH ORDINALITY子句時,才能把列定義列表放在 ROWS FROM( ... )結(jié)構(gòu)后面。

    要把ORDINALITY和列定義列表一起使用,你必須使用 ROWS FROM( ... )語法,并且把列定義列表放在 ROWS FROM( ... )里面。

  • join_type該參數(shù)為以下項之一

    • [ INNER ] JOIN

    • LEFT [ OUTER ] JOIN

    • RIGHT [ OUTER ] JOIN

    • FULL [ OUTER ] JOIN

    • CROSS JOIN

    對于INNEROUTER連接類型,必須指定一個連接條件,即 NATURALON join_condition或者 USING (join_column[, ...]) 之一(只能有一種)。其含義見下文。對于 CROSS JOIN,上述子句不能出現(xiàn)。

    一個JOIN子句聯(lián)合兩個FROM項( 為了方便我們稱之為“表”,盡管實際上它們可以是任何類型的FROM項)。如有必要可以使用圓括號確定嵌套的順序。 在沒有圓括號時,JOIN會從左至右嵌套。在任何情況下,JOIN的聯(lián)合比分隔FROM-列表項的逗號更強。

    CROSS JOININNER JOIN 會產(chǎn)生簡單的笛卡爾積,也就是與在FROM的頂層列出兩個表得到的結(jié)果相同,但是要用連接條件(如果有)約束該結(jié)果。 CROSS JOININNER JOIN ON (TRUE)等效,也就是說條件不會移除任何行。這些連接類型只是一種記號上的方便,因為沒有什么是你用純粹的FROMWHERE能做而它們不能做的。

    LEFT OUTER JOIN返回被限制過的笛卡爾積中的所有行(即所有通過了其連接條件的組合行),外加左手表中沒有相應的通過了連接條件的右手行的每一行的拷貝。通過在右手列中插入空值,這種左手行會被擴展為連接表的完整行。注意在決定哪些行匹配時,只考慮JOIN子句自身的條件。之后才應用外條件。

    相反,RIGHT OUTER JOIN返回所有連接行,外加每一個沒有匹配上的右手行(在左端用空值擴展)。這只是為了記號上的方便,因為你可以通過交換左右表把它轉(zhuǎn)換成一個LEFT OUTER JOIN

    FULL OUTER JOIN返回所有連接行,外加每一個沒有匹配上的左手行(在右端用空值擴展),再外加每一個沒有匹配上的右手行(在左端用空值擴展)。

  • ONjoin_conditionjoin_condition 是一個會得到boolean類型值的表達式(類似于一個 WHERE子句),它說明一次連接中哪些行被認為相匹配。

  • USING (join_column[, ...] ):格式USING ( a, b, ... )的子句是 ON left_table.a = right_table.a AND left_table.b = right_table.b ...的簡寫。還有, USING表示每一對相等列中只有一個會被包括在連接輸出中。

  • NATURALNATURAL是一個USING列表的速記,該列表中提到兩個表中具有匹配名稱的所有的列。如果沒有公共列名,則NATURAL等效于ON TRUE

  • LATERALLATERAL關(guān)鍵詞可以放在一個子-SELECT FROM項前面。這允許該子SELECT引用FROM列表中在它之前的FROM項的列(如果沒有LATERAL,每一個子SELECT會被獨立計算并且因此不能交叉引用任何其他的FROM項)。

    LATERAL也可以放在一個函數(shù)調(diào)用 FROM項前面,但是在這種情況下它只是一個噪聲詞,因為在任何情況下函數(shù)表達式都可以引用在它之前的 FROM項。

    LATERAL項可以出現(xiàn)在FROM列表頂層,或者一個JOIN中。在后一種情況中,它也可以引用其作為右手端的JOIN左手端上的任何項。

    當一個FROM項包含LATERAL交叉引用時,計算會如此進行:對提供被交叉引用列的FROM項的每一行或者提供那些列的多個FROM項的每一個行集,使用該行或者行集的那些列值計算LATERAL項。結(jié)果行會與計算得到它們的行進行通常的連接。對來自哪些列的源表的每一行或者行集都會重復這樣的步驟。

    列的源表必須以INNER或者LEFT的方式連接到 LATERAL項,否則就沒有用于為 LATERAL項計算每一個行集的良定行集。盡管 XRIGHT JOIN LATERAL Y這樣的結(jié)構(gòu)在語法上是合法的, 但實際上不允許用于在 Y中引用 X

WHERE 子句

可選的WHERE子句的形式如下;

    WHERE condition

其中 condition 是任一計算得到布爾類型結(jié)果的表達式。任何不滿足這個條件的行都會從輸出中被去除。如果用一行的實際值替換其中的變量引用后,該表達式返回真,則該行符合條件。

GROUP BY 子句

可選的GROUP BY子句的形式如下:

    GROUP BY grouping_element [, ...]

GROUP BY將會把所有被選擇的行中共享相同分組表達式值的那些行壓縮成一個行。一個被用在 grouping_element中的 expression可以是輸入列名、輸出列 (SELECT列表項)的名稱或序號或者由輸入列值構(gòu)成的任意表達式。在出現(xiàn)歧義時,GROUP BY名稱將被解釋為輸入列名而不是輸出列名。

如果任何GROUPING SETSROLLUP或者 CUBE作為分組元素存在,則GROUP BY子句整體上定義了數(shù)個獨立的 分組集。其效果等效于在子查詢間構(gòu)建一個UNION ALL,子查詢帶有分組集作為它們的GROUP BY子句。

聚集函數(shù)(如果使用)會在組成每一個分組的所有行上進行計算,從而為每一個分組產(chǎn)生一個單獨的值(如果有聚集函數(shù)但是沒有 GROUP BY子句,則查詢會被當成是由所有選中行構(gòu)成的一個單一分組)。傳遞給每一個聚集函數(shù)的行集合可以通過在聚集函數(shù)調(diào)用附加一個FILTER子句來進一步過濾。當存在FILTER子句時,只有那些匹配它的行才會被包括在該聚集函數(shù)的輸入中。

當存在GROUP BY子句或者任何聚集函數(shù)時,SELECT列表表達式不能引用非分組列(除非它出現(xiàn)在聚集函數(shù)中或者它函數(shù)依賴于分組列),因為這樣做會導致返回非分組列的值時會有多種可能的值。如果分組列是包含非分組列的表的主鍵( 或者主鍵的子集),則存在函數(shù)依賴。

記住所有的聚集函數(shù)都是在HAVING子句或者 SELECT列表中的任何“標量”表達式之前被計算。 這意味著一個CASE表達式不能被用來跳過一個聚集表達式的計算。

當前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE不能與GROUP BY一起指定。

HAVING 子句

可選的HAVING子句的形式如下:

    HAVING condition

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

HAVING消除不滿足該條件的分組行。 HAVINGWHERE不同: WHERE會在應用GROUP BY之前過濾個體行,而HAVING過濾由 GROUP BY創(chuàng)建的分組行。 condition中引用的每一個列必須無歧義地引用一個分組列(除非該引用出現(xiàn)在一個聚集函數(shù)中或者該非分組列函數(shù)依賴于分組列。

即使沒有GROUP BY子句,HAVING 的存在也會把一個查詢轉(zhuǎn)變成一個分組查詢。這和查詢中包含聚集函數(shù)但沒有 GROUP BY子句時的情況相同。所有被選擇的行都被認為是一個單一分組,并且SELECT列表和 HAVING子句只能引用聚集函數(shù)中的表列。如果該 HAVING條件為真,這樣一個查詢將會發(fā)出一個單一行; 否則不返回行。

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

WINDOW 子句

可選的WINDOW子句的形式如下:

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

其中 window_name 是一個可以從OVER子句或者后續(xù)窗口定義中引用的名稱。 window_definition如下:

    [ existing_window_name ]
    [ PARTITION BY expression [, ...] ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
    [ frame_clause ]

如果指定了一個 existing_window_name, 它必須引用WINDOW列表中一個更早出現(xiàn)的項。新窗口將從該項中復制它的劃分子句以及排序子句(如果有)。在這種情況下,新窗口不能指定它自己的PARTITION BY子句,并且它只能在被復制窗口沒有ORDER BY的情況下指定該子句。新窗口總是使用自己的幀子句,被復制的窗口不必指定一個幀子句。

PARTITION BY列表元素的解釋以GROUP BY子句元素的方式進行,不過它們總是簡單表達式并且絕不能是輸出列的名稱或編號。另一個區(qū)別是這些表達式可以包含聚集函數(shù)調(diào)用,而這在常規(guī)GROUP BY 子句中是不被允許的。它們被允許的原因是窗口是出現(xiàn)在分組和聚集之后的。

類似地,ORDER BY列表元素的解釋也以語句級ORDER BY子句元素的方式進行, 不過該表達式總是被當做簡單表達式并且絕不會是輸出列的名稱或編號。

可選的 frame_clause為依賴幀的窗口函數(shù)定義窗口幀(并非所有窗口函數(shù)都依賴于幀)。窗口幀是查詢中每一樣(稱為當前行)的相關(guān)行的集合。 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的選擇在上面 of frame_start以及 frame_end 選項的列表中不能早于 frame_start的選擇 — 例如 RANGE BETWEEN CURRENT ROW ANDoffsetPRECEDING是不被允許的。

默認的幀選項是RANGE UNBOUNDED PRECEDING,它和 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW相同。它把幀設置為從分區(qū)開始直到當前行的最后一個平級行(被該窗口的ORDER BY子句認為等價于當前行的行,如果沒有ORDER BY則所有的行都是平級的)。通常, UNBOUNDED PRECEDING表示從分區(qū)第一行開始的幀,類似地 UNBOUNDED FOLLOWING表示以分區(qū)最后一行結(jié)束的幀,不論是處于RANGEROWS或者GROUPS模式中。在ROWS模式中, CURRENT ROW表示以當前行開始或者結(jié)束的幀。而在 RANGE或者GROUPS模式中它表示當前行在ORDER BY排序中的第一個或者最后一個平級行開始或者結(jié)束的幀。 offset PRECEDINGoffset FOLLOWING選項的含義會隨著幀模式而變化。在ROWS模式中, offset是一個整數(shù),表示幀開始或者結(jié)束于當前行之前或者之后的那么多行處。在GROUPS模式中, offset是一個整數(shù),表示真開始或者結(jié)束于當前行的平級組之前或者之后那么多個平級組處,其中平級組是一組根據(jù)窗口的ORDER BY子句等效的行。在RANGE模式中, offset選項的使用要求在窗口定義中正好有一個ORDER BY列。那么該幀包含的行的排序列值不超過 offset且小于(對于PRECEDING)或者大于(對于FOLLOWING)當前行的排序列值。在這些情況中, offset表達式的數(shù)據(jù)類型取決于排序列的數(shù)據(jù)類型。對于數(shù)字排序列,它通常與排序列是相同類型,但對于 datetime 類型的排序列它是interval。在所有這些情況中, offset的值必須是非空和非負。此外,雖然 offset并非必須是簡單常量,但它不能包含變量、聚集函數(shù)或者窗口函數(shù)。

frame_exclusion選項允許從幀中排除當前行周圍的行,即便根據(jù)幀的起始選項來說它們應該被包含在幀中。EXCLUDE CURRENT ROW把當前行從幀中排除。EXCLUDE GROUP把當前行和它在排序上的平級行從幀中排除。EXCLUDE TIES從幀中排除當前行的任何平級行,但是不排除當前行本身。EXCLUDE NO OTHERS只是明確地指定不排除當前行或其平級行的默認行為。

注意,如果ORDER BY排序無法把行唯一地排序,則ROWS模式可能產(chǎn)生不可預測的結(jié)果。RANGE以及GROUPS模式的目的是確保在ORDER BY順序中平等的行被同樣對待:一個給定平級組中的所有行將在一個幀中或者被從幀中排除。

WINDOW子句的目的是指定出現(xiàn)在查詢的 SELECT list 或 ORDER BY 子句中的 窗口函數(shù)的行為。這些函數(shù)可以在它們的 OVER子句中用名稱引用WINDOW 子句項。不過,WINDOW子句項不是必須被引用。 如果在查詢中沒有用到它,它會被簡單地忽略。可以使用根本沒有任何 WINDOW子句的窗口函數(shù),因為窗口函數(shù)調(diào)用可以直接在其OVER子句中指定它的窗口定義。不過,當多個窗口函數(shù)都需要相同的窗口定義時, WINDOW子句能夠減少輸入。

當前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE不能和 WINDOW一起被指定。

SELECT 列表

SELECT列表(位于關(guān)鍵詞 SELECTFROM之間)指定構(gòu)成 SELECT語句輸出行的表達式。這些表達式可以(并且通常確實會)引用FROM子句中計算得到的列。

正如在表中一樣,SELECT的每一個輸出列都有一個名稱。 在一個簡單的SELECT中,這個名稱只是被用來標記要顯示的列,但是當SELECT是一個大型查詢的一個子查詢時,大型查詢會把該名稱看做子查詢產(chǎn)生的虛表的列名。要指定用于輸出列的名稱,在該列的表達式后面寫上 AS output_name( 你可以省略AS,但只能在期望的輸出名稱不匹配任何 PolarDB 關(guān)鍵詞時省略。為了避免和未來增加的關(guān)鍵詞沖突, 推薦總是寫上AS或者用雙引號引用輸出名稱)。如果你不指定列名, PolarDB會自動選擇一個名稱。如果列的表達式是一個簡單的列引用,那么被選擇的名稱就和該列的名稱相同。在使用函數(shù)或者類型名稱的更復雜的情況中,系統(tǒng)可能會生成諸如 ?column?之類的名稱。

輸出列的名稱可以被用來在ORDER BY以及 GROUP BY子句中引用該列的值,但是不能用于 WHEREHAVING子句(在其中必須寫出表達式)。

可以在輸出列表中寫來取代表達式,它是被選中行的所有列的一種簡寫方式。還可以寫 table_name.,它是指來自那個表的所有列的簡寫形式。在這些情況中無法用 AS指定新的名稱,輸出行的名稱將和表列的名稱相同。

根據(jù) SQL 標準,輸出列表中的表達式應該在應用DISTINCTORDER BY或者LIMIT之前計算。在使用DISTINCT時顯然必須這樣做,否則就無法搞清到底在區(qū)分什么值。不過,在很多情況下如果先計算ORDER BYLIMIT再計算輸出表達式會很方便,特別是如果輸出列表中包含任何 volatile 函數(shù)或者代價昂貴的函數(shù)時尤其如此。通過這種行為,函數(shù)計算的順序更加直觀并且對于從未出現(xiàn)在輸出中的行將不會進行計算。只要輸出表達式?jīng)]有被DISTINCTORDER BY或者GROUP BY引用,PolarDB實際將在排序和限制行數(shù)之后計算輸出表達式(作為一個反例,SELECT f(x) FROM tab ORDER BY 1顯然必須在排序之前計算f(x))。包含有集合返回函數(shù)的輸出表達式實際是在排序之后和限制行數(shù)之前被計算,這樣LIMIT才能切斷來自集合返回函數(shù)的輸出。

DISTINCT 子句

如果指定了SELECT DISTINCT,所有重復的行會被從結(jié)果集中移除(為每一組重復的行保留一行)。SELECT ALL則指定相反的行為:所有行都會被保留,這也是默認情況。

SELECT DISTINCT ON (expression[, ...] ) 只保留在給定表達式上計算相等的行集合中的第一行。 DISTINCT ON表達式使用和 ORDER BY相同的規(guī)則(見上文)解釋。注意,除非用 ORDER BY來確保所期望的行出現(xiàn)在第一位,每一個集合的“第一行”是不可預測的。例如:

    SELECT DISTINCT ON (location) location, time, report
        FROM weather_reports
        ORDER BY location, time DESC;

為每個地點檢索最近的天氣報告。但是如果我們不使用 ORDER BY來強制對每個地點的時間值進行降序排序, 我們?yōu)槊總€地點得到的報告的時間可能是無法預測的。

DISTINCT ON表達式必須匹配最左邊的 ORDER BY表達式。ORDER BY子句通常將包含額外的表達式,這些額外的表達式用于決定在每一個 DISTINCT ON分組內(nèi)行的優(yōu)先級。

當前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE不能和 DISTINCT一起使用。

UNION 子句

UNION子句具有下面的形式:

    select_statement UNION [ ALL | DISTINCT ] select_statement

select_statement 是任何沒有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE子句的 SELECT語句(如果子表達式被包圍在圓括號內(nèi), ORDER BYLIMIT可以被附著到其上。如果沒有圓括號,這些子句將被應用到UNION的結(jié)果而不是右手邊的表達式上)。

UNION操作符計算所涉及的 SELECT語句所返回的行的并集。如果一行至少出現(xiàn)在兩個結(jié)果集中的一個內(nèi),它就會在并集中。作為 UNION兩個操作數(shù)的 SELECT語句必須產(chǎn)生相同數(shù)量的列并且對應位置上的列必須具有兼容的數(shù)據(jù)類型。

UNION的結(jié)果不會包含重復行,除非指定了 ALL選項。ALL會阻止消除重復(因此, UNION ALL通常顯著地快于UNION, 盡量使用ALL)。可以寫DISTINCT來顯式地指定消除重復行的行為。

除非用圓括號指定計算順序, 同一個SELECT語句中的多個 UNION操作符會從左至右計算。

當前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE不能用于UNION結(jié)果或者 UNION的任何輸出。

INTERSECT 子句

INTERSECT子句具有下面的形式:

select_statement INTERSECT [ ALL | DISTINCT ] select_statement

select_statement 是任何沒有ORDER BY, LIMITFOR NO KEY UPDATEFOR UPDATEFOR SHARE以及FOR KEY SHARE子句的 SELECT語句。

INTERSECT操作符計算所涉及的 SELECT語句返回的行的交集。如果一行同時出現(xiàn)在兩個結(jié)果集中,它就在交集中。

INTERSECT的結(jié)果不會包含重復行,除非指定了 ALL選項。如果有ALL,一個在左表中有 m次重復并且在右表中有 n 次重復的行將會在結(jié)果中出現(xiàn) min(m,n) 次。 DISTINCT可以寫DISTINCT來顯式地指定消除重復行的行為。

除非用圓括號指定計算順序, 同一個SELECT語句中的多個 INTERSECT操作符會從左至右計算。 INTERSECT的優(yōu)先級比 UNION更高。也就是說, A UNION B INTERSECT C將被讀成A UNION (B INTERSECT C)

當前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE不能用于INTERSECT結(jié)果或者 INTERSECT的任何輸出。

EXCEPT 子句

EXCEPT子句具有下面的形式:

select_statement EXCEPT [ ALL | DISTINCT ] select_statement

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

EXCEPT操作符計算位于左 SELECT語句的結(jié)果中但不在右 SELECT語句結(jié)果中的行集合。

EXCEPT的結(jié)果不會包含重復行,除非指定了 ALL選項。如果有ALL,一個在左表中有 m次重復并且在右表中有 n次重復的行將會在結(jié)果集中出現(xiàn) max(m-n,0) 次。 DISTINCT可以寫DISTINCT來顯式地指定消除重復行的行為。

除非用圓括號指定計算順序, 同一個SELECT語句中的多個 EXCEPT操作符會從左至右計算。 EXCEPT的優(yōu)先級與 UNION相同。

當前,FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE不能用于EXCEPT結(jié)果或者 EXCEPT的任何輸出。

ORDER BY 子句

可選的ORDER BY子句的形式如下:

ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]

ORDER BY子句導致結(jié)果行被按照指定的表達式排序。 如果兩行按照最左邊的表達式是相等的,則會根據(jù)下一個表達式比較它們, 依次類推。如果按照所有指定的表達式它們都是相等的,則它們被返回的順序取決于實現(xiàn)。

每個 expression 可以是輸出列(SELECT列表項)的名稱或序號,它也可以是由輸入列值構(gòu)成的任意表達式。

序號指的是輸出列的順序(從左至右)位置。這種特性可以為不具有唯一名稱的列定義一個順序。這不是絕對必要的,因為總是可以使用 AS子句為輸出列賦予一個名稱。

也可以在ORDER BY子句中使用任意表達式,包括沒有出現(xiàn)在SELECT輸出列表中的列。因此, 下面的語句是合法的:

SELECT name FROM distributors ORDER BY code;

這種特性的限制是應用在UNIONINTERSECTEXCEPT子句結(jié)果上的 ORDER BY只能指定輸出列名稱或序號,但不能指定表達式。

如果ORDER BY表達式既匹配輸出列名稱又匹配輸入列名稱的簡單名稱,ORDER BY將把它解讀成輸出列名稱。這與在同樣情況下GROUP BY會做出的選擇相反。這種不一致是為了與SQL標準兼容。

可以為ORDER BY子句中的任何表達式之后增加關(guān)鍵詞 ASC(上升)DESC(下降)。如果沒有指定, ASC被假定為默認值。或者,可以在USING 子句中指定一個特定的排序操作符名稱。一個排序操作符必須是某個B-樹操作符族的小于或者大于成員。ASC通常等價于 USING <DESC通常等價于 USING >(但是一種用戶定義數(shù)據(jù)類型的創(chuàng)建者可以準確地定義默認排序順序是什么,并且它可能會對應于其他名稱的操作符)。

如果指定NULLS LAST,空值會排在非空值之后;如果指定 NULLS FIRST,空值會排在非空值之前。如果都沒有指定, 在指定或者隱含ASC時的默認行為是NULLS LAST, 而指定或者隱含DESC時的默認行為是 NULLS FIRST(因此,默認行為是空值大于非空值)。 當指定USING時,默認的空值順序取決于該操作符是否為小于或者大于操作符。

注意順序選項只應用到它們所跟隨的表達式上。例如 ORDER BY x, y DESCORDER BY x DESC, y DESC是不同的。

字符串數(shù)據(jù)會被根據(jù)引用到被排序列上的排序規(guī)則排序。根據(jù)需要可以通過在 expression中包括一個 COLLATE子句來覆蓋,例如 ORDER BY mycolumn COLLATE "en_US"

LIMIT 子句

LIMIT子句由兩個獨立的子句構(gòu)成:

LIMIT { count | ALL }
OFFSET start

參數(shù) count指定要返回的最大行數(shù),而 start 指定在返回行之前要跳過的行數(shù)。在兩者都被指定時,在開始計算要返回的 count行之前會跳過 start行。

如果 count表達式計算為NULL,它會被當成LIMIT ALL,即沒有限制。如果 start計算為 NULL,它會被當作OFFSET 0

SQL:2008 引入了一種不同的語法來達到相同的結(jié)果, PolarDB也支持它:

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

在這種語法中,標準要求 startcount 是一個文本常量、一個參數(shù)或者一個變量名。而作為一種 PolarDB的擴展,還允許其他的表達式,但通常需要被封閉在圓括號中以避免歧義。如果在一個 FETCH子句中省略 count,它的默認值為 1。 WITH TIES選項用于根據(jù)ORDER BY子句返回與結(jié)果集中最后一個位置相關(guān)的任何附加行; ORDER BY在這種情況下是強制性的。 ROWROWS以及 FIRSTNEXT是噪聲,它們不影響這些子句的效果。根據(jù)標準,如果都存在,OFFSET子句必須出現(xiàn)在FETCH子句之前。但是 PolarDB更寬松,它允許兩種順序。

在使用LIMIT時,用一個ORDER BY子句把結(jié)果行約束到一個唯一順序是個好辦法。否則你講得到該查詢結(jié)果行的一個不可預測的子集 — 你可能要求從第10到第20行,但是在什么順序下的第10到第20,除非指定ORDER BY,否則是不知道順序的。

查詢規(guī)劃器在生成一個查詢計劃時會考慮LIMIT,因此根據(jù)你使用的LIMITOFFSET,你很可能得到不同的計劃(得到不同的行序)。所以,使用不同的 LIMIT/OFFSET值來選擇一個查詢結(jié)果的不同子集將會給出不一致的結(jié)果,除非用ORDER BY強制一種可預測的結(jié)果順序。這不是一個缺陷,它是 SQL 不承諾以任何特定順序(除非使用 ORDER BY來約束順序)給出一個查詢結(jié)果這一事實造成的必然后果。

如果沒有一個ORDER BY來強制選擇一個確定的子集, 重復執(zhí)行同樣的LIMIT查詢甚至可能會返回一個表中行的不同子集。同樣,這也不是一種缺陷,在這樣一種情況下也無法保證結(jié)果的確定性。

鎖定子句

FOR UPDATEFOR NO KEY UPDATEFOR SHAREFOR KEY SHARE鎖定子句,它們影響SELECT 把行從表中取得時如何對它們加鎖。

鎖定子句的一般形式:

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

其中 lock_strength可以是:

UPDATE
NO KEY UPDATE
SHARE
KEY SHARE

為了防止該操作等待其他事務提交,可使用NOWAIT或者 SKIP LOCKED選項。使用NOWAIT時, 如果選中的行不能被立即鎖定,該語句會報告錯誤而不是等待。使用 SKIP LOCKED時,無法被立即鎖定的任何選中行都會被跳過。跳過已鎖定行會提供數(shù)據(jù)的一個不一致的視圖,因此這不適合于一般目的的工作,但是可以被用來避免多個用戶訪問一個類似隊列的表時出現(xiàn)鎖競爭。注意NOWAITSKIP LOCKED只適合行級鎖—所要求的 ROW SHARE表級鎖仍然會以常規(guī)的方式取得。如果想要不等待的表級鎖,你可以先使用帶NOWAIT的LOCK。

如果在一個鎖定子句中提到了特定的表,則只有來自于那些表的行會被鎖定,任何SELECT中用到的其他表還是被簡單地照常讀取。一個沒有表列表的鎖定子句會影響該語句中用到的所有表。如果一個鎖定子句被應用到一個視圖或者子查詢,它會影響在該視圖或子查詢中用到的所有表。不過,這些子句不適用于主查詢引用的WITH查詢。如果你希望在一個WITH查詢中發(fā)生行鎖定,應該在該 WITH查詢內(nèi)指定一個鎖定子句。

如果有必要對不同的表指定不同的鎖定行為,可以寫多個鎖定子句。 如果同一個表在多于一個鎖定子句中被提到(或者被隱式的影響到), 那么會按照所指定的最強的鎖定行為來處理它。類似地,如果在任何影響一個表的子句中指定了NOWAIT,就會按照 NOWAIT的行為來處理該表。否則如果 SKIP LOCKED在任何影響該表的子句中被指定, 該表就會被按照SKIP LOCKED來處理。

如果被返回的行無法清晰地與表中的行保持一致,則不能使用鎖定子句。 例如鎖定子句不能與聚集一起使用。

當鎖定子句出現(xiàn)在SELECT查詢的頂層時, 被鎖定的行正好就是該查詢返回的行。在連接查詢的情況下,被鎖定的行是那些對返回的連接行有貢獻的行。此外,自該查詢的快照起滿足查詢條件的行將被鎖定,如果它們在該快照后被更新并且不再滿足查詢條件,它們將不會被返回。如果使用了LIMIT,只要已經(jīng)返回的行數(shù)滿足了限制,鎖定就會停止(但注意被 OFFSET跳過的行將被鎖定)。類似地,如果在游標的查詢中使用鎖定子句,只有被該游標實際取出或者跳過的行才將被鎖定。

當鎖定子句出現(xiàn)在子-SELECT中時,被鎖定行是那些該子查詢返回給外層查詢的行。這些被鎖定的行的數(shù)量可能比從子查詢自身的角度看到的要少,因為來自外層查詢的條件可能會被用來優(yōu)化子查詢的執(zhí)行。例如:

SELECT _ FROM (SELECT _ FROM mytable FOR UPDATE) ss WHERE col1 = 5;

將只鎖定具有col1 = 5的行(雖然在子查詢中并沒有寫上該條件)。

早前的發(fā)行無法維持一個被之后的保存點升級的鎖。例如,這段代碼:

BEGIN;
SELECT \* FROM mytable WHERE key = 1 FOR UPDATE;
SAVEPOINT s;
UPDATE mytable SET ... WHERE key = 1;
ROLLBACK TO s;

ROLLBACK TO之后將無法維持 FOR UPDATE鎖。

警告

運行在READ COMMITTED事務隔離級別并且使用ORDER BY和鎖定子句的SELECT命令有可能返回無序的行。 這是因為ORDER BY會被首先應用。該命令對結(jié)果排序,但是可能接著在嘗試獲得一個或者多個行上的鎖時阻塞。一旦SELECT解除阻塞,某些排序列值可能已經(jīng)被修改,從而導致那些行變成無序的(盡管它們根據(jù)原始列值是有序的)。根據(jù)需要,可以通過在子查詢中放置 FOR UPDATE/SHARE來解決之一問題,例如

SELECT _ FROM (SELECT _ FROM mytable FOR UPDATE) ss ORDER BY column1;

注意這將導致鎖定mytable的所有行,而頂層的 FOR UPDATE只會鎖定實際被返回的行。這可能會導致顯著的性能差異,特別是把ORDER BYLIMIT或者其他限制組合使用時。因此只有在并發(fā)更新排序列并且要求嚴格的排序結(jié)果時才推薦使用這種技術(shù)。

REPEATABLE READ或者SERIALIZABLE 事務隔離級別上這可能導致一個序列化失敗(SQLSTATE'40001'),因此在這些隔離級別下不可能收到無序行。

TABLE 命令

命令如下:

TABLE name

等價于:

SELECT \* FROM name

它可以被用作一個頂層命令,或者用在復雜查詢中以節(jié)省空間。只有 WITHUNIONINTERSECTEXCEPTORDER BYLIMITOFFSETFETCH以及FOR鎖定子句可以用于 TABLE。不能使用WHERE子句和任何形式的聚集。

示例

將表films與表 distributors連接:

    SELECT f.title, f.did, d.name, f.date_prod, f.kind
        FROM distributors d, films f
        WHERE f.did = d.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對結(jié)果分組:

    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列求和、對結(jié)果按照 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

下面兩個例子都是根據(jù)第二列(name)的內(nèi)容來排序結(jié)果:

    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的并集,把結(jié)果限制為那些在每個表中以字母W開始的行。只想要可區(qū)分的行,因此省略了關(guān)鍵詞 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子句中使用函數(shù), 分別使用和不使用列定義列表:

    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

這里是帶有增加的序數(shù)列的函數(shù)的例子:

    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的所有下屬(直接的或者間接的)以及他們的間接層數(shù):

    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,然后是查詢的遞歸部分。要確保查詢的遞歸部分最終將不返回任何行,否則該查詢將無限循環(huán)。

這個例子使用LATERALmanufacturers 表的每一行應用一個集合返回函數(shù)get_product_names()

    SELECT m.name AS mname, pname
    FROM manufacturers m, LATERAL get_product_names(m.id) pname;

當前沒有任何產(chǎn)品的制造商不會出現(xiàn)在結(jié)果中,因為這是一個內(nèi)連接。 如果我們希望把這類制造商的名稱包括在結(jié)果中,我們可以執(zhí)行以下命令:

    SELECT m.name AS mname, pname
    FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true;

兼容性

當然,SELECT語句是兼容SQL標準的。 但是也有一些擴展和缺失的特性。

省略的FROM子句

PolarDB允許省略 FROM子句。一種簡單的使用是計算簡單表達式的結(jié)果:

    SELECT 2+2;

     ?column?
    ----------
            4

某些其他 SQL 數(shù)據(jù)庫需要引入一個假的單行表放在該SELECTFROM子句中才能做到這一點。

說明

如果沒有指定一個FROM子句,該查詢就不能引用任何數(shù)據(jù)庫表。例如,下面的查詢是非法的:

    SELECT distributors.* WHERE distributors.name = 'Westward';

空SELECT列表

SELECT之后的輸出表達式列表可以為空, 這會產(chǎn)生一個零列的結(jié)果表。對SQL標準來說這不是合法的語法。PolarDB允許它是為了與允許零列表保持一致。不過在使用 DISTINCT時不允許空列表。

省略AS關(guān)鍵詞

在SQL標準中,只要新列名是一個合法的列名(就是說與任何保留關(guān)鍵詞不同), 就可以省略輸出列名之前的可選關(guān)鍵詞AS。 PolarDB要稍微嚴格些:只要新列名匹配任何關(guān)鍵詞(保留或者非保留)就需要AS。推薦的習慣是使用 AS或者帶雙引號的輸出列名來防止與未來增加的關(guān)鍵詞可能的沖突。

FROM項中,標準和PolarDB都允許省略非保留關(guān)鍵詞別名之前的AS。但是由于語法的歧義,這無法用于輸出列名。

ONLY和繼承

在書寫ONLY時,SQL標準要求在表名周圍加上圓括號,例如 SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...。PolarDB認為這些圓括號是可選的。

PolarDB允許寫一個拖尾的來顯式指定包括子表的非-ONLY行為。而標準則不允許這樣。

(這些點同等地適用于所有支持ONLY選項的 SQL 命令)。

TABLESAMPLE子句限制

當前只在常規(guī)表和物化視圖上接受TABLESAMPLE子句。 根據(jù)SQL標準,應該可以把它應用于任何FROM項。

FROM中的函數(shù)調(diào)用

PolarDB允許一個函數(shù)調(diào)用被直接寫作 FROM列表的一個成員。在SQL標準中,有必要把這樣一個函數(shù)調(diào)用包裹在一個子-SELECT中。也就是說,語法 FROMfunc(...)alias 近似等價于 FROM LATERAL (SELECTfunc(...))alias。 注意該LATERAL被認為是隱式的,這是因為標準對于 FROM中的一個UNNEST()項要求 LATERAL語義。PolarDB會把 UNNEST()和其他集合返回函數(shù)同樣對待。

GROUP BY和ORDER BY可用的名字空間

在SQL-92標準中,一個ORDER BY子句只能使用輸出列名或者序號,而一個GROUP BY子句只能使用基于輸入列名的表達式。PolarDB擴展了這兩種子句以允許它們使用其他的選擇(但如果有歧義時還是使用標準的解釋)。PolarDB也允許兩種子句指定任意表達式。注意出現(xiàn)在一個表達式中的名稱將總是被當做輸入列名而不是輸出列名。

SQL:1999及其后的標準使用了一種略微不同的定義,它并不完全向后兼容SQL-92。不過,在大部分的情況下, PolarDB會以與 SQL:1999 相同的方式解釋ORDER BYGROUP BY表達式。

函數(shù)依賴

只有當一個表的主鍵被包括在GROUP BY列表中時, PolarDB才識別函數(shù)依賴(允許從GROUP BY中省略列)。SQL 標準指定了應該要識別的額外情況。

FOR NO KEY UPDATE、FOR UPDATE、FOR SHARE、FOR KEY SHARE

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

WITH中的數(shù)據(jù)修改語句

PolarDB允許將INSERTUPDATE以及DELETE用作WITH 查詢。

非標準子句

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

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

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