MEMBERS拡張

MEMBERSGROUP BYに対する1つの拡張であり、セットのメンバーによるグルーピングを使用できます。

MEMBERSを使用すると、複数割当て属性によりグルーピングできます。複数割当て属性によるグルーピングの際には、すべての行(属性に割当てがない行を含む)が保持されることに注意してください。

MEMBERSの構文

MEMBERSGROUP BY句の中に出現し、次の構文が使用されます。
GROUP BY MEMBERS(<set>) AS <alias> [,MEMBERS(<set2>) AS <alias2>]*
ここで、
  • setはセット・データ型の1つのセットであり(mdex:string-setmdex:long-setなど)、属性参照にする必要があります。たとえば、setは、指定したコレクションからの複数割当ての文字列属性にすることができます。

    LETが使用されていない場合、MEMBERSはソース文またはコレクションの属性のみ(つまり、ローカル定義ではない)を参照できます。LETが使用されている場合、MEMBERSで同じ文内で定義されている属性(属性がSELECT句ではなく、LET句で定義されている場合)を参照できます。

  • aliasは別名で、NCNameに準拠している必要があります。文の結果では、別名はセットの要素と同じデータ型を持っています。

構文に示したように、EQLは同時に複数セットのメンバーによるグルーピングをサポートしています。これを行うには、複数のMEMBERS句を1つのGROUPリストに含めるだけです。

MEMBERS形式はグルーピング・セットで使用可能で、次のような表層構文を使用します。
GROUP BY ROLLUP(a, b, MEMBERS(c) AS cValue, d)

セットのメンバーによるグルーピングは、1つのコレクションに対するものだけでなく任意の文で使用可能です(これは、EQLがセット内のすべての値を文境界を越えて保持するためです)。

MEMBERSデータ型のエラー・メッセージ

MEMBERSへの引数として単一割当て属性を使用しようとすると、次の例のようなエラー・メッセージが返されます。
Argument to MEMBERS has type mdex:double; only set types are permitted.

このエラーの例では、MEMBERSが複数割当てのdouble属性(mdex:double-set)ではなく、単一割当てのdouble属性(mdex:double)で使用されています。

MEMBERSの例

25レコードの小規模なデータ・セットがあり、各レコードにはBody複数割当て属性が割り当てられていないか、あるいは1つまたは2つ割り当てられているとします。WineIDは単一割当て属性で、Wineコレクションのキーです。次のサンプル問合せをします。
RETURN Results AS
SELECT
  SET(WineID) AS IDs
FROM WineState
GROUP BY MEMBERS(Body) AS bodyType
この文の結果は次のようになります。
IDs                                          bodyType
-------------------------------------------------------
| { 14, 15 }                                | Supple  |
| { 22, 25 }                                | Firm    |
| { 19 }                                    | Fresh   |
| { 11, 19, 22, 23, 24, 25, 4, 6, 8 }       | Robust  |
| { 10, 11, 12, 13, 16, 18, 3, 4, 5, 7, 9 } | Tannins |
| { 10, 12, 13, 16, 18, 3, 5, 7, 9 }        | Silky   |
| { 1, 17, 2, 20, 21 }                      |         |
-------------------------------------------------------

結果を見ると、いくつかのレコードに2つのBodyが割り当てられているため、それらのレコードが複数のバケットの対象となっています。結果の最後の5つのレコードにはBody属性が割り当てられていませんが、グルーピング時に破棄されず、NULLのbodyTypeでリストされます。(WineIDを使用することで、IDセット内の値が表示され、どの入力行がどの出力行に含まれるかを確認できます。たとえば、レコード4はRobustとTanninsの両方に含まれ、レコード14はSuppleにのみ含まれます。レコード16はTanninsとSilkyに含まれます。)

この2番目の例では、同時に複数セットのメンバーによるグルーピングを行う方法を示しています。マルチ割当て属性のBodyおよびScoreが、単一割当て属性WineTypeと同様に問合せに使用されています。
RETURN Results AS
SELECT
  SET(WineID) as IDs
