[ WITH [ RECURSIVE ] with_query [, ...] ] SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] * | expression [ [ AS ] output_name ] [, ...] [ FROM from_item [, ...] ] [ WHERE condition ] [ GROUP BY expression [, ...] ] [ 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 ] [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT ] [...] ] ここでfrom_itemは以下のいずれかです。 [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ] [ LATERAL ] ( select ) [ AS ] alias [ ( column_alias [, ...] ) ] with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ] [ LATERAL ] function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ] [ LATERAL ] function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] ) from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ] またwith_queryは以下の通りです。 with_query_name [ ( column_name [, ...] ) ] AS ( select | values | insert | update | delete ) TABLE [ ONLY ] table_name [ * ]
SELECTは0個以上のテーブルから行を返します。 SELECTの一般的な処理は以下の通りです。
WITHリスト内のすべての問い合わせが計算されます。 これらは実質、FROMリスト内から参照可能な一時テーブルとして提供されます。 FROM内で2回以上参照されるWITH問い合わせは一度のみ計算されます。 (後述のWITH句を参照してください。)
FROMリストにある全要素が計算されます (FROMリストの要素は実テーブルか仮想テーブルのいずれかです)。 FROMリストに複数の要素が指定された場合、それらはクロス結合されます (後述のFROM句を参照してください)。
WHERE句が指定された場合、条件を満たさない行は全て出力から取り除かれます (後述のWHERE句を参照してください)。
GROUP BY句が指定された場合、1つまたは複数の値が条件に合う行ごとにグループに組み合わせて出力されます。 HAVING句が指定された場合、指定した条件を満たさないグループは取り除かれます (後述のGROUP BY句とHAVING句を参照してください)。
実際には、選択された各行または行グループに対して、SELECT出力式を使用して計算した結果の行が出力されます (後述のSELECTリストを参照してください)。
DISTINCTは結果から重複行を取り除きます。 DISTINCT ONは指定した全ての式に一致する行を取り除きます。 ALLでは、重複行も含め、全ての候補行を返します(これがデフォルトです。 詳しくは、後述のDISTINCT句を参照してください)。
UNION、INTERSECT、EXCEPT演算子を使用すると、複数のSELECT文の出力を1つの結果集合にまとめることができます。 UNION演算子は、両方の結果集合に存在する行と、片方の結果集合に存在する行を全て返します。 INTERSECT演算子は、両方の結果集合に存在する行を返します。 EXCEPT演算子は、最初の結果集合にあり、2番目の結果集合にない行を返します。 ALLが指定されない限り、いずれの場合も、重複する行は取り除かれます。 無意味なDISTINCTという単語を付けて、明示的に重複行を除去することを指定することができます。 SELECT自体はALLがデフォルトですが、この場合はDISTINCTがデフォルトの動作であることに注意してください。 (後述のUNION句、INTERSECT句、EXCEPT句を参照してください。)
ORDER BY句が指定された場合、返される行は指定した順番でソートされます。 ORDER BYが指定されない場合は、システムが計算過程で見つけた順番で行が返されます (後述のORDER BY句を参照してください)。
LIMIT(またはFETCH FIRST)あるいはOFFSET句が指定された場合、SELECT文は結果行の一部分のみを返します (詳しくは、後述のLIMIT句を参照してください)。
FOR UPDATE、FOR NO KEY UPDATE、FOR SHAREまたはFOR KEY SHARE句を指定すると、SELECT文は引き続き行われる更新に備えて選択行をロックします (詳しくは、後述のロック処理句を参照してください)。
SELECTコマンド内で使われる列それぞれに対するSELECT権限が必要です。 FOR NO KEY UPDATE、FOR UPDATE、FOR SHAREまたはFOR KEY SHAREを使用するためには、さらに、(選択できるように各テーブルで少なくとも1列に対する)UPDATE権限が必要です。
WITH句により主問い合わせ内で名前により参照可能な、1つ以上の副問い合わせを指定することができます。 副問い合わせは実質的に主問い合わせの間の一時的なテーブルかビューのように動作します。 各副問い合わせはSELECT、VALUES、INSERT、UPDATE、DELETEにすることができます。 WITH内でデータ変更文(INSERT、UPDATE、DELETE)を記述する場合は、RETURNING句を含めることが有用です。 主問い合わせで読み取られる一時テーブルを形成するのは、RETURNINGの出力であり、文が変更する背後のテーブルではありません。 RETURNINGを省くと、文は同様に実行されますが、出力を生成しませんので、主問い合わせでテーブルとして参照することができません。
(スキーマ修飾がない)名前を各WITH問い合わせで指定しなければなりません。 省略可能ですが、列名のリストを指定することもできます。 これを省略すると、列名は副問い合わせから推定されます。
RECURSIVEが指定されると、SELECT副問い合わせは自身で名前により参照することができます。 こうした副問い合わせは以下のような形式でなければなりません。
non_recursive_term UNION [ ALL | DISTINCT ] recursive_term
ここで再帰的な自己参照はUNIONの右辺に現れなければなりません。 問い合わせ当たり1つの再帰的な自己参照のみが許されます。 再帰的なデータ変更文はサポートされていませんが、データ変更文で再帰的なSELECTの結果を使用することができます。 例は項7.8を参照してください。
RECURSIVEには他にも、WITH問い合わせが順序通りでなくても構わないという効果があります。 問い合わせはリストの後にある別のものを参照することができます。 (しかし巡回する参照や相互的な参照は実装されていません。) RECURSIVEがないと、WITH問い合わせは主問い合わせが共通するWITH問い合わせのうち、WITHリストの前方にあるもののみを参照することができます。
WITH問い合わせの鍵となる特性は、これらを主問い合わせが複数回参照していたとしても、主問い合わせの実行当たり一度のみ評価される点です。 特にデータ変更文は、主問い合わせがその出力のすべてまたは一部を読み取るかに関係なく、本当に一度のみ実行されることが保証されています。
主問い合わせとWITH問い合わせは(理論上)同時にすべて実行されます。 WITH内のデータ変更文によりなされた影響は、RETURNING出力を読み取る以外、問い合わせの他の部分では参照できないことを意味します。 こうしたデータ変更文が2つあり、同じ行を変更しようとした場合、その結果は明確ではありません。
追加情報については項7.8を参照してください。
FROM句にはSELECTの対象となるソーステーブルを1つ以上指定します。 複数のソースが指定された場合、結果は全てのソースの直積(クロス結合)となります。 しかし、通常は(WHEREを介して)制約条件を付けて、直積のごく一部を返すように結果行を限定します。
FROM句には以下の要素を指定できます。
既存のテーブルもしくはビューの名前です(スキーマ修飾名も可)。 テーブル名の前にONLYが指定された場合、そのテーブルのみがスキャンされます。 ONLYが指定されない場合、テーブルと(もしあれば)それを継承する全てのテーブルがスキャンされます。 省略することもできますが、テーブル名の後に*を指定することで、明示的に継承するテーブルも含まれることを示すことができます。
別名を含むFROMアイテムの代替名です。 別名は、指定を簡潔にするため、もしくは、自己結合(同じテーブルを複数回スキャンする結合)の曖昧さをなくすために使われます。 別名が指定されている場合は、その別名によって実際のテーブル名または関数名が完全に隠されます。 例えば、FROM foo AS fと指定されている場合、以降のSELECT文ではこのFROMアイテムをfooではなくfとして参照する必要があります。 テーブルの別名があれば、そのテーブルの複数の列の名前を置き換える列の別名リストを記述することができます。
FROM句では、副SELECTを使うことができます。 SELECTコマンドの実行中、副SELECTの出力は一時テーブルであるかのように動作します。 副SELECTは括弧で囲まれなければなりません。また、必ず別名を与えておかなければなりません。 VALUESコマンドをここで使用することもできます。
WITH問い合わせは、問い合わせの名前があたかもテーブル名であるかのように、名前を記述することで参照されます。 (実際にはWITH問い合わせは主問い合わせの対象とするテーブルと同じ名前の実テーブルを隠蔽します。 必要ならばテーブル名をスキーマ修飾することで同じ名前の実テーブルを参照することができます。) テーブルと同様の方法で別名を提供することができます。
FROM句では、関数呼び出しを使用することができます (これは特に関数が結果セットを返す場合に有用ですが、任意の関数を使用することもできます)。 SELECTコマンドの実行中は、この関数の結果は一時テーブルであるかのように動作します。 また、別名を使用することもできます。 別名が記述されていれば、列の別名リストを記述して、関数の複合型の戻り値の1つ以上の、ORDINALITYがある場合はそれが追加する列を含め、属性に対する代替名を提供することもできます。 関数がrecordデータ型を返すと定義されている場合は、別名すなわちASキーワードと、それに続く(column_name data_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アイテムを結び付けます。 便宜上"tables"として参照するものですが、実際には任意の種類のFROMアイテムとすることができます。 入れ子の順番を決めるために、必要ならば括弧を使用してください。 括弧がないと、JOINは左から右へ入れ子にします。 どのような場合でもJOINは、カンマで分けられたFROM項目よりも強い結び付きを持ちます。
CROSS JOINとINNER JOINは直積を1つ生成します。これは、FROMの最上位で2つのテーブルを結合した結果と同一です。 しかし、(指定すれば)結合条件によって制限をかけることができます。 CROSS JOINはINNER JOIN ON (true)と等価であり、条件によって削除される行はありません。 これらの結合型は記述上の便宜のためだけに用意されています。 したがって、通常のFROMとWHEREを実行しなければ何も行いません。
LEFT OUTER JOINは、条件に合う直積の全ての行(つまり、その結合条件を満たす全ての組み合わせ)に加え、左側テーブルの中で、右側テーブルには結合条件を満たす行が存在しなかった行のコピーも返します。 この左側テーブルの行を結合結果のテーブルの幅に拡張するために、右側テーブルが入る列にはNULL値が挿入されます。 マッチする行を決める時は、JOIN句自身の条件のみが考慮されることに注意してください。 他の外部結合条件は後で適用されます。
逆に、RIGHT OUTER JOINは、全ての結合行と、左側テーブルに当てはまるものがなかった右側の行(左側はNULLで拡張されています)の1行ずつを返します。 左右のテーブルを入れ替えればLEFT OUTER JOINに変換できるので、RIGHT OUTER JOINは記述上の便宜を図るため用意されているに過ぎません。
FULL OUTER JOINは、全ての結合行に加え、一致しなかった左側の行(右側はNULLで拡張)、一致しなかった右側の行(左側はNULLで拡張)を全て返します。
join_conditionは、結合においてどの行が一致するかを指定する、boolean型の値を返す式です(WHERE句に類似しています)。
USING ( a, b, ... )句はON left_table.a = right_table.a AND left_table.b = right_table.b ...の省略形です。 USINGは等価な列の両方ではなく片方のみが結合の出力に含まれることを意味します。
NATURALは、2つのテーブル内の同じ名前を持つ行を全て指定したUSINGリストの省略形です。
LATERALキーワードを副SELECTのFROM項目の前に付けることができます。 これにより、SELECTがFROMリストの中で前に現れるFROM項目の列を参照することができます。 (LATERALがないと、副SELECTそれぞれが個別に評価され、他のFROM項目とのクロス参照を行うことができません。)
LATERALを関数を呼び出すFROMの前に付けることもできます。 しかしこの場合、無意味な単語になります。 関数式はどのような場合でもより前のFROM項目を参照することができるからです。
LATERAL項目はFROMの最上位レベルやJOINツリー内に記述することができます。 後者の場合、JOINの右辺にあれば、左辺にある任意の項目を参照することができます。
FROM項目がLATERALクロス参照を含む場合、評価は次のように行われます。 クロス参照される列を提供するFROM項目の各行、または、その列を提供する複数のFROM項目の行集合に対して、 LATERAL項目は列の行または行集合を使用して評価されます。 結果となる行は、計算された行であるかのように通常通り結合されます。 これが各行または列ソーステーブルからの行集合に対して繰り返されます。
列ソーステーブルはLATERAL項目とINNERまたはLEFT結合されていなければなりません。 さもないと、 LATERAL項目において各行集合を計算するための行集合が完全に定義することができません。 したがってX RIGHT JOIN LATERAL Yという式は構文としては有効ですが、実際にはYではXを参照することができません。
WHERE句は通常以下の形式となります(この句は省略可能です)。
WHERE condition
conditionは、評価の結果としてboolean型を返す任意の式です。 この条件を満たさない行は全て出力から取り除かれます。 全ての変数に実際の行の値を代入して、式が真を返す場合、その行は条件を満たすとみなされます。
GROUP BY句は通常以下の形式となります(この句は省略可能です)。
GROUP BY expression [, ...]
GROUP BYは、グループ化のために与えられた式を評価し、結果が同じ値になった行を1つの行にまとめる機能を持ちます。 expressionには、入力列の名前、出力列(SELECTリスト項目)の名前/序数、あるいは入力列の値を計算する任意の式を取ることができます。 判断がつかない時は、GROUP BYの名前は出力列名ではなく入力列名として解釈されます。
集約関数が使用された場合、各グループ内の全ての行を対象に計算が行われ、結果としてグループごとの値が生成されます (一方GROUP BYがなければ、集約関数は選択された全ての行を対象に計算を行い、1つの値を生成します)。 GROUP BYが存在する場合、集約関数内部以外で、グループ化されていない列を参照する場合やグループ化されていない列がグループ化された列に関数依存する場合、SELECTリストは無効になります。 こうしないとグループ化されていない列について返される値は複数の値になってしまう可能性があるからです。 グループ化された列(またはその部分集合)がグループ化されていない列を含むテーブルのプライマリキーである場合、関数依存が存在します。
HAVINGは通常以下の形になります(この句は省略可能です)。
HAVING condition
conditionはWHERE句で指定するものと同じです。
HAVINGは、グループ化された行の中で、条件を満たさない行を取り除く機能を持ちます。 HAVINGとWHEREは次の点が異なります。 WHEREが、GROUP BYの適用前に個々の行に対してフィルタを掛けるのに対し、HAVINGは、GROUP BYの適用後に生成されたグループ化された行に対してフィルタをかけます。 condition内で使用する列は、集約関数内で使用されたものを除き、グループ化された列を一意に参照するものでなければなりません。
HAVING句があると、GROUP BY句がなかったとしても問い合わせはグループ化された問い合わせになります。 GROUP BY句を持たない問い合わせが集約関数を含む場合も同様です。 選択された行はすべて、1つのグループを形成するものとみなされます。また、SELECTリストとHAVING句では、集約関数が出力するテーブル列しか参照することができません。 こうした問い合わせでは、HAVINGが真の場合には単一の行を、真以外の場合は0行を出力します。
省略可能な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 ] frame_start [ RANGE | ROWS ] BETWEEN frame_start AND frame_end
ここでframe_startとframe_endは以下のいずれかを取ることができます。
UNBOUNDED PRECEDING value PRECEDING CURRENT ROW value FOLLOWING UNBOUNDED FOLLOWING
frame_endが省略された場合デフォルトでCURRENT ROWとなります。 frame_startはUNBOUNDED FOLLOWINGとすることができない、frame_endはUNBOUNDED PRECEDINGとすることができない、および、上のリストでframe_endの選択をframe_startの選択より先に行うことができないという制限があります。 例えばRANGE BETWEEN CURRENT ROW AND value PRECEDINGは許されません。
デフォルトのフレーム化オプションはRANGE UNBOUNDED PRECEDINGです。 これはRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWと同じで、 パーティションの先頭からORDER BY順序における現在の行の最後のピアまでのすべての行をフレームとします(ORDER BYがなければすべての行を意味します)。 一般的にUNBOUNDED PRECEDINGはフレームがパーティションの先頭から始まることを意味し、同様にUNBOUNDED FOLLOWINGはフレームがパーティションの最終行で終わることを意味します(RANGEモードかROWSかは関係ありません)。 ROWSモードでは、CURRENT ROWはフレームが現在の行で始まる、または終わることを意味しますが、RANGEモードでは、フレームが現在の行のORDER BY順序における最初のピアまたは最後のピアで始まる、または終わることを意味します。 現時点ではvalue PRECEDINGおよびvalue FOLLOWINGという場合わけはROWSモードだけで許されます。 これらは、現在の行の何行前または何行後にフレームが始まるまたは終わることを示します。 valueは整数式でなければならず、変数、集約関数、ウィンドウ関数を含めることはできません。 この値はNULLまたは負を取ることはできません。 しかし、現在の行自身を選択するゼロを取ることができます。
ORDER BY順序によりその行を一意に順序付けできない場合、ROWSが予期できない結果をもたらす可能性があることに注意して下さい。 RANGEは、ORDER BY順序におけるピアとなる行が同等に扱われる、つまり任意の2つのピアはフレーム内に両方とも存在するか、存在しないかのいずれかとなることが確実になるように設計されています。
WINDOW句の目的は、問い合わせのSELECTリストまたはORDER BY句に記載されるウィンドウ関数の動作を規定することです。 これらの関数はそのOVER句において名前でWINDOW句の項目を参照することができます。 しかしWINDOW句の項目は他で参照されてはなりません。 問い合わせ内で使用されなかったものは、単に無視されます。 ウィンドウ関数呼び出しはOVER句でウィンドウ定義を直接規定することができますので、WINDOW句を全く使わずにウィンドウ関数を使用することができます。 しかしWINDOW句は、同じウィンドウ定義が複数のウィンドウ関数で必要とされる場合に入力量を省くことができます。
SELECTリスト(SELECTとFROMの間にあるキーワード)は、SELECT文の出力行を形成する式を指定するものです。 この式では、FROM句で処理後の列を参照することができます(通常は実際に参照します)。 AS output_nameを使用すると、出力列に元の名前とは別の名前を付けることができます。
テーブルの場合と同様に、SELECTの出力列はすべて名前を持ちます。 簡単なSELECTでは、この名前は列に表示用のラベルを付けるために使用されるだけです。 しかしSELECTが大規模な問い合わせの副問い合わせである場合、大規模な問い合わせ側で副問い合わせで生成された仮想のテーブルの列名としてこの名前が参照されます。 出力列として使用するための名前を指定するためには、列式の後にAS output_nameと記述してください。 (希望する列名がPostgreSQLのキーワード(付録Cを参照)に一致しない場合にのみASを省略することができます。 将来あり得るキーワードの追加に備えるために、常にASを記述する、あるいは、出力名を二重引用符で括ることを推奨します。) 列名を指定しない場合、名前はPostgreSQLにより自動的に付けられます。 列式が単純な列参照であれば、つけられる名前はその列の名前と同じものです。 より複雑な場合では、関数名または型名が使用されるかもしれません。さもなければ?columnN?のように生成される名前になるかもしれません。
ORDER BY句とGROUP BY句内で列の値を参照する時も、出力列名を使用できます。 しかし、WHEREやHAVING句では使用できません。これらでは式を書かなければなりません。
リストには、選択された行の全ての列を表す省略形として、式ではなく*と書くことができます。 また、そのテーブルに由来する列のみを表す省略形として、table_name.*と書くこともできます。 このような場合、ASにより新しい名前を指定することはできません。 出力列名はテーブルの列名と同一になります。
SELECT DISTINCTが指定されると、重複する行は全て結果セットから削除されます (重複するグループの中で1行が保持されます)。 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グループの中での行の優先順位を決定する追加的な式を含みます。
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 BYとLIMITは、括弧で囲めば複式として付与することができます。 括弧がない場合、これらの句は右側に置かれた入力式ではなく、UNIONの結果に対して適用されてしまいます)。
UNION演算子は、2つのSELECT文が返す行の和集合を作成します。 この和集合には、2つのSELECT文の結果集合のいずれか(または両方)に存在する行が全て含まれています。 UNIONの直接のオペランドとなるSELECT文同士が返す列数は、同じでなければなりません。また、対応する列のデータ型には互換性が存在する必要があります。
ALLオプションが指定されていない限り、UNIONの結果には重複行は含まれません。 ALLを指定するとこのような重複除去が行われません (したがって、通常UNION ALLはUNIONよりかなり高速です。 できるだけALLを使用してください)。 重複行を除去するデフォルトの動作を明示的に指定するためにDISTINCTを記述することができます。
1つのSELECT文に複数のUNION演算子がある場合、括弧がない限り、それらは左から右に評価されます。
現時点では、UNIONの結果やUNIONに対する入力に、FOR NO KEY UPDATE、FOR UPDATE、FOR SHARE、FOR KEY SHAREを指定することはできません。
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は、2つのSELECT文が返す行の積集合を計算します。 この積集合に含まれるのは、2つのSELECT文の結果集合の両方に存在する行です。
ALLオプションを指定しない限り、INTERSECTの結果に重複行は含まれません。 ALLが指定された場合、左側テーブルにm個、右側テーブルにn個の重複がある行は、結果集合ではmin(m,n)個出現します。 重複行を除去するデフォルトの動作を明示的に指定するためにDISTINCTを記述することができます。
1つのSELECT文に複数のINTERSECT演算子がある場合、括弧がない限り、それらは左から右に評価されます。 INTERSECTはUNIONよりも強い結び付きを持ちます。 つまり、A UNION B INTERSECT C はA UNION (B INTERSECT C)と解釈されます。
現時点では、INTERSECTの結果やINTERSECTに対する入力に、FOR NO KEY UPDATE、FOR UPDATE、FOR SHAREまたはFOR KEY SHAREを指定することはできません。
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文の結果には存在し、右側のSELECT文の結果には存在しない行の集合を生成します。
ALLオプションが指定されていない限り、EXCEPTの結果には重複行は含まれません。 ALLがある場合、左側テーブルにm個、右側テーブルにn個の重複がある行は、結果集合ではmax(m-n,0)個出現します。 重複行を除去するデフォルトの動作を明示的に指定するためにDISTINCTを記述することができます。
1つのSELECT文に複数のEXCEPT演算子がある場合、括弧がない限り、それらは左から右に評価されます。 EXCEPTの結び付きの強さはUNIONと同じです。
現時点では、EXCEPTの結果やEXCEPTに対する入力に、FOR NO KEY UPDATE、FOR UPDATE、FOR SHAREまたはFOR KEY SHAREを指定することはできません。
ORDER BY句は通常以下の形式となります(この句は省略可能です)。
ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]
ORDER BY句を使うと、結果行を指定した式(複数可)に従ってソートすることができます。 最も左側の式を使って比較した結果、2つの行が等しいと判断された場合は、1つ右側の式を使って比較します。その結果も等しければ、さらに次の式に進みます。 指定した全ての式で等しいと判断された場合は、実装に依存した順番で返されます。
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および項22.2を参照してください。
LIMIT句は2つの独立した副句から構成されます。
LIMIT { count | ALL } OFFSET start
countには返される行の最大数を、一方、startには行を返し始める前に飛ばす行数を指定します。 両方とも指定された場合、start行分が飛ばされ、そこから数えてcount行が返されます。
count式がNULLと評価された場合、LIMIT ALLとして、つまり制限無しとして扱われます。 startがNULLと評価された場合、OFFSET 0と同様に扱われます。
SQL:2008では同じ結果を実現する異なる構文が導入されました。 PostgreSQLでもサポートしています。 以下の構文です。
OFFSET start { ROW | ROWS } FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY
この構文において、startまたはcountに単一整数定数以外を記述するためには、括弧でくくって記述しなければなりません。 countをFETCH句で省略した場合、そのデフォルトは1です。 ROWおよびROWS、そしてFIRSTおよびNEXTは意味がない単語で、この句に影響を与えることはありません。 標準に従うとOFFSET句は、FETCH句と同時に使用する場合、これより前に存在しなければなりません。 しかしPostgreSQLは厳密ではなく、どちらが先でも許されます。
LIMITを使う時は、結果行を一意な順番に強制するORDER BY句を使うとよいでしょう。 そうしないと、問い合わせ結果のどの部分が返されるのかがわかりません。 10〜20行目までを出力するとしても、どの順番で並べた時の10〜20行目なのでしょうか。 ORDER BYを指定しない限り、行が返される順番は不明です。
問い合わせプランナは問い合わせ計画を作成する時にLIMITを考慮するので、LIMITとOFFSETの指定によって異なった計画を得ることになるでしょう。計画が異なれば、異なる順番で行が返ります。 したがって、LIMIT/OFFSET値の変更によって異なる結果行を選択しようとすると、ORDER BYで順序を並び替えない限り、矛盾した結果を返すことになります。 これはバグではありません。 「SQLは、ORDER BYで順序を制御されない限り、問い合わせ結果が返す順序を約束しない」という事実の当然の帰結なのです。
厳密的に部分集合の選択を強制するORDER BYがなければ、同じLIMIT問い合わせを繰り返し実行してもテーブル行から異なる部分集合が取り出される可能性すらあります。 繰り返しますが、これは不具合ではありません。 こうした場合に確定した結果は単に保証されていないのです。
FOR UPDATE、FOR NO KEY UPDATE、FOR SHAREおよびFOR KEY SHAREはロック処理句です。 これらはテーブルから行を入手する時にどのようにSELECTがその行をロックするかに影響します。
ロック処理句は以下のような汎用形式を持ちます。
FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT ]
ここでlock_strengthは以下のいずれかを取ることができます。
UPDATE NO KEY UPDATE SHARE KEY SHARE
FOR UPDATEを使用すると、問い合わせによって検索された行が更新用にロックされます。 これにより、現行のトランザクションが終了するまでは、これらの行が他のトランザクションによって変更されたり削除されたりすることがなくなります。 つまり、現行のトランザクションが終了するまでは、他のトランザクションがこれらの行に対してUPDATE、DELETE、SELECT FOR UPDATE、SELECT FOR NO KEY UPDATE、SELECT FOR SHAREもしくはSELECT FOR KEY SHAREを試行しても拒否されます。 FOR UPDATEロックモードは、行に対するDELETEでも、ある列の値を変更するUPDATEでも獲得されます。 現在、UPDATEで複数の列が対象になる場合は、これらは外部キー内で使用することができる一意性制約を持ちます。 (このため部分インデックスや式インデックスは考慮されません。) しかしこれは今後変わるかもしれません。 また、他のトランザクションからのUPDATE、DELETE、SELECT FOR UPDATEによって選択した行がロックされている場合、SELECT FOR UPDATEを実行しようとすると、SELECT FOR UPDATEはそのトランザクションが終了するのを待ってから、その後行をロックして更新された行を返します(行が削除された場合は返しません)。 しかしREPEATABLE READまたはSERIALIZABLEトランザクションの内部では、ロック対象の行がトランザクション開始時から変更されていた場合、エラーが発生します。 第13章を参照してください。
FOR NO KEY UPDATEは似たような動作をしますが、より弱いロックが獲得される点が異なります。 これは同じ行に対するロックの獲得を試行するSELECT FOR KEY SHAREをブロックしません。 このロックモードはFOR UPDATEロックを獲得しないUPDATEでも獲得されます。
FOR SHAREも同様に振舞いますが、入手する行に対し排他的ロックを獲得するのではなく共有ロックを獲得する点が異なります。 共有ロックにより、他トランザクションによるその行に対するUPDATE、DELETE、SELECT FOR UPDATE、SELECT FOR NO KEY UPDATE操作はブロックされます。 しかし、他トランザクションによるSELECT FOR SHARE、SELECT FOR KEY SHARE操作を防ぎません。
FOR KEY SHAREはFOR SHAREと似た動作をしますが、より弱いロックが獲得される点が異なります。 SELECT FOR UPDATEはブロックされますが、SELECT FOR NO KEY UPDATEはブロックされません。 キー共有ロックは 他のトランザクションによるDELETEやそのキー値を変更するUPDATEが実行されることをブロックしますが、その他のUPDATEやこれらを行わないSELECT FOR NO KEY UPDATE、SELECT FOR SHARE、SELECT FOR KEY SHAREをブロックしません。
他のトランザクションのコミットを待機することなく操作を進めるには、NOWAITオプションを使用してください。 NOWAITでは、選択行のロックを即座に獲得できない時、文は待機せずに、エラーを報告します。 NOWAITは行レベルロックにのみに適用される点に注意してください。 つまり、必要なROW SHAREテーブルレベルロックは通常通りの方法( 第13章を参照)で獲得されます。 もし、テーブルレベルのロックを待機せずに獲得しなければならないのであれば、最初にLOCKのNOWAITオプションを使用してください。
ロック処理句内に特定のテーブルが指定されている場合は、そのテーブルの行のみがロックされます。 SELECT内の他のテーブルは通常通りに読み込まれます。 テーブルリストを持たないロック処理句は、その文で使用されるすべてのテーブルに影響を与えます。 ロック処理句がビューまたは副問い合わせで使用された場合、そのビューや副問い合わせで使用されるすべてのテーブルに影響を与えます。 しかしこれらの句は主問い合わせで参照されるWITH問い合わせには適用されません。 WITH問い合わせ内での行ロックを行いたい場合は、WITH問い合わせ内でロック処理句を指定してください。
異なるロック方式を異なるテーブルに指定する必要があれば、複数のロック処理句を記述することができます。 複数のロック処理句で同一のテーブルを記述した(または暗黙的に影響が与えられた)場合、最も強いものが指定されたかのように処理されます。 同様に、あるテーブルに影響を与える句のいずれかでNOWAITが指定された場合、そのテーブルはNOWAITとして処理されます。
ロック処理句は、返される行がテーブルのどの行に対応するのかが明確に識別できない場合には使用することができません。 例えば、集約には使用できません。
ロック処理句がSELECT問い合わせの最上位レベルに存在する場合、ロック対象行は問い合わせが返す行に正確に一致します。 結合問い合わせ内の場合、ロック対象行は返される結合行に関連する行となります。 さらに、スナップショットを更新した後に問い合わせ条件を満たさなくなった場合は返されなくなりますが、問い合わせのスナップショット時点で問い合わせ条件を満たす行もロックされます。 LIMITが使用された場合、制限を満たす行が返されるとロック処理は止まります。 (しかし、OFFSETにより飛ばされた行はロックされることに注意してください。) 同様に、ロック処理句がカーソル問い合わせで使用された場合、カーソルにより実際に取り込んだ行または過去に処理された行のみがロックされます。
ロック処理句が副SELECTに存在する場合、ロック対象行は副問い合わせの外側の問い合わせで返される行となります。 外側の問い合わせからの条件が副問い合わせ実行の最適化に使用される可能性がありますので、これには副問い合わせ自体の検査が提示する行より少なくなるかもしれません。 例えば、
SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;
は、副問い合わせ内では文字として条件が記載されていなくても、col1 = 5を持つ行のみがロックされます。
Previous releases failed to preserve a lock which is upgraded by a later savepoint. For example, this code: --> これまでのリリースでは、セーブポイント以降に更新されるロックの保持は失敗しました。 例えば以下のコードです。
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で修正されました。
注意 |
ORDER BY句とロック処理句を使用した、READ COMMITTEDトランザクション隔離レベルで実行するSELECTコマンドでは、順序通りにならない行を返す可能性があります。 ORDER BYが最初に適用されるためです。 このコマンドは結果をソートしますが、その後、1行または複数の行のロック獲得がブロックされる可能性があります。 このSELECTのブロックが解除された時点で、順序付け対象の列値の一部が変更されているかもしれません。 これによりこうした行が(元の列値という観点では順序通りではありますが、)順序通りに現れません。 必要に応じて、これは以下のように副問い合わせ内にFOR UPDATE/SHARE句を記述することで、回避することができます。 SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1; これは、最上位レベルにおけるFOR UPDATEは実際に返される行のみをロックするのに対して、結果としてmytableのすべての行をロックすることに注意してください。 これは、特にORDER BYがLIMITやその他の制限と組み合わせている場合、性能上大きな違いを生み出す可能性があります。 このため、この技法は、順序付け対象の列に対する同時実行の更新が想定され、かつ、厳密にソートされた結果が要求される場合にのみ推奨されます。 REPEATABLE READまたはSERIALIZABLEトランザクション隔離レベルでは、('40001'というSQLSTATEを持つ)シリアライゼーション失敗が発生します。 このためこれらの隔離レベルでは順序外の行を受け取る可能性はありません。 |
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
次に、結果を2番目の列(name)の内容に基づいてソートする方法を2つ例示します。
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
以下の例では簡単な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問い合わせが一度だけ評価されることに注意してください。 このため3つのランダムな値の2つの集合を得ることになります。
以下の例では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を参照してください。)
以下の例では、manufacturersテーブルの各行に対して集合を返すget_product_names()
関数を適用するためにLATERALを使用します。
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と互換性があります。 しかし、拡張機能や実現されていない機能もいくつかあります。
PostgreSQLでは、FROM句を省略することができます。 これによって、以下のように単純な式を計算させることができます。
SELECT 2+2; ?column? ---------- 4
他のSQLデータベースでは、このようなSELECTを行うためにはダミーの1行テーブルを使わなければなりません。
FROM句の指定がない場合、問い合わせではデータベーステーブルを参照することができません。 例えば、以下の問い合わせは無効です。
SELECT distributors.* WHERE distributors.name = 'Westward';
PostgreSQLリリース8.1より前まででは、こうした形の問い合わせを受け付け、問い合わせで参照する各テーブルに対する暗黙的な項目を問い合わせのFROM句に追加していました。 これは許されなくなりました。
標準SQLでは、省略可能なキーワードASは、新しい列名が有効な列名(つまり予約済みのキーワードと異なるものすべて)である場合は常に、出力列名の前から省くことができます。 PostgreSQLには多少より強い制限があります。 新しい列名が予約済みか否かに関わらず何らかのキーワードに一致する場合はASが必要です。 推奨する実践方法は、今後のキーワードの追加と競合する可能性に備え、ASを使用する、または出力列名を二重引用符で括ることです。
FROM項目において標準およびPostgreSQLでは、未予約のキーワードである別名の前のASを省略することができます。 しかし、構文があいまいになるため、出力名では現実的ではありません。
標準SQLでは、SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...のように、ONLYを記述する時にテーブル名の前後を括弧でくくることを要求します。 PostgreSQLではこの括弧を省略可能であるとみなしています。
PostgreSQLでは最後に*を付けることで 明示的に子テーブルを含めるというONLYではない動作を指定することができます。 標準ではこれを許していません。
(この点はONLYオプションをサポートするすべてのSQLコマンドで同様に適用されます。)
PostgreSQLでは、FROMリストのメンバとして直接関数呼び出しを記述することができます。 標準SQLではこうした関数呼び出しを副SELECT内に囲む必要があります。 つまりFROM func(...) aliasはおおよそFROM LATERAL (SELECT func(...)) aliasと同じです。 暗黙的にLATERALであるとみなされることに注意してください。 標準ではFROM内のUNNEST()項目にはLATERAL構文を必要とするためです。 PostgreSQLではUNNEST()を他の集合を返す関数と同じものとして扱います。
標準SQL-92では、ORDER BY句で使用できるのは、出力列名か序数のみであり、GROUP BY句で使用できるのは、入力列名からなる式のみです。 PostgreSQLは、これらの句で両方が指定できるように拡張されています (ただし、不明瞭さがある場合は標準の解釈が使用されます)。 さらに、PostgreSQLではどちらの句にも任意の式を指定できます。 式で使われる名前は、常に出力列名ではなく入力列の名前とみなされることに注意してください。
SQL:1999以降では、SQL-92との上位互換性がまったくない、多少異なる定義が採用されています。 しかし、ほとんどの場合、PostgreSQLはSQL:1999と同じ方法でORDER BYやGROUP BYを解釈します。
テーブルのプライマリキーがGROUP BYリストに含まれる場合に限り、PostgreSQLは(GROUP BYで列を省くことができる)関数依存性を認識します。 標準SQLでは、認識しなければならない追加の条件を規定しています。
LIMITおよびOFFSET句はPostgreSQL独自の構文ですが、MySQLでも使用されています。 LIMIT句で説明したように、標準SQL:2008にて同じ機能のOFFSET ... FETCH {FIRST|NEXT} ...が導入されました。 この構文はIBM DB2でも使用されています。 (PostgreSQLでは利用できませんが、Oracle用に開発されたアプリケーションでは、これらの句の機能を実装するためによく自動生成されるrownum列を含めるという回避策を使用します。)