本章ではSQLの構文について説明します。 本章の内容は、データの定義や変更のためにSQLコマンドを適用する方法について詳しく説明する以後の章を理解する上での基礎となります。
規則や概念によっては、SQLデータベースによって異なっていたり、あるいは、PostgreSQLに固有のものなどがありますので、SQLについて熟知しているユーザも本章を注意深く読むことをお勧めします。
SQLの入力は、ひと続きのコマンドからなります。 コマンドはトークンが繋がったもので構成され、最後はセミコロン(";")で終わります。 入力ストリームの終了もやはりコマンドを終わらせます。 どのトークンが有効かは特定のコマンドの構文によります。
トークンはキーワード、識別子、引用符で囲まれた識別子、リテラル(もしくは定数)、特別な文字シンボルです。 トークンは通常空白(スペース、タブ、改行)で区切られますが、曖昧さがなければ(一般的には特別な文字が他のトークン型と隣接している場合のみ)必要ありません。
さらに、入力された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構文は、どのトークンがコマンドを識別し、どれがオペランドでどれがパラメータかに関してはさほど首尾一貫していません。 最初のいくつかのトークンは一般にコマンド名です。 したがって、上記の例において"SELECT"、"UPDATE"、"INSERT"コマンドについて通常説明することになります。 しかし、例えばUPDATEコマンドでは、SETトークンが特定の位置に常に記述されなければなりませんし、この例で使われているINSERTコマンドを完結するためにはVALUESトークンが必要です。 それぞれのコマンドの正確な構文規則はパートVIで説明されています。
上記の例に出てくるSELECT、UPDATE、もしくはVALUESのようなトークンは、キーワードの一例です。 キーワードとは、SQL言語で決まった意味を持っている単語です。 MY_TABLEトークンやAトークンは識別子の一例です。 これらは、使われるコマンドによって、テーブル、列、他のデータベースオブジェクトの名前を識別します。 したがって、単に"名前"と呼ばれることもあります。 キーワードと識別子は同じ語彙の構造を持つため、言語を知らなくてはトークンが識別子なのかキーワードなのかわからないということになります。 全てのキーワードのリストは付録Cにあります。
SQL識別子とキーワードは、文字(a〜zおよび発音区別符号と非Latin文字)、アンダースコア(_)で始まらなければいけません。 識別子またはキーワードの中で続く文字は、文字、アンダースコア、数字(0〜9)を使用することができます。 標準SQLの記述に従うと、ドル記号は識別子内では使用できないことに注意してください。 ですから、これを使用するとアプリケーションの移植性は低くなります。 標準SQLでは、数字を含む、あるいはアンダースコアで始まったり終わったりするキーワードは定義されていません。 したがって、この形式の識別子は標準の今後の拡張と競合する可能性がないという意味で安全と言えます。
システムはNAMEDATALEN-1文字より長い識別子の文字数を使いません。 より長い名前をコマンドで書くことはできますが、短く切られてしまいます。 デフォルトではNAMEDATALENは64なので、識別子は最長で63です。 この制限が問題になる場合は、src/include/postgres_ext.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;
引用符付き識別子は、二重引用符自身以外であればどのような文字でも使えます (二重引用符を含めたい場合は、二重引用符を2つ入力します)。 この決まりがあることによって、普段使えない空白やアンパサンド(&)を含むテーブル名や列名を作ることが可能です。 この場合においても長さの制限は適用されます。
引用符が付かない名前は常に小文字に解釈されますが、識別子を引用符で囲むことによって大文字と小文字が区別されるようになります。 例えば、識別子FOO、foo、"foo"はPostgreSQLによれば同じものとして解釈されますが、"Foo"と"FOO"は、これら3つとも、またお互いに違ったものとして解釈されます (PostgreSQLが引用符の付かない名前を小文字として解釈することは標準SQLと互換性がありません。標準SQLでは引用符の付かない名前は大文字に解釈されるべきだとされています。 したがって標準SQLによれば、fooは"FOO"と同じであるべきで、"foo"とは異なるはずなのです。 もし移植可能なアプリケーションを書きたいならば、特定の名前は常に引用符で囲むか、あるいはまったく囲まないかのいずれかに統一することをお勧めします)。
PostgreSQLには、3つの暗黙に型付けされる定数があります。 文字列、ビット文字列、そして数字です。 定数は明示的な型で指定することもでき、その場合はシステムによる、より正確な表現と効率の良い操作が可能になります。 こうした他の方法については後ほど説明します。
SQLにおける文字列定数は、単一引用符(')で括られた任意の文字の並びです。 例えば、'This is a string'です。 標準に準拠した文字列定数内の単一引用符の記述方法は、2つ続けて単一引用符を記述することです。 例えば、'Dianne''s horse'です。 PostgreSQLでは、また、単一引用符をバックスラッシュでエスケープすること(\')ができます。 しかし、今後のPostgreSQLのバージョンではこれはできなくなる予定です。 ですので、バックスラッシュを使用するアプリケーションを上述の標準に準拠するように変更しなければなりません。
他にもPostgreSQLの拡張として、C言語形式のバックスラッシュによるエスケープも有効です。 \bはバックスペース、\fは改頁、\nは改行、\rは復帰(キャリッジリターン)、\tはタブを意味します。 また、\digitsという形式や\xhexdigitsもサポートしています。 ここで、digitsは8進数を表し、hexdigitsは16進数のバイト値を表します。 (作成するバイトの並びがサーバの文字セット符号化方式として有効かどうかはコード作成者の責任です。) ここに示した以外のバックスラッシュに続く文字は、文字通りに解釈されます。 したがって、文字列定数にバックスラッシュを含む場合は、バックスラッシュを2つ入力してください。
注意: 現在普通の文字をC書式のバックスラッシュエスケープさせることはできますが、今後のバージョンでは、このような使用に対しては警告がなされ、標準に従うようにバックスラッシュを文字通りに扱うようになります。 エスケープ処理を適切に指定する方法は、エスケープ処理を行うことを示すエスケープ文字構文を使用することです。 エスケープ文字構文は、Eという文字(大文字小文字のどちらでもかまいません)を、文字列の直前に記述することで指定します。 例えばE'\041'です。 この方法は今後のすべてのバージョンのPostgreSQLで動作します。
文字コード0の文字は文字列定数の中には含められません。
2つの文字列定数が、少なくとも1つの改行を含んだ空白で区切られている場合は、2つの定数は連結されて、あたかも1つの定数として書かれたように効率的に処理されます。 例を示します。
SELECT 'foo' 'bar';
は、
SELECT 'foobar';
と同じです。しかし、
SELECT 'foo' 'bar';
は有効な構文ではありません (このちょっとした奇妙な振舞いはSQLで決められているもので、PostgreSQLではこの標準に従っています)。
SQLにおける文字列定数の指定構文はたいていの場合便利ですが、対象とする文字列内に多くの単一引用符やバックスラッシュがあると、それらを全て二重にしなければなりませんので理解しづらくなります。 こうした状況においても問い合わせの可読性をより高めるために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つに減少します。
ビット文字列定数はB(大文字もしくは小文字)が引用符の始まりの前に付いている(間に空白はありません)通常の文字列定数のように見えます。 例えばB'1001'のようになります。 ビット文字列定数の中で許可される文字は0と1のみです。
その他にも、ビット文字列定数はX'1FF'といった具合に、先頭にX(大文字または小文字)を使用して16進表記で指定することもできます。 この表記は、各16進数値をそれぞれ4つの2進数値に置き換えたビット文字列定数と同等です。
どちらの形式のビット文字列定数でも、通常の文字列定数と同じように複数行にわたって続けて書くことができます。 ドル引用符付けはビット文字列定数では使用できません。
数値定数は下記の一般的な形で受け付けられます。
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書式
実のところ、これらは以下で説明する一般的なキャスト記法の特別な場合です。
任意の型の定数は下記の表記のいずれかを使って入力することができます。
type 'string' 'string'::type CAST ( 'string' AS type )
文字列定数のテキストはtypeと呼ばれる型の入力変換ルーチンへと渡されます。 結果は指示された型の定数です。 明示的な型キャストは、定数がどの型でなければならないかについて曖昧な点がなければ(例えば定数が直接テーブル列に代入されている場合)省略しても構いません。 その場合自動的に型強制されます。
文字列定数は通常のSQL記法でもドル引用符付けでも記述することができます。
関数のような構文を使って型強制を指定することも可能です。
typename ( 'string' )
しかし、全ての型の名前でこの方法は使用できるというわけではありません。 詳細は項4.2.8を参照してください。
::、CAST()や関数呼び出し構文も、項4.2.8で説明する通り、任意の式の実行時の型変換を指定するために使うことができます。 しかし、type 'string'という形式はリテラル定数を指定する場合にのみ使うことができます。 この他type 'string'には、配列型では動作しないという制限があります。 配列型の定数を指定する場合は::かCAST()を使用してください。
CAST()構文はSQLに従っています。 type 'string'構文は、標準を一般化したものです。 SQLでは、この構文を数個のデータ型でのみ規定しています。 しかし、PostgreSQLではすべての型で使用することができます。 ::付きの構文は、関数呼び出し構文と同様に歴史的にPostgreSQLで使用されてきました。
演算子はNAMEDATALEN-1までの(デフォルトは63)長さの、以下に示すリストに含まれる文字の並びです。
+ - * / < > = ~ ! @ # % ^ & | ` ?
しかし、演算子の名前にはいくつかの制約があります。--と/*は演算子名の中に使うことができません。 なぜならこれらはコメントの始まりと解釈されるからです。
複数文字の演算子名は、その名前が少なくとも下記の文字の1つ以上を含まない限り、+や-で終わることができません。
~ ! @ # % ^ & | ` ?
例えば、@-は演算子名として認められていますが、*-は認められていません。 この制限によりPostgreSQLは、SQLに準拠する問い合わせをトークン同士の間に空白を要求せず、解析することができます。
非SQL標準の演算子名を使う場合、通常は曖昧さを回避するために、隣り合った演算子を空白で区切る必要があります。 例えば@という左単項演算子を定義した場合、X*@Yとは書けません。 PostgreSQLがこれを確実に1つではなく2つの演算子名として解釈できるように、X* @Yと書く必要があります。
英数字ではないいくつかの文字は、演算子であることとは異なる特殊な意味を持っています。 使用法の詳細はそれぞれの構文要素についてのところで説明します。 本節では、単にその存在を知らせ、これらの文字の目的をまとめるに留めます。
直後に数字が続くドル記号($)は、関数定義の本体または準備された文中の位置パラメータを表すために使われます。 他の文脈ではドル記号は演算子名の一部であるかもしれませんし、ドル引用符付けされた文字列定数の一部であるかもしれません。
括弧(())は、通常通り式をまとめ優先するという意味を持ちます。 場合によっては括弧は、特定のSQLコマンドの固定構文の一部として要求されることがあります。
大括弧([])は、配列要素を選択するために使われます。 配列に関する詳しい情報は項8.10を参照してください。
カンマ(,)は、リストの要素を区切るために構文的構造体で使われることがあります。
セミコロン(;)は、SQLコマンドの終わりを意味します。 文字列定数または引用符付き識別子以外では、コマンドの途中では使うことができません。
コロン(:)は、配列から"一部分"を取り出すために使われます (項8.10を参照してください)。 いくつかのSQL方言(埋め込みSQLなど)では、コロンは変数名の接頭辞として使われます。
アスタリスク(*)は、いくつかの文脈において、テーブル行や複合型の全てのフィールドを表現するために使用されます。
またCOUNT
集約関数の引数として使われる場合も特殊な意味を持ちます。
ピリオド(.)は数値定数の中で使われます。 また、スキーマ、テーブル、列名を区切るためにも使われます。
コメントは二重ハイフンで始まる任意の文字の並びで、行の終わりまで続きます。 例えば以下のようになります。
-- これは標準SQLのコメントです
他にも、C言語様式のブロックコメントも使用できます。
/* ネストされた複数行にわたる * コメント /* ネストされたブロックコメント */ */
コメントは/*で始まり、対応する*/で終わります。 これらのブロックコメントはC言語とは異なり、標準SQLで規定されているように入れ子にすることができます。 したがって、既存のブロックコメントを含む可能性のある大きなコードのブロックをコメントアウトすることができます。
コメントは、その後の構文解析が行われる前に入力ストリームから取り去られ、空白によって適切に置き換えられます。
表4-1は、PostgreSQLの演算子の優先順位と結合性を示しています。 ほとんどの演算子は同じ優先順位を持ち、左結合します。 演算子の優先順位と結合性はパーサに組み込まれています。 これは非直感的な動作を導く可能性があります。 例えば、ブーリアン演算子<と>は、ブーリアン演算子<=と>=とは違った優先順位を持ちます。 さらに、二項演算子と単項演算子を組み合わせて使う場合は括弧を加える必要がある場合があります。 例えば下記のような場合です。
SELECT 5 ! - 6;
は、
SELECT 5 ! (- 6);
と解析されます。 なぜならば、パーサは!が中置ではなく接尾演算子として定義されていることに最後まで気が付かないためです。 この場合、求める結果を得るためには下記のように書く必要があります。
SELECT (5 !) - 6;
これが拡張性を求める故の代償です。
表 4-1. 演算子の優先順位(強いものから)
演算子/要素 | 結合性 | 説明 |
---|---|---|
. | 左 | テーブル/列名の区切り文字 |
:: | 左 | PostgreSQL方式の型キャスト |
[ ] | 左 | 配列要素選択 |
- | 右 | 単項減算 |
^ | 左 | 累乗 |
* / % | 左 | 掛け算、割り算、剰余 |
+ - | 左 | 加算、減算 |
IS | IS TRUE、IS FALSE、IS UNKNOWN、IS NULL | |
ISNULL | NULLかどうかを試す | |
NOTNULL | 非NULLかどうかを試す | |
(その他) | 左 | その他全ての組み込み、あるいはユーザ定義の演算子 |
IN | メンバシップを設定する | |
BETWEEN | 範囲内に含有 | |
OVERLAPS | 時間間隔の重複 | |
LIKE ILIKE SIMILAR | 文字列パターンのマッチング | |
< > | 小なり、大なり | |
= | 右 | 等しい、代入 |
NOT | 右 | 論理否定 |
AND | 左 | 論理積 |
OR | 左 | 論理和 |
演算子優先順位の規則は、上記で触れた組み込み演算子と同じ名前を持つユーザ定義演算子にも当てはまります。 例えばもし"+"演算子をある独自のデータ型に定義すると、新しい演算子が何をするかにかかわらず、"+"組み込み演算子と同じ優先順位を持つようになります。
次の例のように、OPERATOR構文でスキーマで修飾された演算子名を使用する場合、
SELECT 3 OPERATOR(pg_catalog.+) 4;
OPERATOR構文は、表4-1の"any other"演算子で示されているデフォルトの優先順位を持つとみなされます。 これは、OPERATOR()にどの特定の演算子が入る場合でも変わりません。