FROM WineState
WHERE WineType = 'White'
GROUP BY MEMBERS(Body) AS bodyType, MEMBERS(Score) AS scoreValue
この問合せの結果は次のようになります。
IDs      bodyType  scoreValue
------------------------
| { 25 } | Firm   | 82 |
| { 25 } | Firm   | 84 |
| { 19 } | Fresh  | 88 |
| { 25 } | Robust | 82 |
| { 25 } | Robust | 84 |
| { 19 } | Robust | 88 |
| { 20 } |        | 71 |
| { 20 } |        | 75 |
| { 21 } |        | 87 |
| { 21 } |        | 89 |
------------------------

WineID=25であるレコードは、{Firm、Robust}と{82、84}のクロス積に対応して、4つのバケットの対象となっています。レコード20および21は、Score属性は割り当てられていますが、Body属性は割り当てられていないため、bodyTypeはNULLでscoreValueは各値でリストされています。

MEMBERSとGROUPING SETSの対話に関する注意

セット・メンバーによるグルーピングはGROUPING SETS (CUBEROLLUPを含む)と対話して、一見したところ予期していないような結果を生成する場合があることに注意してください。

たとえば、最初にROLLUP拡張のみによるグルーピングを行う問合せを実行するとします。
RETURN Results AS
SELECT
  SUM(Price) AS totalPrice
FROM WineState
GROUP BY ROLLUP(WineType)
現在のデータ・セットでの結果は次のようになります。
WineType          totalPrice
----------------------------
| Blanc de Noirs  |  16.99 |
| Brut            |  46.98 |
| Zinfandel       |        |
| Merlot          |  25.99 |
| Bordeaux        |  21.99 |
| Chardonnay      |  52.90 |
| White           |  97.97 |
| Pinot Noir      |  14.99 |
| Red             | 142.34 |
|                 | 420.15 |
----------------------------

各WineType対して1行が割り当てられ、1番下にはサマリーを示す行があります。結果には、すべてのWineType値に対するレコードが含まれています。SUMは結合であるため、予期される動作は、totalPriceのサマリー行がその他すべての行のtotalPrice値の合計と等しくなることであり、実際に420.15は予期した結果に一致しています。(Whiteワインの合計は97.97です。)

次に同様の問合せを実行しますが、今度はWhiteワインのみを選択してMEMBERSROLLUPでグルーピングを行います。
RETURN Results AS
SELECT
  SUM(Price) AS totalPrice
FROM WineState
WHERE WineType = 'White'
GROUP BY ROLLUP(WineType, MEMBERS(Body) AS bodyType)
この2番目の問合せの結果は次のようになります。
WineType bodyType totalPrice
--------------------------
| White | Firm   | 43.99 |
| White | Fresh  | 20.99 |
| White | Robust | 64.98 |
| White |        | 32.99 |
| White |        | 97.97 |
|       |        | 97.97 |
--------------------------

この場合、サマリー行と個別の行の間の対応関係が予期した結果になっていません。'White'のサマリー行(つまり、WineTypeがWhiteでbodyTypeがNULLである行)のtotalPriceが、その行より上の(White、Firm)、(White、Fresh)および(White、Robust)の各行のtotalPriceの合計になると予期したはずです。

しかし、最初の4行の合計金額を加算すると、予期される値97.97ではなく、162.95になります。この相違が生じる理由は、セットのメンバーによるグルーピングを行った際に、1行が複数のバケットの対象となってしまったためです。特に、レコード19には2個のBody (FreshおよびRobust)が割り当てられているため、(White、Fresh)と(White、Robust)の両方の行の対象となってしまい、実際にその価格が二重に数えられています。

ただし、EQLがWineType (単一割当て属性)によるグルーピングを行って'White'のサマリー行を効率的に計算しているため、各入力行は正確に1度だけ数えられます。