SELECT

名前

SELECT -- テーブルもしくはビューからの行の検索

概要

SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    * | expression [ AS output_name ] [, ...]
    [ FROM from_item [, ...] ]
    [ WHERE condition ]
    [ GROUP BY expression [, ...] ]
    [ HAVING condition [, ...] ]
    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]
    [ LIMIT { count | ALL } ]
    [ OFFSET start ]
    [ FOR UPDATE [ OF table_name [, ...] ] ]

ここで from_item は以下のいずれかです。

    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
    ( select ) [ AS ] alias [ ( column_alias [, ...] ) ]
    function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]
    function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
    from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]

説明

SELECTは1つ以上のテーブルから行を返します。 SELECT の一般的な処理は以下の通りです。

  1. FROM リストにある全要素が計算されます。 (FROM リストの各要素は実テーブルか仮想テーブルです。) FROM リストに複数の要素が指定された場合、それらはクロス結合されます。 (後述の FROM を参照してください。)

  2. WHERE 句が指定された場合、条件を満たさない行はすべて出力から取り除かれます。 (後述のWHERE を参照してください。)

  3. GROUP BY 句が指定された場合、出力は、1つ以上の値に一致する行のグループに分割されます。 HAVING 句が指定された場合、指定した条件を満たさないグループは取り除かれます。 (後述の GROUP BYHAVING を参照してください。)

  4. UNIONINTERSECT、および、EXCEPT 演算子を使用すると、複数のSELECT文の出力を1つの結果集合にまとめることができます。 UNION 演算子は、両方あるいは片方の結果集合にある行をすべて返します。 INTERSECT 演算子は両方の結果集合にある行をすべて返します。 EXCEPT 演算子は最初の結果集合にあり、2番目の結果集合にない行を返します。 ALL が指定されない限り、これら3つとも、重複する行は取り除かれます。 (後述のUNIONINTERSECT、および、EXCEPTを参照してください。)

  5. 実際の出力行は、選択された各行に対して、SELECT出力式を使用して計算されたものです。 (後述のSELECT リストを参照してください。)

  6. ORDER BY 句が指定された場合、返される行は指定した順番でソートされます。 ORDER BY が指定されない場合は、システムが計算過程で最初に見付けたものという何らかの順番で行が返されます。 (後述の ORDER BY を参照してください。)

  7. DISTINCT は結果から重複行を取り除きます。 DISTINCT ONは、指定された式すべてに一致する行を取り除きます。 (デフォルトの)ALL は重複した行も含め、すべての候補行を返します。 (後述のDISTINCT を参照してください。)

  8. LIMIT あるいは OFFSET 句が指定された場合、SELECT文は結果行の一部分のみを返します。 (後述のLIMITを参照してください。)

  9. FOR UPDATE 句により、SELECT 文は、引続き実行される更新用に選択行をロックします。 (後述のFOR UPDATE を参照してください。)

テーブルから値を読み取るためには SELECT 権限が必要です。 FOR UPDATE を使用するためには、同様にUPDATE 権限が必要です。

パラメータ

FROM

FROM 句はSELECTの対象となるソーステーブルを1つ以上指定します。 複数のソースが指定された場合、結果はすべてのソースの直積(クロス結合)となります。 しかし、通常は直積の小さな一部分を返すように制限するために制約条件が付け加えられます。

FROM-句の要素には以下を指定できます。

table_name

既存のテーブルもしくはビューの名前です(スキーマ修飾名でも可)。 ONLYが指定された場合、そのテーブルのみがスキャンされます。 もし ONLY が指定されない場合、テーブルと(もしあれば)それを継承するすべてのテーブルがスキャンされます。 子テーブルがスキャンされることを表すために、テーブル名に * を付けることができますが、現在のバージョンでは、子テーブルのスキャンはデフォルトで行われます。 (7.1 より前のリリースでは、ONLY がデフォルトでした。) デフォルトの振る舞いを変更するには、sql_inheritance 設定オプションを変更します。 (訳注:原文のsql_interitanceをsql_inheritanceに変更。)

alias

