他のバージョンの文書 16 | 15 | 14 | 13 | 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

4.1. 字句の構造

SQLの入力は、ひと続きのコマンドからなります。 コマンドはトークンが繋がったもので構成され、最後はセミコロン(;)で終わります。 入力ストリームの終了もやはりコマンドを終わらせます。 どのトークンが有効かは特定のコマンドの構文によります。

トークンはキーワード識別子引用符で囲まれた識別子リテラル(もしくは定数)、特別な文字シンボルです。 トークンは通常空白(スペース、タブ、改行)で区切られますが、曖昧さがなければ(一般的には特別な文字が他のトークン型と隣接している場合のみ)必要ありません。

例えば、以下のものは(構文的に)正しいSQLの入力です。

SELECT * FROM MY_TABLE;
UPDATE MY_TABLE SET A = 5;
INSERT INTO MY_TABLE VALUES (3, 'hi there');

この例は1行に1つのコマンドを記述した、3つのコマンドが連続しています(必ずしも1つのコマンドを1行で書く必要はありません。 1行に複数のコマンドを入力することも可能ですし、1つのコマンドを複数行に分けて記述することも可能です)。

さらに、入力されたSQLにコメントが付いていても構いません。 コメントはトークンではなく、その効果は空白と同じです。

SQL構文は、どのトークンがコマンドを識別し、どれがオペランドでどれがパラメータかに関してはさほど首尾一貫していません。 最初のいくつかのトークンは一般にコマンド名です。 したがって、上記の例においてSELECTUPDATEINSERTコマンドについて通常説明することになります。 しかし、例えばUPDATEコマンドでは、SETトークンが特定の位置に常に記述されなければなりませんし、この例で使われているINSERTコマンドを完結するためにはVALUESトークンが必要です。 それぞれのコマンドの正確な構文規則はパート VIで説明されています。

4.1.1. 識別子とキーワード

上記の例に出てくるSELECTUPDATE、もしくはVALUESのようなトークンは、キーワードの一例です。 キーワードとは、SQL言語で決まった意味を持っている単語です。 MY_TABLEトークンやAトークンは識別子の一例です。 これらは、使われるコマンドによって、テーブル、列、他のデータベースオブジェクトの名前を識別します。 したがって、単に名前と呼ばれることもあります。 キーワードと識別子は同じ字句の構造を持つため、言語を知らなくてはトークンが識別子なのかキーワードなのかわからないということになります。 全てのキーワードのリストは付録Cにあります。

SQL識別子とキーワードは、文字(azおよび発音区別符号付き文字と非Latin文字)、アンダースコア(_)で始まらなければいけません。 識別子またはキーワードの中で続く文字は、文字、アンダースコア、数字(09)あるいはドル記号($)を使用することができます。 標準SQLの記述に従うと、ドル記号は識別子内では使用できないことに注意してください。 ですから、これを使用するとアプリケーションの移植性は低くなる可能性があります。 標準SQLでは、数字を含む、あるいはアンダースコアで始まったり終わったりするキーワードは定義されていません。 したがって、この形式の識別子は標準の今後の拡張と競合する可能性がないという意味で安全と言えます。

システムはNAMEDATALEN-1バイトより長い識別子を使いません。 より長い名前をコマンドで書くことはできますが、短く切られてしまいます。 デフォルトではNAMEDATALENは64なので、識別子は最長で63バイトです。 この制限が問題になる場合は、src/include/pg_config_manual.h内のNAMEDATALEN定数の値を変更して増やすことができます。

キーワードと引用符付きでない識別子は大文字と小文字を区別しません。 したがって、

UPDATE MY_TABLE SET A = 5;

は、以下の文と同じ意味になります。

uPDaTE my_TabLE SeT a = 5;

慣習的によく使われる方法では、キーワードを大文字で、名前を小文字で書きます。 例えば下記のようになります。

UPDATE my_table SET a = 5;

