FOREACH関数は、セットのメンバーごとに計算を実行し、その結果をセットに集約します。
FOREACHは、式を受け入れるEQL文内のコンテキストで使用できます: LET、SELECT、行関数またはアグリゲータ引数、WHERE、HAVINGまたはORDER BY。 FOREACHは常にセットに評価されるため、コンテキストはセット・タイプの式を受け入れる必要があります。そうしないと、EQLでチェック・エラーが発生します。
構文
FOREACH関数の構文は、次のとおりです:
FOREACH id_1 IN set_1[, id_n IN set_n] RETURN(expression)説明:
expressionはEQL式です。 式はカッコで囲み、RETURNキーワードが必須です。 idパラメータの数に関係なく、関数にはRETURNを1つのみ含める必要があります。
少なくとも1つの識別子/セット・ペア(id IN set)とRETURN式を指定する必要があります。
スコープとシャドウ
FOREACHでは、RETURN式内でid_n識別子を使用してid_1がバインドされます。set_1からset_nまでの範囲ではありません。 これらのバインディングにより、FOREACH関数のポイントでスコープ内に存在する可能性のあるid_nを通じて、id_1のその他のバインドがシャドウ化されます。
EVERYおよびSOMEの数量詞と同様に、EQLでは、バインドされた変数への参照をデータソースの別名で修飾することはできません。 たとえば、次の文を考えてみます:
RETURN results AS
SELECT
Source.x AS x,
FOREACH x IN {1, 2}, y in {3, 4} RETURN (results.x + Source.y) AS vals
FROM Source
EQLでは、results.xへの参照が(FOREACH RETURN式で) SELECT句によって定義されたxへの参照として(つまり、Source.xの別名として、FOREACHによりバインドされたxへの参照としてではありません)解釈されます。 同様に、EQLでは参照Source.yが「ソース」の属性yへの参照として解釈されます。
RETURN results AS
SELECT
Source.x AS x,
FOREACH x IN {1, 2}, y in {3, 4} RETURN (x + y) AS vals
FROM Source
その後、EQLはxとy (FOREACH RETURN式内)をFOREACHでバインドされた識別子への参照として解釈しますが、xとyは以前のSELECTからのスコープですでに存在します。 したがって、「値」では常に値 {4, 5, 6}が設定されます。
タイプ
FOREACH構文では、set_1 through set_nはsetデータ型(mdex:string-setなど)である必要があります。EQLはエラーを通知します。それ以外の場合はエラーを発行します。 対応するx_1からx_nへの識別子は、これらのセットの要素のタイプを持つ必要があります。 例として、次の例を考えてみます:
FOREACH x IN {1, 2}, y IN {'abc', 'def'} RETURN (x + y)
ここで、最初の汎用は整数のセットであるため、xはRETURN式に整数のタイプを持っています。 同様に、2番目の汎用は文字列のセットであるため、yには型文字列があります。 その結果、RETURN式x + yは不正タイプになる(それに応じてEQLによってエラーが発行される)ようになります。
RETURN式にアトミック・タイプtが含まれる場合、FOREACH式全体のタイプはtになります。 したがって、RETURN式に型整数が指定されている場合、その式を構成するFOREACH式には、型整数が設定されます。
一方、RETURN式にセット・タイプがある場合、FOREACH式はRETURN式と同じタイプになります。 (これは、FOREACHがRETURN式の値を結合する場合に対応します。) そのため、RETURN式で文字列のセットが生成される場合、FOREACH式でも同じように処理されます。
FOREACHと集計
FOREACH式は、グループ化前とグループ化後の両方の計算(WHERE、HAVINGおよびORDER BYの各句を含む)に表示できます。 次に、数量式(EVERYおよびSOME)が行うのとほとんど同じ方法で集計と対話します:
FOREACH式は、アグリゲータ引数内に表示できます:
RETURN results AS
SELECT
SET_UNIONS(FOREACH x IN e RETURN(b)) AS unions
FROM Source
GROUP
FOREACHとそのバウンド変数の間に表示できません。 つまり、次のものは無効であり、EQLによってエラーが通知されます:
FOREACH x IN e RETURN(SUM(x))
操作の詳細
FOREACHの動作を説明するために、簡単な例を使用します:
FOREACH x IN {1, 2, 3} RETURN(x * 2 + 1)
この式はセット {3, 5, 7}として評価されます。 これは、暗黙的に、EQLはセット {1, 2, 3}の各メンバーに対してRETURN式x * 2 + 1を1回評価し、xでそのセットの各要素を順番に取得するためです。 最後に、EQLはこれらの評価の結果を別のセットにアセンブルします。
汎用性と結果はどちらもセットであるため、トラバースが汎用の要素を訪問する順序、または最終セットに結果値が出現する順序は指定できません。
FOREACHを使用して、複数セットを反復処理することもできます:
FOREACH x IN {1, 2, 3}, y IN {40, 50, 60} RETURN(x + y)
この式は、セット {41, 42, 43, 51, 52, 53, 61, 62, 63}に評価されます。 ここで、EQLは2つのセットの値xとyのすべての組合せについてRETURN式x + yを評価します:
x = 1, y = 40: x + y = 41 x = 2, y = 40: x + y = 42 x = 3, y = 40: x + y = 43 x = 1, y = 50: x + y = 51 ... x = 3, y = 60: x + y = 63
FOREACH式の結果が重複(または汎用のクロス積)より小さくなる場合があります:
FOREACH x IN {-1, 1, 2} RETURN (ABS(x)) // returns {1, 2}
FOREACH x IN {'3', '4', 'y'} RETURN (TO_STRING(x)) // returns {3, 4}
最初の例では、ABS(-1) = ABS(1) = 1,であるため、最後のセットには2つの要素のみが含まれます。値1は2回出現しない場合があります。 2番目の例では、TO_INTEGER('x')がNULLであるため、この値は最後のセットには出現しません。
RETURN式自体で(単一の値ではなく)セットが生成される場合、FOREACHは前述のように評価しますが、すべてのRETURNセットの結合を最終結果として計算します。 次に例を示します。
FOREACH x in {3, 4, 5}, y IN {-1, 0, 2} RETURN ({x + y, x - y})
// Note: "body" is the RETURN expression
| x | y | body |
------------------
| 3 | -1 | {2,4} |
| 3 | 0 | {3} |
| 3 | 2 | {1,5} |
| 4 | -1 | {3,5} |
| 4 | 0 | {4} |
| 4 | 2 | {2,6} |
| 5 | -1 | {4,6} |
| 5 | 0 | {5} |
| 5 | 2 | {3,7} |
------------------
body列内のすべてのセットのユニオンを計算すると、最終的な結果が得られます。
| xs | ys |
-----------------
| {1,2} | {3} |
| {} | {4,5} |
| {6} | {} |
-----------------
RETURN results AS
SELECT
xs,
ys,
FOREACH x IN xs, y IN ys RETURN (x + y) AS zs
FROM InputState
| xs | ys | zs |
-------------------------
| {1,2} | {3} | {4,5} |
| {} | {4,5} | {} |
| {6} | {} | {} |
-------------------------
FOREACHの例
RETURN式が各スコア・セットの値のみを返すため、FOREACH式の最も単純な例の1つです:
RETURN Results AS SELECT WineID AS id, FOREACH x IN Score RETURN(x) AS ratings FROM WineState ORDER BY id
RETURN Results AS SELECT WineID AS id, FOREACH x IN Body, y IN Flavors RETURN (CONCAT(x, ' ', y)) AS bodyflavor FROM WineState WHERE IS_NOT_EMPTY(Body) AND IS_NOT_EMPTY(Flavors) ORDER BY id
空のセットが選択されないように、WHERE句では2つのIS_NOT_EMPTY関数が使用されています。
LETとFOREACHの両方を使用し、RETURN式では、EXTRACT関数も使用しています:
RETURN Results AS LET (FOREACH d IN ShipDate RETURN (EXTRACT(d, YEAR))) AS yearSet SELECT SET(Price) AS prices FROM WineState GROUP BY MEMBERS(yearSet) AS shipyear
RETURN式内でのみ表示され、その式内で同じ名前を持つ他の属性の影が表示されます。 yearSetはSELECT句ではなくLET句で定義されるため、文の結果には表示されません。