別名を含む FROM アイテムの代替名です。 別名は簡潔さのため、もしくは自己結合 (同じテーブルが複数回スキャンされる場合です) の曖昧さをなくすために使われます。 別名が指定されている場合は、その別名によって実際のテーブル名または関数名が完全に隠されます。 例えば、FROM foo AS f と指定されている場合、以降の SELECT 文ではこの FROM アイテムを foo ではなく f として参照する必要があります。 テーブルの別名があれば、そのテーブルの複数の列の名前を置き換える列の別名リストを記述することができます。

select

SELECTFROM 句で使うことができます。 これはその出力がこの SELECT コマンド実行時に一時テーブルとして作成されたかのように動作します。 副 SELECT はカッコで囲まれなければならず、必ず別名が提供されなければなりません。

function_name

FROM 句に関数呼び出しを使用することができます。 (これは特に関数が結果セットを返す場合に有用ですが、任意の関数を使用することができます。) これはその出力がこの SELECT コマンド実行時に一時テーブルとして作成されたかのように動作します。 また、別名を使用することもできます。 別名があれば、その関数の複合戻り型の複数の属性の代替名を提供する別名リストを記述することができます。 関数が record データ型を返すものと定義されている場合は、別名すなわちキーワード AS とそれに続く ( column_name data_type [, ... ]) という形式の列定義リストが必要です。 列定義リストは、関数によって返される実際の列の数およびデータ型に一致していなければなりません。

join_type

以下のいずれかです。

  • [ INNER ] JOIN

  • LEFT [ OUTER ] JOIN

  • RIGHT [ OUTER ] JOIN

  • FULL [ OUTER ] JOIN

  • CROSS JOIN

INNER および OUTER 結合型では、結合条件、すなわち、NATURAL, ON join_condition、もしくは、USING (join_column [, ...])のいずれかを1つのみ指定する必要があります。 意味は後で説明します。 CROSS JOIN では、これらの句を記述しなくても構いません。

JOIN 句は、2つのFROM アイテムを結びつけます。 入れ子の順番を決めるために、必要ならば括弧を使用してください。 括弧が無いと、JOIN は左から右へと入れ子にされます。 どのような場合でもJOINは、コンマで分けられたFROM 項目よりも強く結び付きます。

CROSS JOININNER JOIN は、FROM の最上位で2つの項目を付けた結果と同一の、1つの直積を生成します。 しかし、(もしあれば)結合条件で制限をかけることができます。 CROSS JOININNER JOIN ON (true)と等価であり、条件によって削除される行はありません。 これらの結合型は記述上の便宜のためだけのものです。従って、通常のFROMWHEREを行わないと何も行いません。

LEFT OUTER JOIN は条件に合う直積の全ての行(つまり、その結合条件を満たす全ての組み合わされた行)に加え、右側の行を持たないが結合条件を満たす左側のテーブルの各々の行のコピーを返します。 この左側の行は右側の行に NULL 値を挿入することで結合されたテーブルの全幅に拡張されます。 どの行がマッチしているかを決める間、JOIN 句自身の条件のみが考慮されることに注意してください。 他の外部結合条件は後で適用されます。

逆に、RIGHT OUTER JOIN は全ての結合された行と、それぞれの当てはまるものがなかった右側の行(左側は null で拡張されています)に一行ずつを返します。 左と右の入力を入れ換えることで LEFT OUTER JOIN に変換することもできるため、これはただの記述上の便宜でしかありません。

FULL OUTER JOIN は、すべての結合された行、一致しなかった左側の行(を右側をnullで拡張させた行)を1行ずつ、更に、一致しなかった右側の行(を左側をnullで拡張させた行)を1行ずつ返します。

ON join_condition

join_condition は、結合においてどの行が一致したとみなすかどうかを指定する(WHERE句同様)boolean 型の値を返す式です。

USING (join_column [, ...])

USING ( a, b, ... ) 句は ON left_table.a = right_table.a AND left_table.b = right_table.b ...の省略形です。 USING は等価となる列の組合せの両方ではなく片方のみが結合の出力に含まれることを意味します。

NATURAL

NATURAL は 2 つのテーブル内の同じ名前を持つすべてを指定した USING リストの省略形です。

WHERE

省略可能な WHERE 句は通常以下の形式となります。

WHERE condition

ここで、condition は評価の結果 boolean 型を返す任意の式です。 この条件を満たさない行はすべて出力から取り除かれます。 すべての変数参照に実際の行の値を代入した時に式が真を返す場合に、行は条件を満たします。

