4.2. 評価式

評価式は、たとえばSELECTコマンドの目的リストとして、INSERTUPDATEの新しい列の値として、もしくはいくつかのコマンドの検索条件としてさまざまな文脈のなかで使われます。 評価式の結果は、テーブル式の結果(つまりテーブル)から区別するために、スカラと呼ばれることもあります。 したがって、評価式はスカラ式(もしくはもっと簡単に)とも呼ばれます。 式の構文によって、算術、論理、集合などの演算を行う基本的な部分で値の計算を行うことができます。

評価式は下記のうちのどれかです。

これ以外にも、式として分類されるけれども一般的な構文規約には従わない、いくつかの構成要素があります。 これらは一般的に関数あるいは演算子の意味を持ちます。第9章の該当部分で説明されています。 例をあげるとIS NULL句があります。

項4.1.2ですでに定数については説明しました。 続く節では残りのオプションについて説明します。

4.2.1. 列の参照

列は、下記のような形式で参照することができます。

correlation.columnname

correlationは、テーブル名(スキーマで修飾されている場合もあり)、FROM句で定義されたテーブルの別名、あるいはNEWまたはOLDというキーワードです。 (NEWOLDは書き換えルールでしか使用されませんが、他の相関名はすべてのSQL文で使用することができます。) 相関名と区切り用のドットは、もし列名が現在の問い合わせで使われるすべてのテーブルを通して一意である場合は省略してもかまいません。 (第7章も参照してください。)

4.2.2. 位置パラメータ

位置パラメータ参照は、外部からSQL文に渡される値を示すために使用されます。 パラメータはSQL関数定義および準備済み問い合わせの中で使用されます。 また、クライアントライブラリの中には、SQLコマンド文字列とデータ値を分離して指定できる機能をサポートするものもあります。 この場合、パラメータは行外データ値を参照するために使用されます。 パラメータ参照の形式は以下のとおりです。

$number

たとえば、関数 dept の定義が以下のようにされたとします。

CREATE FUNCTION dept(text) RETURNS dept
    AS 'SELECT * FROM dept WHERE name = $1'
    LANGUAGE SQL;

ここで$1は関数が呼び出されるときに最初の関数引数によって置き換えられます。

4.2.3. 添字

配列の値を与える式の場合、特定の配列要素の値は以下のように記述することで展開されます。

expression[subscript]

また、複数の要素を跨る("配列の一部分")場合は以下のように記述することで展開されます。

expression[lower_subscript:upper_subscript]

(ここで大括弧[ ]はリテラルとして現れています。) 各subscriptは自身が式であり、整数値を生成しなければなりません。

一般的には、配列expressionは括弧で括らなければなりませんが、添字がついた式が単なる列参照や位置パラメータであった場合、その括弧を省略することができます。 以下に例を示します。

mytable.arraycolumn[4]
mytable.two_d_column[17][34]
$1[10:42]
(arrayfunction(a,b))[42]

最後の例では括弧が必要です。 配列のより詳細は項8.10を参照してください。

4.2.4. フィールド選択

式が複合型(行型)の値を生成する場合、行の特定のフィールドは以下のように記述することで展開できます。

expression.fieldname

一般的には、行expressionは括弧で括らなければなりません。 しかし、選択元となる式が単なるテーブル参照や位置パラメータの場合、括弧を省略することができます。 以下に例を示します。

mytable.mycolumn
$1.somecolumn
(rowfunction(a,b)).col3

(従って、修飾された列参照は実際の所、単なるこのフィールド選択構文の特殊な場合です。)

4.2.5. 演算子の呼び出し

演算子の呼び出しには以下の3構文が可能です。

expression operator expression (二項中置演算子)
operator expression (単項前置演算子)
expression operator (単項後置演算子)

ここでoperatorトークンは、項4.1.3構文規則に従うもの、もしくはキーワードANDORNOTのいずれか、または以下の形式の修飾された演算子名です。

OPERATOR(schema.operatorname)

具体的にどんな演算子が存在し、それが単項か二項かかどうかは、システムやユーザによってどんな演算子が定義されたかに依存します。 第9章にて、組み込み演算子について説明します。

4.2.6. 関数呼び出し

関数呼び出しの構文は、関数名 (スキーマ名で修飾されている場合があります) に続けてその引数を括弧で囲んで列挙したものです。

function ([expression [, expression ... ]] )

たとえば、以下のものは2の平方根を計算します。

sqrt(2)

組み込み関数のリストは第9章にあります。 他の関数はユーザによって追加できます。

