GROUP句/GROUP BY句

GROUP句およびGROUP BY句では、文の出力をグルーピングするためにソース・レコードをどのように結果レコードにマッピングするかを指定します。

これらの句を問合せで使用するには、次のような方法があります。

その他のグルーピング関数(たとえば、CUBEGROUPING SETS)も、GROUP句やGROUP BY句とともに使用できます。このような関数の詳細は、この章で後述します。

グルーピングのためのBNF文法

BNF文法によるGROUPおよびグルーピング関数ファミリの表記は次のとおりです。
GroupByList ::= GROUP | GROUP BY GroupByList_ | GROUP BY GroupAll
GroupByList_ ::= GroupByElement | GroupByList_ ,  GroupByElement
GroupByElement ::= GroupBySingle | GroupingSets | CubeRollup

GroupingSets ::= GROUPING SETS (GroupingSetList)
GroupingSetList ::=  GroupingSetElement |  GroupingSetList ,  GroupingSetElement
GroupingSetElement ::=  GroupBySingle | GroupByComposite | CubeRollup | GroupAll

CubeRollup ::= {CUBE | ROLLUP} (CubeRollupList)
CubeRollupList ::=  CubeRollupElement |  CubeRollupList ,  CubeRollupElement
CubeRollupElement ::=  GroupBySingle | GroupByComposite

GroupBySingle ::= Identifier
GroupByComposite ::= (GroupByCompositeList)
GroupByCompositeList ::= GroupBySingle | GroupByCompositeList, GroupBySingle

GroupAll ::= ()
GroupAllを使用すると、次に示すものがすべて等価になることに注意してください。
GROUP = GROUP BY() = GROUP BY GROUPING SETS(())

GROUPのみを指定

GROUP句を使用すると、結果を集計して1つのバケットを作成できます。BNF文法が示すように、GROUP句は引数を取りません。

たとえば、次に示す文ではSUM文を使用してレコードのセット全体の合計を1つのみ返します。
RETURN ReviewCount AS 
SELECT SUM(NumReviews) AS NumberOfReviews
GROUP

この文が返すのは、NumberOfReviewsのレコード1つです。値は、NumReviews属性の値の合計です。

GROUP BYの指定

GROUP BYを使用すると、グルーピング・キーの値が同じである結果を集計してバケットを作成できます。GROUP BYの構文は次のとおりです。
GROUP BY(attributeList)
attributeListは、単一の属性、カンマ区切りの複数属性リスト、GROUPING SETSCUBEまたはROLLUPです。()を指定すると、空のグループを指定したことになります。空のグループを指定すると、合計が生成されます。

グルーピングは、ソースおよびローカルで定義された属性に対して実行できます。

注意: ローカル定義された属性でグルーピングする場合は、その属性は非グルーピング属性を参照することはできず、その属性に集計を含めることはできません。ただし、LOOKUP式とIN式は、このコンテキストでは有効です。

グルーピング属性はすべて、結果レコードに含まれます。グルーピング属性のNULL値は、他の値と同様に扱われます。つまり、ソース・レコードは結果レコードにマッピングされます。(ただし、コーパスから選択する場合はNULL値は無視されます。)EQLでのユーザー定義のNULL値の扱いの詳細は、COALESCEを参照してください。

たとえば、販売トランザクション・データのレコードが、次の属性で構成されているとします。
{ TransId, ProductType, Amount, Year, Quarter, Region,
  SalesRep, Customer }
次に例を示します。
{ TransId = 1, ProductType = "Widget", Amount = 100.00,
  Year = 2011, Quarter = "11Q1", Region  = "East",
  SalesRep = "J. Smith", Customer = "Customer1" }
EQL文でRegionとYearをGROUP BYの属性として使用する場合は、文の結果には、有効で、空ではないRegionとYearの各組合せからなる、集計レコードが出力されます。EQLでは、この例は次のように表現されます。
DEFINE RegionsByYear AS
GROUP BY Region, Year
この結果は、{ Region, Year }という形式の集計です。次に例を示します。
{ "East", "2010" }
{ "West", "2011" }
{ "East", "2011" }
GROUP BY句の中では、同じ列を重複して使用できることに注意してください。つまり、次の2つの問合せは、等価として扱われます。
RETURN Results AS
SELECT SUM(PROMO_COST) AS PR_Cost
GROUP BY PROMO_NAME

RETURN Results AS
SELECT SUM(PROMO_COST) AS PR_Cost
GROUP BY PROMO_NAME, PROMO_NAME

SELECT式の出力であるGROUP BYの使用

GROUP BYのキーは、SELECT式の出力であってもかまいません。ただし、その式自体に集計関数が含まれていないことが条件です。

たとえば、次に示す構文はGROUP BYの正しい使用法です。
SELECT COALESCE(Person, 'Unknown Person') AS Person2, ... GROUP BY Person2
次に示す構文は間違っているため、結果はエラーになります。Sales2の中に集計関数(SUM)があるからです。
SELECT SUM(Sales) AS Sales2, ... GROUP BY Sales2

管理対象属性の階層レベルの指定

各管理対象属性の指定した深さでグルーピングできます。ただし、GROUP BY文ではANCESTOR関数は使用できません(EQLでは式のグルーピングができないからです)。したがって、最初にANCESTORSELECT文とともに使用してから、別名を付けた結果をGROUP BY句の中で指定します。

たとえば、Region属性の中にCountry、State、Cityの階層があるとします。結果のグルーピングを、Stateレベル(管理対象属性階層のルートの1レベル下)で行うとします。省略形の問合せを次に示します。
SELECT ANCESTOR("Region", 1) AS StateInfo
...
GROUP BY StateInfo

複数割当て属性によるグルーピング

複数割当て属性でグルーピングする場合は、1つのソース・レコードが、対応する複数の出力レコードにマッピングされます。たとえば、レコード[A:1, A:2, B:3, B:4, B:5]のマッピング先は次のようになります。
  • Aでグルーピングする場合は、2つの出力レコード
  • Bでグルーピングする場合は、3つの出力レコード
  • AとBの両方でグルーピングする場合は、6つの出力レコード
  • SELECT A + B AS C GROUP BY Cの場合は6つの出力レコード。A + Bについて考えられる6個の値すべてがグルーピングの前に計算されるからです。

これが発生する可能性があるのはコーパス・ソースに対してのみです。結果レコードは常に単一割当てであるからです。

この例では、UserTagは複数割当てです。
RETURN "Example" AS SELECT
   AVG("Gross") AS "AvgGross",
   SUM("Gross") AS "TotalGross"
GROUP BY UserTag

結果バケットのセットを定義するには、文でGROUP BY属性のセットを指定する必要があります。これらのグルーピング属性のすべての値のクロス積によって、候補バケットのセットが定義されます。

結果には空ではないバケットのみが含まれるように、自動的に切り捨てられます。

属性参照が出現するのが、GROUP句の中ではなく、属性定義の中でGROUP句を持つ文である場合は、その属性には暗黙的にARB集計が適用されます。