GROUP BY

省略可能な GROUP BY 句は通常以下の形式となります。

GROUP BY expression [, ...]

GROUP BY は、グループ化式で同じ値を共有するすべての行を 1つの行に凝縮します。 expression は、入力列名か、出力列(SELECT リスト項目)の名前もしくは序数、もしくは、入力列の値から計算される任意の式を取ることができます。 曖昧な場合、GROUP BY の名前は出力列名ではなく入力列名として解釈されます。

集約関数がもし使用されていると、各グループを生成するすべての行に対して計算され、グループ毎に分けた値が生成されます。 (一方GROUP BYが無い場合は、集約関数はすべての選択された行に対して計算され、1つの値を生成します。) GROUP BY があると、集約関数内部以外でグループ化されていない列を参照する SELECT リストは無効になります。 グループ化されていない列について返される値は複数の値になってしまうからです。

HAVING

省略可能な HAVING は通常以下の形になります。

HAVING condition

ここで conditionWHERE 句で指定するものと同じです。

HAVING はこの条件を満たさないグループ化された行を取り除きます。 HAVINGWHERE とは違います。 WHERE では、GROUP BY の適用前に、個別の行に対してフィルタを行い、HAVINGGROUP BY で生成されたグループ化された行に対してフィルタを行います。 condition内の列参照は、集約関数内で表れる参照を除き、曖昧さが無いグループ化された列を参照しなければなりません。

UNION

UNION は通常以下の形式となります。

select_statement UNION [ ALL ] select_statement

select_statement は、ORDER BYLIMITFOR UPDATE句を持たない、任意のSELECT文です。 (もし括弧で括られていたら、ORDER BYLIMIT は副式に付与できます。 括弧が無いと、これらの句は右側の入力式にではなく、UNIONの結果に対して適用されてしまいます。)

UNION 演算子は、呼び出されたSELECT文で返される行の和集合を計算します。 少なくともどちらか片方に表れれば、その行は2つの結果セットの和集合内にあります。 直接 UNION の演算項目となる SELECT 文は、同じ列数を返さなければならず、また、対応する列のデータ型には互換性が必要です。

ALL オプションが指定されていないと、UNION の結果には重複行は含まれません。 ALL は重複除去を行いません。

一つの SELECT文で複数のUNION 演算子がある場合、括弧で示されない限り、その評価は左から右に行われます。

現時点では、FOR UPDATEUNION の結果に対しても、UNIONの何らかの入力に対しても指定することができません。

INTERSECT

INTERSECT は通常以下の形式となります。

select_statement INTERSECT [ ALL ] select_statement

select_statement は、ORDER BYLIMITFOR UPDATE を持たない、任意のSELECT文です。

INTERSECT は、呼び出されるSELECT文が返す行の積集合を計算します。 両方の結果セットに現れる場合、その行は2つの結果セットの積集合内に存在します。

ALLオプションが指定されていないと、INTERSECT の結果には重複行は含まれません。 ALL がある場合、左側テーブルにm個の重複、右側テーブルにn個の重複がある行は、結果セットにmin(m,n)個 出現します。

一つの SELECT文で複数のINTERSECT 演算子がある場合、括弧で示されない限り、その評価は左から右に行われます。 INTERSECTUNIONよりも強い結び付きです。 つまり、A UNION B INTERSECT CA UNION (B INTERSECT C) と解釈されます。

EXCEPT

EXCEPT は通常以下の形式となります。

select_statement EXCEPT [ ALL ] select_statement

select_statement は、ORDER BYLIMITFOR UPDATE 句を持たない、任意のSELECT文です。

EXCEPTは、左側の SELECT 文の結果に存在し、右側の結果には存在しない行の集合を計算します。

ALLオプションが指定されていないと、EXCEPT の結果には重複行は含まれません。 ALL がある場合、左側テーブルにm個の重複、右側テーブルにn個の重複がある行は、結果セットにmax(m-n,0)個 出現します。

一つの SELECT文で複数のEXCEPT 演算子がある場合、括弧で示されない限り、その評価は左から右に行われます。 EXCEPTの結び付きのレベルはUNIONと同じです。

SELECT リスト