4.2.7. 集約式

集約式は、問い合わせによって選択される行に対して集約関数が適用されることを意味します。 集約関数は、たとえば入力の合計や平均などのように、複数の入力を単一の出力値にします。 集計式の構文は下記のうちのいずれかです。

aggregate_name (expression)
aggregate_name (ALL expression)
aggregate_name (DISTINCT expression)
aggregate_name ( * )

ここで aggregate_name は事前に定義された集約(スキーマ名で修飾された場合もあります)で、expression 自体は集約式を含まない評価式です。

集約式の最初の形式は、指定された式が非null値を返す入力行すべてについての集計を呼び出します。 (実際には NULL 値を無視するかどうかは集約関数によって異なりますが、すべての標準的な集約関数では無視します。) ALLはデフォルトなので、2つ目の形式は最初の形式と同じです。 3番目の形式は、入力行の中にある式の、すべての重複しない、非NULL値の集計を呼び出します。 最後の形式はNULL値か非NULL値かに関わらず、それぞれの入力行に対して1回ずつ集計を呼び出します。 具体的な入力値が指定されていないため、これは一般的にcount()集約関数でのみ役に立ちます。

たとえば、count(*)は入力行の合計数を出します。 count(f1)f1が非NULLである入力行の数を出します。 count(distinct f1)f1の重複しない非NULL値の数を出します。

すでに定義された集約関数は項9.15で説明されています。 他の集約関数はユーザによって追加することができます。

集約式は、SELECTコマンドの結果リストもしくはHAVING句内でのみ現れます。 WHEREなどの他の句では許されません。 これらの句は、ロジック上集計結果が形成される前に評価されるためです。

集約式が副問い合わせ(項4.2.9項9.16参照)内に現れた場合、通常集約は副問い合わせの行全体に対して評価します。 しかし、その集約の引数が上位レベルの変数のみを持つ場合は例外です。 その場合、上位問い合わせの行全体に対して評価します。 全体として、その集約式は、その後、その集約を含む副問い合わせでは外部参照となり、その副問い合わせにおける評価に対しては定数として動作します。 結果リストもしくはHAVING句にのみ現れるという制約は、その集約が属する問い合わせレベルに関連して適用されます。

4.2.8. 型キャスト

型キャストは、あるデータ型から他のデータ型への変換を指定します。 PostgreSQLは型キャストに2つの等価な構文を受け付けます。

CAST ( expression AS type )
expression::type

CAST構文はSQLに準拠したものです。 ::を使用する構文は、PostgreSQLで伝統的に使用されている方法です。

キャストが既知の型の評価式に適用された場合、それは実行時型変換を表します。 このキャストは、適切な型変換関数が使用可能であれば成功します。 項4.1.2.4で示すように、これと定数のキャストの使用との微妙な違いに注意して下さい。 修飾されていない文字列リテラルに対するキャストは、リテラル定数値の初期に割り当てられる型を表します。 ですから、これは(文字列リテラル定数の内容がそのデータ型の入力構文で受け付けられるのであれば)全ての型で成功します。

通常 (たとえば、テーブル列への代入時など)、評価式が生成しなければならない型に曖昧さがない場合、明示的な型キャストは省略することができます。 その場合、システムは自動的に型キャストを適用します。 しかし、自動キャストは、システムカタログに"暗黙的に適用しても問題無し"と示されている場合にのみ実行されます。 その他のキャストは明示的なキャスト構文で呼び出す必要があります。 この制限は、知らないうちに変換が実行されてしまうことを防ぐためのものです。

また、関数のような構文を使用して型キャストを指定することもできます。

typename ( expression )

しかし、これはその型の名前が関数の名前としても有効な場合にのみ動作します。 たとえば、double precision はこの方式で使用できませんが、同等のfloat8は使用できます。 また、intervaltimetimestampという名前は、構文が衝突するため、二重引用符で括った場合にのみこの方式で使用できます。 このように、この関数のようなキャスト構文は一貫性がなくなりがちですので、おそらくは新しいアプリケーションでは使用すべきではありません。 (この関数のような構文は、実際には単なる関数呼び出しです。 2つの標準的なキャスト構文のうちの1つが実行時変換で使用されると、この構文は登録済みの関数を内部的に呼び出して変換を実行します。 慣習的に、これらの変換関数は自身の出力型と同じ名前を持ち、これにより、"関数のような構文"は背後にある変換用関数を直接呼び出す以上のことを行ないません。 移植性をもつアプリケーションが依存すべきものでないことは明確です。)