識別子には副次的な種類もあります。 区切り識別子あるいは引用符付き識別子です。 任意の文字の連なりを二重引用符(")で囲んだものです。 区切り識別子は常に識別子であって、キーワードではありません。 ですから、"select"selectという名前の列あるいはテーブルを問い合わせるために使えますが、引用符の付かないselectはキーワードとして理解されるので、テーブルもしくは列名が期待される部分では解析エラーを起こします。 引用符付き識別子は下記の例のように書くことができます。

UPDATE "my_table" SET "a" = 5;

引用符付き識別子は、コード0の文字以外であればどのような文字でも使えます (二重引用符を含めたい場合は、二重引用符を2つ入力します)。 これにより、空白やアンパサンド(&)を含むテーブル名や列名など、この方法がなければ作れないような名前のものを作ることが可能になります。 この場合においても長さの制限は適用されます。

引用符付き識別子には異形があり、コード番号で識別されるエスケープされたUnicode文字を含むことができます。 この異形は、U&(大文字または小文字のUの後にアンパサンド)で始まり、その直後に空白を間に入れずに二重引用符を続けます。 例えば、U&"foo"となります。 (これにより演算子&との不明確性が生じることに注意してください。 この問題を回避するには空白を演算子の前後に入れます。) 引用符の中で、Unicode文字はバックスラッシュとそれに続く4桁16進数の文字コード番号で、またはもう1つの方法として、バックスラッシュに続いてプラス符号、そして続いた6桁16進数の文字コード番号によりエスケープ形式で指定されます。 例えば、識別子"data"は次のように書くことができます。

U&"d\0061t\+000061"

次の少し意味のある例はロシア語のslon(象)をキリル文字で書いたものです。

U&"\0441\043B\043E\043D"

バックスラッシュ以外のエスケープ文字を使用したい場合、文字列の後にUESCAPE句を使用して指定することが可能です。例をあげます。

U&"d!0061t!+000061" UESCAPE '!'

エスケープ文字には、16進表記用の文字、プラス記号、単一引用符、二重引用符、空白文字以外の任意の単一文字を使用することができます。 エスケープ文字には二重引用符ではなく単一引用符で記述していることに注意してください。

識別子内にエスケープ文字をそのまま含めるためには、それを2つ記述してください。

Unicodeエスケープ構文はサーバの符号化方式がUTF8の場合のみ有効です。 他のサーバ符号化方式が用いられている場合、ASCII範囲(\007Fまで)のコードポイントのみ指定できます。 U+FFFFより大きなコードポイントを持つ文字を構成するUTF-16サロゲートペアを指定するために、4桁と6桁の形式の両方を使用することができますが、技術的には6桁形式の機能によりこれは不要になります。 (サロゲートペアは直接格納されるわけではなく、一つのコードポイントに結合されてから、UTF-8に符号化されます。)

引用符が付かない名前は常に小文字に解釈されますが、識別子を引用符で囲むことによって大文字と小文字が区別されるようになります。 例えば、識別子FOOfoo"foo"PostgreSQLによれば同じものとして解釈されますが、"Foo""FOO"は、これら3つとも、またお互いに違ったものとして解釈されます (PostgreSQLが引用符の付かない名前を小文字として解釈することは標準SQLと互換性がありません。標準SQLでは引用符の付かない名前は大文字に解釈されるべきだとされています。 したがって標準SQLによれば、foo"FOO"と同じであるべきで、"foo"とは異なるはずなのです。 もし移植可能なアプリケーションを書きたいならば、特定の名前は常に引用符で囲むか、あるいはまったく囲まないかのいずれかに統一することをお勧めします)。

4.1.2. 定数

PostgreSQLには、3つの暗黙に型付けされる定数があります。 文字列、ビット文字列、そして数字です。 定数は明示的な型で指定することもでき、その場合はシステムによる、より正確な表現と効率の良い操作が可能になります。 こうした他の方法については後ほど説明します。

4.1.2.1. 文字列定数

SQLにおける文字列定数は、単一引用符(')で括られた任意の文字の並びです。 例えば、'This is a string'です。 文字列定数内に単一引用符を含めるには、2つ続けて単一引用符を記述します。 例えば、'Dianne''s horse'です。 二重引用符(")とは同一ではない点に注意してください。

2つの文字列定数が、少なくとも1つの改行を含んだ空白のみで区切られている場合は、2つの定数は連結され、実質的に1つの定数として書かれたように処理されます。 例を示します。

SELECT 'foo'
'bar';

は、

SELECT 'foobar';

と同じです。しかし、

SELECT 'foo'      'bar';

は有効な構文ではありません (このちょっとした奇妙な振舞いはSQLで決められているもので、PostgreSQLではこの標準に従っています)。

4.1.2.2. C形式エスケープでの文字列定数

PostgreSQLでは、また、エスケープ文字列定数を受け付けます。 これは標準SQLの拡張です。 エスケープ文字列定数は、E(大文字でも小文字でもかまいません)を開始単一引用符の直前に記述することで指定されます。 例えばE'foo'です。 (複数行に渡るエスケープ文字列定数では、最初の開始引用符の前にのみEを記述してください。) エスケープ文字列の中では、バックスラッシュ文字(\)によりC言語のようなバックスラッシュシーケンスが開始し、その中でバックスラッシュとそれに続く文字の組み合わせが(表 4.1で示したように)特別なバイト値を表現します。

表4.1 バックスラッシュエスケープシーケンス

バックスラッシュエスケープシーケンス解釈
\b後退
\f改ページ
\n改行
\r復帰
\tタブ
\o, \oo, \ooo (o = 0 - 7) 8進数バイト値
\xh, \xhh (h = 0 - 9, A - F) 16進数バイト値
\uxxxx, \Uxxxxxxxx (x = 0 - 9, A - F) 16もしくは32ビットの16進数 Unicode 文字値

バックスラッシュの後のそのほかの全ての文字はそのまま扱われます。 従って、バックスラッシュ文字を含ませるときは2つのバックスラッシュ(\\)を記載します。 同時に、エスケープ文字列の中では、単一引用符を、通常の方法の''に加え、\'としても含めることができます。

特に8進数や16進数エスケープを用いて作成されるバイトシーケンスが、サーバ文字セット符号化方式において有効な文字で構成されていることはコードを書く人の責任です。 サーバ符号化方式がUTF-8の場合、Unicodeエスケープか、4.1.2.3で説明するもう一つのUnicodeエスケープ構文を代わりとして使用すべきです。 (後者は手作業でUTF-8符号化を行い、書き出さなくてはならないのでとても厄介です。)

Unicodeエスケープ構文は、サーバの符号化方式がUTF8である場合のみ、完全に動作します。 他のサーバ符号化方式が使用されている場合、ASCII範囲(\u007Fまで)のコードポイントのみを指定することができます。 U+FFFFより大きなコードポイントを持つ文字を構成するUTF-16サロゲートペアを指定するために、4桁と8桁の両方の形式を使用することができますが、技術的には8桁形式の機能によりこれは不要になります。 (サーバの符号化方式がUTF8の場合にサロゲートペアが使用される時、まず単一のコードポイントに組み合わされ、その後にUTF-8に符号化されます。)

注意

設定パラメータstandard_conforming_stringsoffの場合、PostgreSQLはバックスラッシュエスケープを通常の文字列定数とエスケープ文字列定数の両方で認識します。 しかし、PostgreSQL9.1からデフォルトはonになりました。これはバックスラッシュエスケープはエスケープ文字列でのみ認識されるということになります。 この振る舞いはSQL標準仕様に即していますが、バックスラッシュエスケープを常に認識するという歴史的な動作に依存しているアプリケーションは動作しなくなるでしょう。 回避策として、このパラメータをoffにすることはできますが、バックスラッシュエスケープの使用を避けるよう移植するのが良いでしょう。 特殊文字を表現するためにバックスラッシュを使用する必要がある場合、Eをつけて文字列定数を記述してください。

standard_conforming_stringsの他に、設定パラメータescape_string_warningおよびbackslash_quoteが文字定数内のバックスラッシュの動作を決定します。

コードゼロの文字は文字列定数の中に入れられません。

4.1.2.3. Unicodeエスケープがある文字列定数

PostgreSQLは同時に、文字コード番号で任意のUnicode文字を指定可能な文字列に対するもう一つのエスケープ構文を提供します。 Unicodeエスケープ文字列定数は、U&(大文字・小文字のUの後にアンパサンド)で始まり、その直後に、空白を間にはさまず、開始引用符が続きます。 例えば、U&'foo'となります。 (これにより演算子&との曖昧性が生じることに注意してください。 この問題を回避するには空白を演算子の前後に入れます。) 引用符の中で、Unicode文字はバックスラッシュとそれに続く4桁16進数の文字コード番号で、またはもう1つの方法として、バックスラッシュに続いてプラス符号、そして続いた6桁16進数の文字コード番号によりエスケープ形式で指定されます。 例えば、文字列'data'は次のように書かれます。

U&'d\0061t\+000061'

次の少し意味のある例はロシア語のslon(象)をキリル文字で書いたものです。

U&'\0441\043B\043E\043D'

バックスラッシュ以外のエスケープ文字を使用したい場合、文字列の後にUESCAPE句を使用して指定することが可能です。例をあげます。

U&'d!0061t!+000061' UESCAPE '!'

エスケープ文字には、16進表記用の文字、プラス記号、単一引用符、二重引用符、空白文字以外の任意の単一文字を使用することができます。

Unicodeエスケープ構文はサーバの符号化方式がUTF8の場合のみ有効です。 他のサーバ符号化方式が用いられている場合、ASCII範囲(\007Fまで)のコードポイントのみ指定できます。 U+FFFFより大きなコードポイントを持つ文字を構成するUTF-16サロゲートペアを指定するために、4桁と6桁の両方の形式を使用することができますが、技術的には6桁形式の機能によりこれは不要になります。 (サーバの符号化方式がUTF8の場合にサロゲートペアが使用される時、まず単一のコードポイントに組み合わされ、その後にUTF-8に符号化されます。)

また、文字列定数に対するユニコードエスケープ構文は設定パラメータstandard_conforming_stringsが有効なときのみ動作します。 そうでないとこの構文は、SQL文を構文解釈するクライアントを混乱させ、SQLインジェクションや、それに類似したセキュリティ問題に繋がることさえあるからです。 パラメータがoffに設定されていれば、この構文はエラーメッセージを出して拒絶されます。

文字列の中に、エスケープ文字をそのまま含めるにはエスケープ文字を2回書きます。

4.1.2.4. ドル記号で引用符付けされた文字列定数

文字列定数の標準の構文はたいていの場合便利ですが、対象とする文字列内に多くの単一引用符やバックスラッシュがあると、それらを全て二重にしなければなりませんので理解しづらくなります。 こうした状況においても問い合わせの可読性をより高めるためにPostgreSQLは、ドル引用符付けという他の文字列定数の指定方法を提供します。 ドル引用符付けされた文字列定数は、ドル記号($)、省略可能な0個以上の文字からなるタグ、ドル記号、文字列定数を構成する任意の文字の並び、ドル記号、この引用符付けの始めに指定したものと同じタグ、ドル記号から構成されます。 例えば、Dianne's horseという文字列をドル引用符付けを使用して指定する方法を、以下に2つ示します。

$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$

ドル引用符付けされた文字列の内側では、単一引用符をエスケープすることなく使用できることを理解して下さい。 実際には、ドル引用符付けされた文字列の内側の文字はまったくエスケープが必要なく、文字列定数はすべてそのまま記述することができます。 その並びが開始タグに一致しない限り、バックスラッシュもドル記号も特別なものではありません。

各入れ子レベルに異なるタグを付けることで、ドル引用符付けされた文字列を入れ子にすることができます。 これは、関数定義を作成する時に非常によく使用されます。 以下に例を示します。

$function$
BEGIN
    RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
END;
$function$

ここで、$q$[\t\r\n\v\\]$q$は、ドル引用符付けされた[\t\r\n\v\\]リテラル文字列を表し、PostgreSQLがこの関数本体を実行する時に認識されます。 しかし、この並びは、外側のドル引用符用の区切り文字$function$に一致しませんので、外側の文字列を対象としている場合は単なる文字の並びとなります。

もしあれば、ドル引用符付けされた文字列のタグは、引用符付けされていない識別子と同じ規則に従います。 ただし、タグにはドル記号を含めることはできません。 タグは大文字小文字を区別します。 したがって、$tag$String content$tag$は正しいのですが、$TAG$String content$tag$は間違いです。

キーワードや識別子の後にドル引用符付けされた文字列を続ける場合は、空白でそれを区切らなければなりません。 さもないと、ドル引用符の区切り文字は、直前の識別子の一部として解釈されます。

ドル引用符付けは、標準SQLで定義されていません。 しかし、複雑な文字列リテラルを記述する場合は標準準拠の単一引用符構文よりも便利なことがよくあります。 特に、他の定数の内部に文字列定数を記述するような場合は役に立ちます。 こうした状況は手続き関数の定義でよく必要とされます。 単一引用符構文では、上の例のバックスラッシュはそれぞれ、4個のバックスラッシュで記述しなければなりません。 この4つのバックスラッシュは、元の文字列定数を解析する際に2つに減少され、そして、関数を実行する際に内部の文字列定数が再解析され1つに減少します。

4.1.2.5. ビット文字列定数

ビット文字列定数はB(大文字もしくは小文字)が始まりの引用符の前に付いている(間に空白はありません)通常の文字列定数のように見えます。 例えばB'1001'のようになります。 ビット文字列定数の中で許可される文字は01のみです。

その他にも、ビット文字列定数はX'1FF'といった具合に、先頭にX(大文字または小文字)を使用して16進表記で指定することもできます。 この表記は、各16進数値をそれぞれ4つの2進数値に置き換えたビット文字列定数と同等です。

どちらの形式のビット文字列定数でも、通常の文字列定数と同じように複数行にわたって続けて書くことができます。 ドル引用符付けはビット文字列定数では使用できません。

4.1.2.6. 数値定数

数値定数は下記の一般的な形で受け付けられます。

digits
digits.[digits][e[+-]digits]
[digits].digits[e[+-]digits]
digitse[+-]digits

ここでdigitsは1つ以上の10進数字(0〜9)です。 小数点を使用する場合は、少なくとも1つの数字が小数点の前か後になくてはなりません。 指数記号eの付く形式を使う場合にはeの後に少なくとも1つの数字がなければいけません。 空白や他の文字は、定数の中に埋め込むことはできません。 プラスまたはマイナスの符号を先頭につけても、定数の一部とはみなされないことに注意してください。 これらの符号は定数に適用される演算子とみなされます。

下記は有効な数値定数のいくつかの例です。


42
3.5
4.
.001
5e2
1.925e-3

小数点も指数も含まない数値定数の場合、まずその値がinteger型(32ビット)に収まればinteger型であるとみなされます。 そうでない場合、bigint型(64ビット)で収まればbigint型とみなされます。 どちらでもない場合は、numeric型とみなされます。 定数が小数点または指数あるいはその両方を含む場合は、常に最初にnumeric型であるとみなされます。

数値定数に最初に割り振られるデータ型は、型解決アルゴリズムの開始点に過ぎません。 ほとんどの場合、定数は文脈に基づいて自動的に最も適切な型に変換されます。 必要であれば、特定のデータ型にキャストして、数値がそのデータ型として解釈されるように強制することができます。 例えば、以下のようにして数値をreal型(float4)として処理することができます。


REAL '1.23'  -- 文字列書式
1.23::REAL   -- (歴史的な)PostgreSQL書式

実のところ、これらは以下で説明する一般的なキャスト記法の特別な場合です。

4.1.2.7. 他の型の定数

任意の型の定数は下記の表記のいずれかを使って入力することができます。

type 'string'
'string'::type
CAST ( 'string' AS type )

文字列定数のテキストはtypeと呼ばれる型の入力変換ルーチンへと渡されます。 結果は指示された型の定数です。 明示的な型キャストは、定数がどの型でなければならないかについて曖昧な点がなければ(例えば定数が直接テーブル列に代入されている場合)省略しても構いません。 その場合自動的に型強制されます。

文字列定数は通常のSQL記法でもドル引用符付けでも記述することができます。

関数のような構文を使って型強制を指定することも可能です。

typename ( 'string' )

しかし、全ての型の名前でこの方法は使用できるというわけではありません。 詳細は4.2.9を参照してください。

::CAST()や関数呼び出し構文は、4.2.9で説明する通り、任意の式の実行時の型変換を指定するために使うこともできます。 構文的なあいまいさをなくすために、type 'string'という形式は単なるリテラル定数を指定する場合にのみ使うことができます。 この他type 'string'構文には、配列型では動作しないという制限があります。 配列型の定数の型を指定する場合は::CAST()を使用してください。

CAST()構文はSQLに従っています。 type 'string'構文は、標準を一般化したものです。 SQLでは、この構文を数個のデータ型でのみ規定しています。 しかし、PostgreSQLではすべての型で使用することができます。 ::付きの構文は、歴史的にPostgreSQLで使用されてきました。 関数呼び出し構文も同じく歴史的に使用されているものです。

4.1.3. 演算子

演算子はNAMEDATALEN-1(デフォルトは63)までの長さの、以下に示すリストに含まれる文字の並びです。


+ - * / < > = ~ ! @ # % ^ & | ` ?

しかし、演算子の名前にはいくつかの制約があります。

  • --/*は演算子名の中に使うことができません。 なぜならこれらはコメントの始まりと解釈されるからです。

  • 複数文字の演算子名は、その名前が少なくとも下記の文字の1つ以上を含まない限り、+-で終わることができません。


    ~ ! @ # % ^ & | ` ?

    例えば、@-は演算子名として認められていますが、*-は認められていません。 この制限によりPostgreSQLは、SQLに準拠する問い合わせをトークン同士の間に空白を要求せず、解析することができます。

非SQL標準の演算子名を使う場合、通常は曖昧さを回避するために、隣り合った演算子を空白で区切る必要があります。 例えば@という左単項演算子を定義した場合、X*@Yとは書けません。 PostgreSQLがこれを確実に1つではなく2つの演算子名として解釈できるように、X* @Yと書く必要があります。

4.1.4. 特殊文字

英数字ではないいくつかの文字は、演算子であることとは異なる特殊な意味を持っています。 使用方法の詳細はそれぞれの構文要素についてのところで説明します。 本節では、単にその存在を知らせ、これらの文字の目的をまとめるに留めます。

  • 直後に数字が続くドル記号($)は、関数定義の本体またはプリペアド文中の位置パラメータを表すために使われます。 他の文脈ではドル記号は識別子名の一部であるかもしれませんし、ドル引用符付けされた文字列定数の一部であるかもしれません。

  • 括弧(())は、通常通り式をまとめ優先するという意味を持ちます。 場合によっては括弧は、特定のSQLコマンドの固定構文の一部として要求されることがあります。

  • 大括弧([])は、配列要素を選択するために使われます。 配列に関する詳しい情報は8.15を参照してください。

  • カンマ(,)は、リストの要素を区切るために構文的構成体で使われることがあります。

  • セミコロン(;)は、SQLコマンドの終わりを意味します。 文字列定数または引用符付き識別子以外では、コマンドの途中では使うことができません。

  • コロン(:)は、配列から一部分を取り出すために使われます (8.15を参照してください)。 いくつかのSQL方言(埋め込みSQLなど)では、コロンは変数名の接頭辞として使われます。

  • アスタリスク(*)は、いくつかの文脈において、テーブル行や複合型の全てのフィールドを表現するために使用されます。 また、集約関数の引数として使われる場合も特殊な、つまり、その集約が明示的なパラメータをまったく必要としないという意味を持ちます。

  • ピリオド(.)は数値定数の中で使われます。 また、スキーマ名、テーブル名、列名を区切るためにも使われます。

4.1.5. コメント

コメントは二重ハイフンで始まる文字の並びで、行の終わりまで続きます。 例えば以下のようになります。


-- これは標準SQLのコメントです

他にも、C言語様式のブロックコメントも使用できます。


/* ネストされた複数行にわたる
 * コメント /* ネストされたブロックコメント */
 */

コメントは/*で始まり、対応する*/で終わります。 これらのブロックコメントはC言語とは異なり、標準SQLで規定されているように入れ子にすることができます。 したがって、既存のブロックコメントを含む可能性のある大きなコードのブロックをコメントアウトすることができます。

コメントは、その後の構文解析が行われる前に入力ストリームから取り去られ、事実上、空白で置き換えられます。

4.1.6. 演算子の優先順位

表 4.2は、PostgreSQLの演算子の優先順位と結合性を示しています。 ほとんどの演算子は同じ優先順位を持ち、左結合します。 演算子の優先順位と結合性はパーサに組み込まれています。

二項演算子と単項演算子を組み合わせて使う場合は括弧を加える必要がある場合があります。 例えば下記のような場合です。

SELECT 5 ! - 6;

は、

SELECT 5 ! (- 6);

と解析されます。 なぜならば、パーサは!が中置ではなく接尾演算子として定義されていることに最後まで気が付かないためです。 この場合、求める結果を得るためには下記のように書く必要があります。

SELECT (5 !) - 6;

これが拡張性を求める故の代償です。

表4.2 演算子の優先順位(高いものから低いものへ)

演算子/要素結合性説明
.テーブル/列名の区切り文字
::PostgreSQL方式の型キャスト
[ ]配列要素選択
+ -単項加算、単項減算
^累乗
* / %掛け算、割り算、剰余
+ -加算、減算
(その他の演算子)その他全ての組み込み、あるいはユーザ定義の演算子
BETWEEN IN LIKE ILIKE SIMILAR 範囲内に包含、集合の要素、文字列の一致
< > = <= >= <>  比較演算子
IS ISNULL NOTNULL IS TRUEIS FALSEIS NULLIS DISTINCT FROM、その他
NOT論理否定
AND論理積
OR論理和

演算子優先順位の規則は、上記で触れた組み込み演算子と同じ名前を持つユーザ定義演算子にも当てはまります。 例えばもし+演算子をある独自のデータ型に定義すると、新しい演算子が何をするかにかかわらず、+組み込み演算子と同じ優先順位を持つようになります。

次の例のように、OPERATOR構文でスキーマで修飾された演算子名を使用する場合、

SELECT 3 OPERATOR(pg_catalog.+) 4;

OPERATOR構文は、表 4.2その他の演算子で示されているデフォルトの優先順位を持つとみなされます。 これは、OPERATOR()にどの特定の演算子が入る場合でも変わりません。

注記

9.5より前のPostgreSQLのバージョンでは少し異なる演算子優先順位規則を使っていました。 特に<=>=<>は一般的な演算子として扱われていました。ISテストは高い優先順位を持つとして使われていました。NOT BETWEENとそれに関係する構文は振る舞いが一貫しておらず、BETWEENではなくNOTの優先順位を持つと見なされる場合がありました。 標準SQLにより準拠し、論理的に等しい構文の一貫しない扱いから来る混乱を減らすように、これらの規則は変更されました。 ほとんどの場合、これらの変更により振る舞いが変わることはないでしょうし、もし変わっても恐らくno such operatorで失敗になるくらいでしょう。後者は括弧を追加することで解決できるでしょう。 しかしながら、稀に問い合わせがパースエラーを返すことなく振る舞いを変える場合があります。 これらの変更が黙って何かを壊してしまったかどうかが心配であれば、設定パラメータoperator_precedence_warningをオンにして、何か警告がログに書き込まれるかを見てください。