SELECT リスト(SELECTFROM の間にあるキーワード)は、SELECT 文の出力行を形成する式を指定したものです。 この式では、FROM 句内で計算された列を参照することができます(そして、通常は参照します)。 AS output_name を使用して、出力列とは別の名前を指定できます。 この名前は主に表示用の列ラベルとして使われます。 また、ORDER BYGROUP BY 句内で列の値を参照するためにも使用されます。 しかし、WHEREHAVING句では使用されず、ここには式を書かなければなりません。

式の代わりに、選択された行の全ての列を表す省略形として、出力リストに * と書くことができます。 また、そのテーブルのみに由来する列を表す省略形として、table_name.*と書くこともできます。

ORDER BY

省略可能な ORDER BY句は通常以下の形式となります。

ORDER BY expression [ ASC | DESC | USING operator ] [, ...]

expression には、出力列(SELECT リスト項目)の名前もしくは序数、あるいは、入力列値から形成される任意の式をとることができます。

ORDER BY 句により、結果の行を指定した式に従ってソートすることができます。 もっとも左にある式で2つの行が等しくなった場合は、次の式に従い、それも等しければ更に次の式に進みます。 指定した式の全てで等しくなった場合は、実装に依存した順番で返されます。

序数とは、結果列の(左から右への)順序の位置です。 この機能により、一意な名前を持たない列に対して順序を定義することができます。 AS 句を使用すれば結果列に名前を割り当てることができますので、これは決して必要なものではありません。

また、ORDER BY 句には、SELECT 結果リストに出現しない列を含む、任意の式を使用できます。 従って、以下の文は有効なものです。

SELECT name FROM distributors ORDER BY code;

この機能の制限は、UNIONINTERSECTEXCEPT の結果に ORDER BY を適用する場合は、式を使用できず、出力列の名前か序数のみを指定できるという点です。

ORDER BY 式が、結果列名と入力列名の両方に一致する単なる名前であった場合、ORDER BYは結果列名としてそれを扱います。 これは、同じ状況における GROUP BY の選択とは反対です。 標準SQLとの互換性のためこの不整合が発生しています。

省略可能なキーワードASC (昇順)、DESC (降順)をORDER BY中の任意の式の後に付け加えることができます。 指定がなければ、デフォルトでASCが付いているものとして扱われます。 別方法に、順序指定演算子名をUSING 句に指定することができます。 通常、ASCUSING < と、DESCUSING > と同じです。 (しかし、ユーザ定義のデータ型の作者は、デフォルトのソート順が何かを正しく定義することができ、演算子に異なる名前を対応づけすることもできます。)

null値は他の値よりも高いものとしてソートされます。 言い替えると、昇順のソート順ではnull値は最後に、降順のソート順ではnull値は最初にソートされます。

文字型のデータでは、データベースクラスタの初期化時に決定されるロケール指定の照合順に従ってソートされます。

LIMIT

LIMIT 句は2つの独立した副句から構成されます。

LIMIT { count | ALL }
OFFSET start

count は返される行の最大数を指定し、一方、start は行を返し始める前に飛ばす行数を指定します。 両方とも指定された場合、 start行が飛ばされ、そこから数えてcount行が返されます。

LIMIT を使う時は、結果の行を一意な順番に強制する ORDER BY 句を使うのが良い考えです。 そうしないと、問い合わせの行の予測不可能なサブセットを得ることになります。 10 から 20 行目までを出そうとしているかもしれませんが、どの順番の 10 から 20 行目までなのでしょうか? ORDER BY を指定しない限りどの順番だかわからないのです。

問い合わせプランナは問い合わせ計画を作成する時に LIMIT を考慮しますので、LIMITOFFSET に何を使用するかによって(異なる行の順番を生む)異なった計画を得ることになるでしょう。 したがって、問い合わせの、異なるサブセットを選択するために異なる LIMIT/OFFSET の値を使うと、ORDER BY で予測可能な結果の順序を強制しない限り、矛盾した結果を返します。 これはバグではありません。 これは SQL が ORDER BY で順番を制御しない限り問い合わせの結果を特定の順番で返すことを約束しないという事実の本質的な結果なのです。

DISTINCT

DISTINCTが指定されると、重複する行は全て結果セットから削除されます。 (各重複行の中で1行のみが保持されます。) ALL はこの反対のことを指定し、全ての行が保持されます。これがデフォルトです。

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 UPDATE