4.2.9. スカラ副問い合わせ

スカラ副問い合わせは、正確に1行1列を返す、括弧内の通常のSELECT問い合わせです。 (問い合わせの書き方については 第7章 を参照してください。) そのSELECT問い合わせは実行され、返される単一の値はその値の前後の評価式で使用されます。 1行を越える行や1列を越える列がスカラ副問い合わせ用の問い合わせとして使用された場合はエラーになります。 (しかし、ある実行時に、副問い合わせが行を返さない場合でもエラーとはなりません。 そのスカラ結果はNULLとして扱われます。) 副問い合わせは、その回りの問い合わせ内の値を参照することができます。 その値は副問い合わせの評価時には定数として扱われます。 副問い合わせに関する他の式については項9.16 も参照して下さい。

例えば、以下は各州で最も人口の多い都市を検索します。

SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
    FROM states;

4.2.10. 配列コンストラクタ

配列コンストラクタは、各要素用の値より配列値を構築する式です。 単純な配列コンストラクタの構成は、ARRAYキーワード、左大括弧[、(カンマで区切った)配列要素値用の1つ以上の式、最後に右大括弧]です。 以下に例を示します。

SELECT ARRAY[1,2,3+4];
  array
---------
 {1,2,7}
(1 row)

配列要素型は、メンバ式の型と同じで、UNIONCASE構文と同じ規則を使用して決定されます。 (項10.5を参照してください。)

多次元配列値は、配列コンストラクタを入れ子にすることで構築できます。 内側のコンストラクタではARRAYキーワードは省略可能です。 例えば、以下は同じ結果になります。

SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]];
     array
---------------
 {{1,2},{3,4}}
(1 row)

SELECT ARRAY[[1,2],[3,4]];
     array
---------------
 {{1,2},{3,4}}
(1 row)

多次元配列は直交でなければなりませんので、同一レベルの内部コンストラクタは同一次元の副配列を生成しなければなりません。

多次元配列コンストラクタの要素は、副ARRAY構文だけでなく、適切な種類の配列を生成するものをとることができます。 以下に例を示します。

CREATE TABLE arr(f1 int[], f2 int[]);

INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]);

SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr;
                     array
------------------------------------------------
 {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}
(1 row)

また、副問い合わせの結果から配列を構成することも可能です。 この形式の場合、配列コンストラクタはARRAYキーワードの後に括弧(大括弧ではない)で括られた副問い合わせとして記述されます。 以下に例を示します。

SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
                          ?column?
-------------------------------------------------------------
 {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
(1 row)

副問い合わせは単一の列を返さなければなりません。 その結果である一次元配列は、副問い合わせの出力列と一致する型を要素型とした、副問い合わせの結果内の各行を要素としてもちます。

ARRAYで構築された配列値の添字は、常に1から始まります。 配列についての詳細は項8.10を参照してください。

4.2.11. 式の評価規則

副式の評価の順序は定義されていません。 特に演算子や関数の入力は、必ずしも左から右などの決まった順序で評価されるわけではありません。

さらに、その式の一部を評価しただけで式の結果を判断できる場合には、他の副式がまったく評価されないこともあります。 たとえば、

SELECT true OR somefunc();

では、(おそらく) somefunc() は呼び出されないでしょう。 以下の場合も同様です。

SELECT somefunc() OR true;

これは一部のプログラミング言語に見られる、ブーリアン演算子での左から右への"ショートサーキット"とは異なることに注意してください。

そのため、副次作用がある関数を複雑な式の一部として使用することは推奨されません。 特に、WHERE句およびHAVING句で副次作用や評価順に依存するのは危険です。 これらの句は、実行計画を作成する過程で頻繁に再処理されるからです。 これらの句のブール式 (AND/OR/NOT の組み合わせ)は、ブール代数の規則で許されるあるゆる方式で再編成される可能瀬があります。

評価の順序を強制することが重要であれば、CASE構文(項9.12を参照)を使用できます。 たとえば、次の式はWHERE句で0除算を避ける方法としては信頼性の低いものです。

SELECT ... WHERE x <> 0 AND y/x > 1.5;

しかし、次のようにすれば安全です。

SELECT ... WHERE CASE WHEN x <> 0 THEN y/x > 1.5 ELSE false END;

このような方法で使用されるCASE構文は最適化を妨げるものなので、必要な場合にのみ使用してください。 (特に、この例では、y > 1.5*xと代わりに記述することが問題を回避する最善の方法であることに間違いはありません。[訳注:x < 0でないことが前提です。])