評価式は、例えばSELECTコマンドの目的リストとして、INSERTやUPDATEの新しい列の値として、もしくはいくつかのコマンドの検索条件として様々な文脈の中で使われます。 評価式の結果は、テーブル式の結果(つまりテーブル)から区別するために、スカラと呼ばれることもあります。 従って、評価式はスカラ式(もしくはもっと簡単に式)とも呼ばれます。 式の構文によって、算術、論理、集合などの演算を行う基本的な部分で値の計算を行うことができます。
評価式は下記の内のいずれかです。
定数あるいはリテラル値。
列の参照。
関数宣言の本体や準備された文における、位置パラメータ参照。
添字付きの式。
フィールド選択式。
演算子の呼び出し。
関数呼び出し。
集約式。
型キャスト。
スカラ副問い合わせ。
配列コンストラクタ。
行コンストラクタ。
これ以外にも、式として分類されるけれども一般的な構文規約には従わない、いくつかの構成要素があります。 これらは一般的に関数あるいは演算子の意味を持ちます。 第9章の該当部分で説明されています。 例をあげるとIS NULL句があります。
項4.1.2ですでに定数については説明しました。 続く節では残りのオプションについて説明します。
列は、下記のような形式で参照することができます。
correlation.columnname
correlationは、テーブル名(スキーマで修飾されている場合もあります)、FROM句で定義されたテーブルの別名、あるいはNEWまたはOLDというキーワードです。 (NEWとOLDは書き換えルールでしか使用されませんが、他の相関名は全てのSQL文で使用することができます。) 相関名と区切り用のドットは、もし列名が現在の問い合わせで使われる全てのテーブルを通して一意である場合は省略してもかまいません。 (第7章も参照してください。)
位置パラメータ参照は、外部からSQL文に渡される値を示すために使用されます。 パラメータはSQL関数定義および準備された問い合わせの中で使用されます。 また、クライアントライブラリの中には、SQLコマンド文字列とデータ値を分離して指定できる機能をサポートするものもあります。 この場合、パラメータは行外データ値を参照するために使用されます。 パラメータ参照の形式は以下のとおりです。
$number
例えば、関数 dept の定義が以下のようにされたとします。
CREATE FUNCTION dept(text) RETURNS dept AS $$ SELECT * FROM dept WHERE name = $1 $$ LANGUAGE SQL;
ここで$1は関数が呼び出されるときに最初の関数引数によって置き換えられます。
配列の値を与える式の場合、特定の配列要素の値は以下のように記述することで展開されます。
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を参照してください。
式が複合型(行型)の値を生成する場合、行の特定のフィールドは以下のように記述することで展開できます。
expression.fieldname
一般的には、行expressionは括弧で括らなければなりません。 しかし、選択元となる式が単なるテーブル参照や位置パラメータの場合、括弧を省略することができます。 以下に例を示します。
mytable.mycolumn $1.somecolumn (rowfunction(a,b)).col3
(従って、修飾された列参照は実際の所、単なるこのフィールド選択構文の特殊な場合です。)
演算子の呼び出しには以下の3構文が可能です。
expression operator expression (二項中置演算子) |
operator expression (単項前置演算子) |
expression operator (単項後置演算子) |
OPERATOR(schema.operatorname)
具体的にどんな演算子が存在し、それが単項か二項かかどうかは、システムやユーザによってどんな演算子が定義されたかに依存します。 第9章にて、組み込み演算子について説明します。
関数呼び出しの構文は、関数名 (スキーマ名で修飾されている場合があります) に続けてその引数を括弧で囲んで列挙したものです。
function ([expression [, expression ... ]] )
例えば、以下のものは2の平方根を計算します。
sqrt(2)
組み込み関数の一覧は第9章にあります。 他の関数はユーザによって追加できます。
集約式は、問い合わせによって選択される行に対して集約関数が適用されることを意味します。 集約関数は、例えば入力の合計や平均などのように、複数の入力を単一の出力値にします。 集計式の構文は下記の内のいずれかです。
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句にのみ現れるという制約は、その集約が属する問い合わせレベルに関連して適用されます。
型キャストは、あるデータ型から他のデータ型への変換を指定します。 PostgreSQLは型キャストに2つの等価な構文を受け付けます。
CAST ( expression AS type ) expression::type
CAST構文はSQLに準拠したものです。 ::を使用する構文は、PostgreSQLで伝統的に使用されている方法です。
キャストが既知の型の評価式に適用された場合、それは実行時型変換を表します。 このキャストは、適切な型変換操作が定義されている場合のみ成功します。 項4.1.2.5で示すように、これと定数のキャストの使用との微妙な違いに注意してください。 修飾されていない文字列リテラルに対するキャストは、リテラル定数値の初期に割り当てられる型を表します。 ですから、これは(文字列リテラル定数の内容がそのデータ型の入力構文で受け付けられるのであれば)全ての型で成功します。
通常 (例えば、テーブル列への代入時など)、評価式が生成しなければならない型に曖昧さがない場合、明示的な型キャストは省略することができます。 その場合、システムは自動的に型キャストを適用します。 しかし、自動キャストは、システムカタログに"暗黙的に適用しても問題無し"と示されている場合にのみ実行されます。 その他のキャストは明示的なキャスト構文で呼び出す必要があります。 この制限は、知らないうちに変換が実行されてしまうことを防ぐためのものです。
また、関数のような構文を使用して型キャストを指定することもできます。
typename ( expression )
しかし、これはその型の名前が関数の名前としても有効な場合にのみ動作します。 例えば、double precision はこの方式で使用できませんが、同等のfloat8は使用できます。 また、interval、time、timestampという名前は、構文が衝突するため、二重引用符で括った場合にのみこの方式で使用できます。 このように、この関数のようなキャスト構文は一貫性がなくなりがちですので、おそらくは新しいアプリケーションでは使用すべきではありません。 (この関数のような構文は、実際には単なる関数呼び出しです。 2つの標準的なキャスト構文の内の1つが実行時変換で使用されると、この構文は登録済みの関数を内部的に呼び出して変換を実行します。 慣習的に、これらの変換関数は自身の出力型と同じ名前を持ち、これにより、"関数のような構文"は背後にある変換用関数を直接呼び出す以上のことを行ないません。 移植性をもつアプリケーションが依存すべきものでないことは明確です。)
スカラ副問い合わせは、正確に1行1列を返す、括弧内の通常のSELECT問い合わせです。 (問い合わせの記述方法については 第7章 を参照してください。) そのSELECT問い合わせは実行され、返される単一の値はその値の前後の評価式で使用されます。 1行を越える行や1列を越える列がスカラ副問い合わせ用の問い合わせとして使用された場合はエラーになります。 (しかし、ある実行時に、副問い合わせが行を返さない場合でもエラーとはなりません。 そのスカラ結果はNULLとして扱われます。) 副問い合わせは、その回りの問い合わせ内の値を参照することができます。 その値は副問い合わせの評価時には定数として扱われます。 副問い合わせに関する他の式については項9.16 も参照してください。
例えば、以下は各州で最も人口の多い都市を検索します。
SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name) FROM states;
配列コンストラクタは、各要素用の値より配列値を構築する式です。 単純な配列コンストラクタの構成は、ARRAYキーワード、左大括弧[、(カンマで区切った)配列要素値用の1つ以上の式、最後に右大括弧]です。 以下に例を示します。
SELECT ARRAY[1,2,3+4]; array --------- {1,2,7} (1 row)
配列要素型は、メンバ式の型と同じで、UNIONやCASE構文と同じ規則を使用して決定されます。 (項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を参照してください。
行コンストラクタは、そのメンバフィールドの値を使用して行の値(複合値とも呼ばれます)を構築する式です。 行コンストラクタは、ROWキーワード、左括弧、行のフィールド値用の0個以上の式(カンマ区切り)、最後に右括弧から成ります。 以下に例を示します。
SELECT ROW(1,2.5,'this is a test');
ROWキーワードは1つ以上の式がリスト内にある場合は省略することができます。
デフォルトでは、ROW式により作成される値は匿名レコード型になります。 必要に応じて、名前付きの複合型、テーブルの行型、もしくは、CREATE TYPE ASで作成された複合型にキャストすることができます。 明示的なキャストは曖昧性を防止するために必要となることもあります。 以下に例を示します。
CREATE TABLE mytable(f1 int, f2 float, f3 text); CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- getf1()が1つしか存在しないためキャスト不要。 SELECT getf1(ROW(1,2.5,'this is a test')); getf1 ------- 1 (1 row) CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric); CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- ここでは、どの関数を呼び出すのかを示すためにキャストが必要。 SELECT getf1(ROW(1,2.5,'this is a test')); ERROR: function getf1(record) is not unique SELECT getf1(ROW(1,2.5,'this is a test')::mytable); getf1 ------- 1 (1 row) SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype)); getf1 ------- 11 (1 row)
行コンストラクタは、複合型のテーブル列に格納する複合型の値を構築するため、あるいは、複合型のパラメータを受け付ける関数に渡すために使用することができます。 また、以下の例のように、2つの行値を比較することも、IS NULLもしくはIS NOT NULLで行を検査することも可能です。
SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same'); SELECT ROW(a, b, c) IS NOT NULL FROM table;
詳細は項9.17を参照してください。 行コンストラクタは、項9.16で説明した、副問い合わせと一緒に使用することもできます。
副式の評価の順序は定義されていません。 特に演算子や関数の入力は、必ずしも左から右などの決まった順序で評価されるわけではありません。
更に、その式の一部を評価しただけで式の結果を判断できる場合には、他の副式が全く評価されないこともあります。 例えば、
SELECT true OR somefunc();
では、(おそらく) somefunc() は呼び出されないでしょう。 以下の場合も同様です。
SELECT somefunc() OR true;
これは一部のプログラミング言語に見られる、ブーリアン演算子での左から右への"ショートサーキット"とは異なることに注意してください。
そのため、副次作用がある関数を複雑な式の一部として使用することは推奨されません。 特に、WHERE句およびHAVING句で副次作用や評価順に依存するのは危険です。 これらの句は、実行計画を作成する過程で頻繁に再処理されるからです。 これらの句のブール式 (AND/OR/NOT の組み合わせ)は、ブール代数の規則で許されるあらゆる方式で再編成される可能性があります。
評価の順序を強制することが重要であれば、CASE構文(項9.13を参照)を使用できます。 例えば、次の式は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でないことが前提です。])