FOR UPDATE は以下の形式となります。

FOR UPDATE [ OF table_name [, ...] ]

FOR UPDATE を使用すると問い合わせによって検索された行が更新用にロックされます。 これにより、現行のトランザクションが終了するまではこれらの行が他のトランザクションによって変更されたり削除されたりすることがなくなります。 つまり、現行のトランザクションが終了するまでは、他のトランザクションがこれらの行に対して UPDATEDELETE、または SELECT FOR UPDATE を試行しても拒否されるのです。 また、他のトランザクションからの UPDATEDELETE、または SELECT FOR UPDATE によって選択されている行がロックされている場合に SELECT FOR UPDATE を実行しようとすると、SELECT FOR UPDATE はそのトランザクションが終了するのを待ち、その後更新された行をロックして返します (行が削除された場合は返しません)。 詳細については、第12章を参照してください。

FOR UPDATE 内に特定のテーブルが指定されている場合は、そのテーブルの行のみがロックされ、SELECT 内の他のテーブルは通常どおりに読み込まれるだけです。

FOR UPDATE は、返される行が対応する個々のテーブル行を明確に識別できない場合には使用することができません。例えば、集約には使用できません。

FOR UPDATE は、バージョン 7.3 より前のPostgreSQLとの互換性のために LIMIT の前に書くことができます。 しかしその場合でも実際には LIMIT の後に実行されるので、LIMIT の後に書くことをお勧めします。

テーブル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 列によって結果をグループ化するには下記のようにします。

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

次の例は、結果をそれぞれのテーブルで W で始まるものだけに制限して、どのようにテーブル distributorsactors の結合を獲得するかを表しています。 重複しない行のみが必要なので、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 文は標準SQLと互換性があります。 しかし、拡張機能や実現されていない機能もいくつかあります。

FROM 句の省略

PostgreSQLでは、FROM 句を省略することができます。 以下のように素直に単純な式の結果を計算させることができます。

SELECT 2+2;

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

他のSQLデータベースでは、こういったSELECTを行うためにはダミーの1行テーブルを使わなければなりません。

明確さはありませんが、普通のSELECTからテーブルを省く、以下のような方法があります。

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

 did |   name
-----+----------
 108 | Westward

これは、SELECTで参照されるけれども FROM では記述されないテーブルが、暗黙の FROM アイテムに追加されるので、動作します。

これは便利な省略形ですが、間違って使いやすいです。 例えば、次のコマンド

SELECT distributors.* FROM distributors d;

はおそらく間違いです。ほとんどのユーザは、

SELECT d.* FROM distributors d;

を意図し、実際に得られる制約の無い結合

SELECT distributors.* FROM distributors d, distributors distributors;

を意図しないでしょう。 この種の間違いを検出できるように、PostgreSQL は、明示的な FROM句があっても、暗黙的な FROM 機能がSELECT文で使用されている場合に警告を発します。 また、ADD_MISSING_FROMパラメータをfalseに設定することで、暗黙的なFROM機能は無効にすることができます。

AS キーワード

標準SQLでは、省略可能なキーワードAS は単なるノイズで、その意味に影響すること無く省略することができます。 PostgreSQL のパーサは出力列の名前を変更する際にこのキーワードを必要とします。 なぜなら型の拡張機能を考えると、このキーワードがないと構文解析の不明瞭さにつながるからです。 しかし、FROM アイテムではASは省略可能です。

GROUP BYORDER BYにおける利用可能な名前空間

SQL92では、ORDER BY句は、結果の列名か序数のみを使用することができ、GROUP BY 句は、入力列名からなる式のみを使用できます。 PostgreSQL は、これらの句でそれぞれ他の選択が同じようにできるように拡張しています。 (しかし不明瞭さがある場合は標準の解釈が使用されます。) また、PostgreSQLではどちらの句にも任意の式を指定できます。 式で使われる名前は常に結果列の名前ではなく入力列の名前としてみなされることに注意してください。

SQL99では、SQL92との上位互換性が全くない、多少異なった定義を使用します。 しかし、ほとんどの場合、PostgreSQLはSQL99と同じ方法でORDER BYGROUP BYを解釈します。

非標準句

DISTINCT ONLIMITOFFSET 句は標準SQLでは定義されていません。