MEMBERS拡張

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

MEMBERSを使用すると、複数割当て属性によりグルーピングできます。複数割当て属性によるグルーピングの際には、属性が割り当てられていない行はグルーピング時に破棄されることに注意してください。

MEMBERSの構文

MEMBERSGROUP BY句の中に出現し、次の構文が使用されます。
GROUP BY MEMBERS(<set>) AS <alias> [,MEMBERS(<set2>) AS <alias2>]*
ここで、
  • setはセット・データ型の1つのセットであり(mdex:string-setmdex:double-setなど)、属性参照にする必要があります。MEMBERSは、ソース文またはコーパスからの属性のみを参照できます(つまり、ローカルには定義できません)。たとえば、setは、コーパスからの複数割当ての文字列属性にすることができます。
  • aliasは別名で、NCNameに準拠している必要があります。文の結果では、別名はセットの要素と同じデータ型を持っています。

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

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

コーパス間のメンバーだけではなく、セットのメンバーによるグルーピングも任意の文で使用可能です(これは、EQLがセット内の文境界にわたるすべての値を保存しているためです)。

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

MEMBERSへの引数として単一割当て属性を使用しようとすると、次の例のようなエラー・メッセージが返されます。
Cannot apply MEMBERS to mdex:double. A set type is required 

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

MEMBERSの例

25レコードの小規模なデータ・セットがあり、各レコードにはBody複数割当て属性が割り当てられていないか、あるいは1つまたは2つ割り当てられているとします。このサンプル問合せでは、WineIDは単一割当て属性です。
RETURN results AS
  SELECT
    SET(WineID) AS IDs
  GROUP BY MEMBERS(Body) AS bodyType
この文の結果は次のようになります。
IDs                                          bodyType
-------------------------------------------------------
| { 19 }                                    | Fresh   |
| { 22, 25 }                                | Firm    |
| { 14, 15 }                                | Supple  |
| { 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   |
-------------------------------------------------------

結果を見ると、いくつかのレコードに2つのBodyが割り当てられているため、それらのレコードが複数のバケットの対象となっています。また、5つのレコードにはBody属性が割り当てられていないため、バケットの対象とはならず、これらのレコードはグルーピング時に破棄されます。

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

WineID=25であるレコードは、{Firm、Robust}と{82、84}のクロス積に対応して、4つのバケットの対象となっています。

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

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

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

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

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

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

ただし、最初の3行のtotalPriceを加算すると、予期される値97.97ではなく、129.96が得られます。この相違が生じる理由は、セットのメンバーによるグルーピングを行った際に、1行が複数のバケットの対象となってしまったためです。特に、レコード19には2個のBody (FreshおよびRobust)が割り当てられているため、(White、Fresh)と(White、Robust)の両方の行の対象となってしまい、実際にその価格が二重に数えられています。同様に、レコード20にはBodyが割り当てられていないため、bodyTypeがNULLではないいずれのバケットの対象ともなっていません。これは、Bodyの値が空のセットであるためです。

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