<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 7.2\. 表表達式 _表表達式_計算一個表,它包含一個`FROM`子句, 該子句可以根據需要選用`WHERE`, `GROUP BY`,`HAVING` 子句。大部分表表達式只是指向磁盤上的一個所謂的基本表, 但是我們可以用更復雜的表達式以各種方法修改或組合基本表。 表表達式里的`WHERE`, `GROUP BY`, `HAVING` 子句聲明一系列對源自`FROM`子句的表的轉換操作。 所有這些轉換最后生成一個虛擬表,傳遞給選擇列表計算輸出行。 ## 7.2.1\. `FROM` 子句 [_FROM_ 子句](#calibre_link-516) 從一個逗號分隔的表引用列表中生成一個虛擬表。 ``` FROM _table_reference_ [, `_table_reference_` [, ...]] ``` 表引用可以是一個表名字(可能有模式修飾)或者是一個生成的表, 比如子查詢、表連接、或這些東西的復雜組合。如果在`FROM`子句中列出了多于一個表, 那么它們交叉連接(見下文)形成一個派生表,該表可以進行`WHERE`, `GROUP BY`, `HAVING`子句的轉換處理,并最后生成表表達式的結果。 如果一個表引用是一個簡單的父表的名字,那么將包括其所有后代子表的行, 除非你在該表名字前面加`ONLY`關鍵字(這樣任何子表都會被忽略)。 除了在表名字前面加`ONLY`,你可以在表名字后面寫`*` 明確指定包括后代表。寫`*`不是必須的,因為這個行為是默認的 (除非你已經改變了[sql_inheritance](#calibre_link-2218)配置選項里面的設置)。 然而寫`*`可能對于強調搜索額外的表是有用的。 ### 7.2.1.1\. 連接表 一個連接表是根據特定的連接規則從兩個其它表(真實表或生成表)中派生的表。 我們支持內連接、外連接、交叉連接。 **連接類型** 交叉連接 ``` _T1_ CROSS JOIN _T2_ ``` 對每個來自`_T1_`和`_T2_` 的行進行組合(也就是,一個笛卡爾積),連接成的表將包含這樣的行: 所有`_T1_`里面的字段后面跟著所有`_T2_` 里面的字段。如果兩表分別有 N 和 M 行,連接成的表將有 N*M 行。 `FROM` `_T1_` CROSS JOIN `_T2_` 等效于`FROM` `_T1_`,`_T2_`。 它還等效于`FROM` `_T1_` INNER JOIN `_T2_` ON TRUE(見下文)。 條件連接 ``` _T1_ { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN _T2_ ON _boolean_expression_ _T1_ { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN _T2_ USING ( _join column list_ ) _T1_ NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN _T2_ ``` `INNER`和`OUTER`對所有連接類型都是可選的。 `INNER`為缺省。`LEFT`, `RIGHT`, 和`FULL`隱含外連接。 _連接條件_在`ON`或`USING`子句里聲明, 或者用關鍵字`NATURAL`隱含地聲明。 連接條件判斷來自兩個源表中的那些行是"匹配"的,這些我們將在下面詳細解釋。 `ON`子句是最常見的連接條件的類型:它接收一個和`WHERE` 子句相同的布爾表達式。如果兩個分別來自`_T1_`和`_T2_` 的行在`ON`表達式上運算的結果為真,那么它們就算是匹配的行。 `USING`是一個連接條件的縮寫語法:它接收一個用逗號分隔的字段名列表, 這些字段必須是連接表共有的并且其值必須相同。最后,`JOIN USING` 會將每一對相等的輸入字段輸出為一個字段,其后跟著所有其它字段。 因此,`USING (a, b, c)` 等效于`ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)` 只不過是如果使用了`ON`,那么在結果里`a`, `b`和`c` 字段都會有兩個,而用`USING`的時候就只會有一個(如果使用了`SELECT *` 的話,他們會優先發生)。 最后,`NATURAL`是`USING`的縮寫形式: 它自動形成一個由兩個表中同名的字段組成的`USING`列表(同名字段只出現一次)。 如果沒有同名的字段,`NATURAL`的行為會像`CROSS JOIN`。 條件連接可能的類型是: `INNER JOIN` 內連接。對于 T1 中的每一行 R1 ,如果能在 T2 中找到一個或多個滿足連接條件的行, 那么這些滿足條件的每一行都在連接表中生成一行。 `LEFT OUTER JOIN` 左外連接。首先執行一次內連接。然后為每一個 T1 中無法在 T2 中找到匹配的行生成一行, 該行中對應 T2 的列用 NULL 補齊。因此,生成的連接表里總是包含來自 T1 里的每一行至少一個副本。 `RIGHT OUTER JOIN` 右外連接。首先執行一次內連接。然后為每一個 T2 中無法在 T1 中找到匹配的行生成一行, 該行中對應 T1 的列用 NULL 補齊。因此,生成的連接表里總是包含來自 T2 里的每一行至少一個副本。 `FULL OUTER JOIN` 全連接。首先執行一次內連接。然后為每一個 T1 與 T2 中找不到匹配的行生成一行, 該行中無法匹配的列用 NULL 補齊。因此,生成的連接表里無條件地包含 T1 和 T2 里的每一行至少一個副本。 如果`_T1_`和`_T2_` 之一或全部是可以連接的表,那么所有類型的連接都可以串連或嵌套在一起。 你可以在`JOIN`子句周圍使用圓括弧來控制連接順序,如果沒有圓括弧, 那么`JOIN`子句從左向右嵌套。 為了解釋這些問題,假設我們有一個表`t1`: ``` num | name -----+------ 1 | a 2 | b 3 | c ``` 和`t2`: ``` num | value -----+------- 1 | xxx 3 | yyy 5 | zzz ``` 然后我們用不同的連接方式可以獲得各種結果: ``` <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 CROSS JOIN t2;</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 1 | a | 3 | yyy 1 | a | 5 | zzz 2 | b | 1 | xxx 2 | b | 3 | yyy 2 | b | 5 | zzz 3 | c | 1 | xxx 3 | c | 3 | yyy 3 | c | 5 | zzz (9 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 3 | c | 3 | yyy (2 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 INNER JOIN t2 USING (num);</kbd> num | name | value -----+------+------- 1 | a | xxx 3 | c | yyy (2 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 NATURAL INNER JOIN t2;</kbd> num | name | value -----+------+------- 1 | a | xxx 3 | c | yyy (2 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | 3 | yyy (3 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 LEFT JOIN t2 USING (num);</kbd> num | name | value -----+------+------- 1 | a | xxx 2 | b | 3 | c | yyy (3 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 3 | c | 3 | yyy | | 5 | zzz (3 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | 3 | yyy | | 5 | zzz (4 rows) ``` 用`ON`聲明的連接條件也可以包含與連接不直接相關的條件。 這種功能可能對某些查詢很有用,但是需要我們仔細想清楚。比如: ``` <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | | (3 rows) ``` 請注意,將限制放在在`WHERE`子句中將會產生不同的結果: ``` <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num WHERE t2.value = 'xxx';</kbd> num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx (1 row) ``` 這是因為限制放在`ON`子句中時是_先于_連接處理的, 而限制放在`WHERE`子句中時是_后于_連接處理的。 ### 7.2.1.2\. 表和列別名 你可以給表或復雜的表引用起一個臨時的_表別名_,以便被其余的查詢引用。 要創建一個表別名,可以這樣: ``` FROM _table_reference_ AS _alias_ ``` 或: ``` FROM _table_reference_ _alias_ ``` `AS`關鍵字沒啥特別的含義。`_alias_`可以是任意標識符。 表別名的典型應用是給長表名賦予比較短的標識,好讓連接子句更易讀一些。比如: ``` SELECT * FROM some_very_long_table_name s JOIN another_fairly_long_name a ON s.id = a.num; ``` 取了別名之后就不允許再用最初的名字了。因此,這是不合法的: ``` SELECT * FROM my_table AS m WHERE my_table.a > 5; -- wrong ``` 表別名主要是為了方便標記,但對于自連接卻是必須的。比如: ``` SELECT * FROM people AS mother JOIN people AS child ON mother.id = child.mother_id; ``` 另外,要引用子查詢的結果也必須使用別名(參見[Section 7.2.1.3](#calibre_link-1849))。 圓括弧用于解決歧義。下面的第一個語句把別名`b`賦予第二個`my_table`表; 而第二個語句則把別名`b`賦予了連接的結果。 ``` SELECT * FROM my_table AS a CROSS JOIN my_table AS b ... SELECT * FROM (my_table AS a CROSS JOIN my_table) AS b ... ``` 另外一種形式的表別名除了給表賦予別名外,還給該表的字段也賦予了別名: ``` FROM _table_reference_ [AS] _alias_ ( _column1_ [, `_column2_` [, ...]] ) ``` 如果聲明的字段別名比表里實際的字段少,那么后面的字段就沒有別名。 這個語法對于自連接或子查詢特別有用。 如果用這些形式中的任何一種給一個`JOIN`子句的輸出結果附加了一個別名, 那么該別名就在`JOIN`里隱藏了其原始的名字。比如: ``` SELECT a.* FROM my_table AS a JOIN your_table AS b ON ... ``` 是合法 SQL ,但是: ``` SELECT a.* FROM (my_table AS a JOIN your_table AS b ON ...) AS c ``` 是不合法的:別名`a`在別名`c`的外面是看不到的。 ### 7.2.1.3\. 子查詢 子查詢的結果(派生表)_必須_包圍在圓括弧里并且必須賦予一個別名(參閱 [Section 7.2.1.2](#calibre_link-488))。比如: ``` FROM (SELECT * FROM table1) AS alias_name ``` 這個例子等效于`FROM table1 AS alias_name`。 更有趣的例子是在子查詢里面有分組或聚集的時候, 這個時候子查詢不能歸納成一個簡單的連接。 子查詢也可以是一個`VALUES`列表: ``` FROM (VALUES ('anne', 'smith'), ('bob', 'jones'), ('joe', 'blow')) AS names(first, last) ``` 這種情況同樣也必須要取一個別名。還可以為`VALUES`列表中的字段取別名, 并且被認為是一個好習慣。更多信息參見[Section 7.7](#calibre_link-616)。 ### 7.2.1.4\. 表函數 表函數是那些生成一個行集合的函數,這個集合可以是由基本數據類型(標量類型)組成, 也可以是由復合數據類型(表的行)組成。他們的用法類似一個表、視圖、或 `FROM` 子句里的子查詢。表函數返回的字段可以像一個表、視圖、或者子查詢字段那樣包含在 `SELECT`,`JOIN`,`WHERE`子句里。 如果表函數返回基本數據類型,那么單一結果字段的名字匹配函數名。 如果表函數返回復合數據類型,那么多個結果字段的名字和該類型的每個屬性的名字相同。 可以在`FROM`子句中為表函數取一個別名,也可以不取別名。 如果一個函數在`FROM`子句中沒有別名,那么將使用函數名作為結果表的名字。 一些例子: ``` CREATE TABLE foo (fooid int, foosubid int, fooname text); CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$ SELECT * FROM foo WHERE fooid = $1; $$ LANGUAGE SQL; SELECT * FROM getfoo(1) AS t1; SELECT * FROM foo WHERE foosubid IN ( SELECT foosubid FROM getfoo(foo.fooid) z WHERE z.fooid = foo.fooid ); CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1); SELECT * FROM vw_getfoo; ``` 有時侯,把一個函數定義成根據不同的調用方法可以返回不同的字段是很有用的。 為了支持這個,表函數可以聲明為返回偽類型`record`。如果在查詢里使用這樣的函數, 那么我們必須在查詢中聲明預期的行結構,這樣系統才知道如何分析和規劃該查詢。 讓我們看看下面的例子: ``` SELECT * FROM dblink('dbname=mydb', 'SELECT proname, prosrc FROM pg_proc') AS t1(proname name, prosrc text) WHERE proname LIKE 'bytea%'; ``` [dblink](#calibre_link-478)函數([dblink](#calibre_link-63)模塊的一部分) 執行一個遠程的查詢。它聲明為返回`record`,因為它可能會被用于任何類型的查詢。 實際的字段集必須在調用它的查詢中聲明,這樣分析器才知道類似`*` 這樣的東西應該擴展成什么樣子。 ### 7.2.1.5\. `LATERAL` 子查詢 `FROM`子句中出現的子查詢可以放在關鍵字`LATERAL`之前。 這樣就允許它們引用通過前置`FROM`條目提供的字段。(如果沒有`LATERAL`, 那么每個子查詢都被認為是獨立的并且不能交叉引用任何其他的`FROM`條目。) `FROM`中出現的表函數也可以出現在關鍵字`LATERAL`之前, 但是對于函數來說,這個關鍵字是可選的;函數的參數在任何情況下都可以包含通過前置`FROM` 條目提供的字段。 `LATERAL`條目可以出現在`FROM`列表的頂級,或者在`JOIN`樹中。 在后者的情況下,它在`JOIN`右側時也可以參考左側的條目。 當`FROM`包含`LATERAL`交叉引用時,評估收益如下: `FROM`條目的每行或多個`FROM`條目的行組提供交叉引用的字段, `LATERAL`條目被評估為使用行或行組的字段值。結果行像平常一樣加入他們的計算行。 這些來自字段原表中的行或行組就這樣重復。 一個`LATERAL`常見的例子是: ``` SELECT * FROM foo, LATERAL (SELECT * FROM bar WHERE bar.id = foo.bar_id) ss; ``` 這并不是特別有用的,因為它的結果正好和更傳統做法的相同。 ``` SELECT * FROM foo, bar WHERE bar.id = foo.bar_id; ``` `LATERAL`當交叉引用字段對于加入的計算行是重要的時是主要有用的。 一個常見的應用是為一個set-returning函數提供一個參數值。例如,假設`vertices(polygon)` 返回一個多邊形的頂點坐標,我們可以識別出多邊形的頂點距離近的存儲在一個表中: ``` SELECT p1.id, p2.id, v1, v2 FROM polygons p1, polygons p2, LATERAL vertices(p1.poly) v1, LATERAL vertices(p2.poly) v2 WHERE (v1 <-> v2) < 10 AND p1.id != p2.id; ``` 這條語句也可以寫成: ``` SELECT p1.id, p2.id, v1, v2 FROM polygons p1 CROSS JOIN LATERAL vertices(p1.poly) v1, polygons p2 CROSS JOIN LATERAL vertices(p2.poly) v2 WHERE (v1 <-> v2) < 10 AND p1.id != p2.id; ``` 或者幾個其他等價的形式。(就像之前提到的,`LATERAL`關鍵字在這個例子中不是必須的, 但是我們為了明確而是用它。) `LEFT JOIN`對于`LATERAL`子查詢來說往往是特別有用的, 所以即使`LATERAL`子查詢不產生行,源行也將出現在結果中。例如, 如果`get_product_names()`返回一個制造商制造的產品名字, 但是一些在我們表中的制造商當前沒有生產任何產品,我們可以像下面這樣找出這些制造商: ``` SELECT m.name FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true WHERE pname IS NULL; ``` ## 7.2.2\. `WHERE`子句 [_WHERE_ 子句](#calibre_link-1321)子句的語法是: ``` WHERE _search_condition_ ``` 這里的`_search_condition_`是一個返回類型為 `boolean` 的值表達式(參閱[Section 4.2](#calibre_link-487))。 在完成對`FROM`子句的處理之后,生成的每一行都會按照搜索條件進行檢查。 如果結果是真,那么該行保留在輸出表中,否則(也就是結果是假或NULL)就把它拋棄。 搜索條件通常至少要引用一列在`FROM`子句里生成的列,這不是必須的, 但如果不這樣的話,`WHERE`子句就沒什么意義了。 > **Note:** 內連接的連接條件既可以寫在`WHERE`子句里也可以寫在`JOIN`子句里。 比如,下面的表表達式是等效的: > > ``` > FROM a, b WHERE a.id = b.id AND b.val &gt; 5 > ``` > > 和: > > ``` > FROM a INNER JOIN b ON (a.id = b.id) WHERE b.val &gt; 5 > ``` > > 或者可能還有: > > ``` > FROM a NATURAL JOIN b WHERE b.val &gt; 5 > ``` > > 你想用哪個只是風格問題。`FROM`子句里的`JOIN` 語法可能不那么容易移植到其它產品中。即使它是在SQL標準。對于外連接而言, 我們沒有選擇:連接條件必須在`FROM`子句中完成。 外連接的`ON`或`USING`子句_不_等于`WHERE`條件, 因為它導致最終結果中行的增(那些不匹配的輸入行)和刪。 這里是一些`WHERE`子句的例子: ``` SELECT ... FROM fdt WHERE c1 > 5 SELECT ... FROM fdt WHERE c1 IN (1, 2, 3) SELECT ... FROM fdt WHERE c1 IN (SELECT c1 FROM t2) SELECT ... FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) SELECT ... FROM fdt WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100 SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1) ``` 在上面的例子里,`fdt`是從`FROM`子句中派生的表。 那些不符合`WHERE`子句的搜索條件的行將從`fdt`中刪除。 請注意我們把標量子查詢當做一個值表達式來用。就像其它查詢一樣, 子查詢里也可以使用復雜的表表達式。同時還請注意子查詢 是如何引用`fdt`的。把`c1`修飾成`fdt.c1` 只有在`c1`是該子查詢生成的列名字時才是必須的, 但修飾列名字可以增加語句的準確性(即使有時不是必須的)。 這個例子就演示了字段名字范圍如何從外層查詢擴展到它的內層查詢。 ## 7.2.3\. `GROUP BY`和`HAVING`子句 在通過了`WHERE`過濾器之后,生成的輸入表可以繼續用`GROUP BY` 子句進行分組,然后用`HAVING`子句選取一些分組行。 ``` SELECT _select_list_ FROM ... [WHERE ...] GROUP BY _grouping_column_reference_ [, `_grouping_column_reference_`]... ``` [_GROUP BY_ 子句](#calibre_link-1322)子句用于把那些所有列出的 grouping_column_reference值都相同的行聚集在一起,縮減為一行, 這樣就可以刪除輸出里的重復和/或計算應用于這些組的聚集。這些字段的列出順序無關緊要。 比如: ``` <samp class="literal">=></samp> <kbd class="literal">SELECT * FROM test1;</kbd> x | y ---+--- a | 3 c | 2 b | 5 a | 1 (4 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT x FROM test1 GROUP BY x;</kbd> x --- a b c (3 rows) ``` 在第二個查詢里,我們不能寫成`SELECT * FROM test1 GROUP BY x`, 因為字段`y`里沒有哪個值可以和每個組關聯起來。 被分組的字段可以在選擇列表中引用是因為它們每個組都有單一的數值。 通常,如果一個表被分了組,不在`GROUP BY`中列出的字段只能在總表達式中被引用。 一個帶聚集表達式的例子是: ``` <samp class="literal">=></samp> <kbd class="literal">SELECT x, sum(y) FROM test1 GROUP BY x;</kbd> x | sum ---+----- a | 4 b | 5 c | 2 (3 rows) ``` 這里的`sum`是一個聚集函數,它在組上計算總和。 有關可用的聚集函數的更多信息可以在[Section 9.20](#calibre_link-1641)中找到。 > **Tip:** 沒有有效的聚合表達式分組可以計算一列中不同值的設置。 這個可以通過`DISTINCT`子句來實現(參考[Section 7.3.3](#calibre_link-1812)). 這里是另外一個例子:它計算每種產品的總銷售額(而不是所有產品的總銷售額)。 ``` SELECT product_id, p.name, (sum(s.units) * p.price) AS sales FROM products p LEFT JOIN sales s USING (product_id) GROUP BY product_id, p.name, p.price; ``` 在這個例子里,字段`product_id`,`p.name` 和`p.price`必須在`GROUP BY`子句里, 因為它們都在查詢選擇列表里被引用了(但見下文)。`s.units`字段不必在 `GROUP BY`列表里,因為它只是在一個聚集表達式(`sum(...)`)里使用, 它代表一組產品的銷售總額。對于每種產品,這個查詢都返回一個該產品的總銷售額。 如果產品表是這樣設置的,就說`product_id`是主鍵, 那么它足夠在上面的例子中對`product_id`分組, 因為名字和價格將會_函數依賴_于產品ID, 這樣將不會在返回每個產品ID組時有名字和價格的分歧。 在嚴格的SQL里,`GROUP BY`只能對源表的列進行分組,但PostgreSQL 把這個擴展為也允許`GROUP BY`對選擇列表中的字段進行分組。 也允許對值表達式進行分組,而不僅僅是簡單的字段。 如果一個表已經用`GROUP BY`分了組, 然后你又只對其中的某些組感興趣,那么就可以用`HAVING`子句篩選分組。 必須像`WHERE`子句,從結果中消除組,語法是: ``` SELECT _select_list_ FROM ... [WHERE ...] GROUP BY ... HAVING _boolean_expression_ ``` 在`HAVING`子句中的表達式可以引用分組的表達式和未分組的表達式 (后者必須涉及一個聚集函數)。 例子: ``` <samp class="literal">=></samp> <kbd class="literal">SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;</kbd> x | sum ---+----- a | 4 b | 5 (2 rows) <samp class="literal">=></samp> <kbd class="literal">SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';</kbd> x | sum ---+----- a | 4 b | 5 (2 rows) ``` 然后是一個更現實的例子: ``` SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING sum(p.price * s.units) > 5000; ``` 在上面的例子里,`WHERE`子句根據未分組的字段選擇數據行 (表達式只是對那些最近四周發生的銷售為真)。而`HAVING` 子句在分組之后選擇那些銷售總額超過5000的組。 請注意聚集表達式不需要在查詢中的所有地方都一樣。 如果一個查詢調用了聚合函數,但沒有`GROUP BY`子句,分組仍然發生: 結果是單一組行(或者如果單一行被`HAVING`所淘汰,那么也許沒有行)。 同樣,它包含一個`HAVING`子句,甚至沒有任何聚合函數的調用或`GROUP BY`子句。 ## 7.2.4\. 窗口函數處理 如果查詢包含窗口函數(參考[Section 3.5](#calibre_link-1330),[Section 9.21](#calibre_link-1804) 和[Section 4.2.8](#calibre_link-1331)),這些函數在執行了分組、聚合和`HAVING` 過濾之后被評估。也就是說,如果查詢使用任何的聚合、`GROUP BY`或`HAVING`, 那么由窗口函數發現的行是該組行而不是從`FROM`/`WHERE`得到的原始表行。 當多個窗口函數被使用的時候,所有在它們的窗口定義里依照語法地等效于 `PARTITION BY`和`ORDER BY`子句的窗口函數保證在同一個過去的數據里被評估。 因此它們將看到同樣的排序, 即使`ORDER BY`不唯一確定一個排序。然而,不確保所做出的關于評價的功能有不同的 `PARTITION BY`或`ORDER BY`規范。(在這種情況下, 一個排序步驟通常需要在窗口函數評估之間傳遞,并且不保證行的排序看似跟`ORDER BY`等效。) 目前,窗口函數總是需要分類數據,所以查詢輸出將按照一個或另一個窗口函數的 `PARTITION BY`/`ORDER BY`子句。它不是說依賴于此。 如果你想要確保結果是按特定的方式分類那么使用顯式的頂級ORDER BY子句。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看