testbook

GROUP BY

GROUP BY子句将查询结果按列值并组,也就是指定列列值相同的将被并入同组。GROUP BY常常与聚合函数合用—— 将查询结果按列值并组,然后再对每组分别使用聚合函数。更多关于聚合函数的内容请参考“函数和运算符”下的“聚合函数”章节。 注意:使用GROUP BY时,SELECT语句和GROUP BY子句所包含的列必须相同。

语法

SELECT select_expression, select_expression, ...
GROUP BY groupby_expression [, groupby_expression, ...]
说明

  • select_expression可以是列,表达式,也可以是聚合函数。
  • groupby_expression可以是列,也可以是表达式

  • 单列GROUP BY
    单列GROUP BY就是GROUP BY 子句中只有一列。
  • 举例
    我们可以用对transactions表用GROUP BY查看各个账户进行交易的次数:
    [$host] transwarp> SELECT acc_num, count(trans_id) FROM transactions  GROUP BY acc_num;
    2394923 1
    2755506 1
    6513065 6
    3912384 4
    0700735 3
    6600641 1
    5224133 2
    6670192 2
    
    但是,如果我们想要查看各个账户所有交易的流水号(trans_id),我们不能使用GROUP BY:
    无效代码
    [$host] transwarp> SELECT acc_num, trans_id FROM transactions GROUP BY acc_num;
    [Hive Error]: Query returned non-zero code: 10, cause: FAILED: Error in semantic analysis: Line 1:16 Expression not in GROUP BY key 'trans_id'
    
    上面这段代码是无效的,因为SELECT语句中包含了列trans_id,但是trans_id不包含在GROUP BY子句中。我们看到6513065这个账号进行了6次交易,上面查询要Inceptor为6513065返回一个trans_id值,但是Inceptor不知道应该返回哪一个trans_id,故Inceptor会报错。

  • 举例
    下面代码查看进行了买(b)和卖(s)操作的账户个数。
    [$host]transwarp> SELECT trans_type, count(DISTINCT acc_num) FROM transactions GROUP BY trans_type;
    b       4
    s       8
    
    有4个账户进行了买操作,有8个账户进行了卖操作。注意count(DISTINCT acc_num)中的DISTINCT确保在统计账户个数时,一个acc_num仅统计一次。
    注意:一次查询可以使用多个聚合函数,但是聚合函数的参数中的DISTINCT列必须相同。
  • 多列GROUP BY
    多列GROUP BY就是GROUP BY子句中有不止一列。
    举例
    下例查询各账户进行的买和卖交易各有多少笔:
    [$host] transwarp> SELECT acc_num, trans_type, count(trans_id) FROM transactions GROUP BY acc_num, trans_type;
    2755506 s       1
    6513065 s       2
    6513065 b       4
    0700735 s       2
    2394923 s       1
    3912384 b       2
    3912384 s       2
    5224133 s       1
    5224133 b       1
    0700735 b       1
    6670192 s       2
    6600641 s       1
    
  • 用表达式GROUP BY
    举例
    下例查询2014年各个月份中发生的交易数量。tdh_todate是Inceptor自带的函数,可以用来提取trans_time中的月份:
    [$host]transwarp> SELECT tdh_todate(trans_time, 'yyyyMMddHHmmss', 'MM'), count(trans_id) FROM transactions GROUP BY tdh_todate(trans_time, 'yyyyMMddHHmmss', 'MM');
    09      1
    07      1
    06      2
    05      2
    04      2
    03      4
    02      3
    01      1
    10      1
    08      1
    11      1
    12      1
    
  • 在GROUP BY子句中过滤:HAVING 子句
    如果过滤条件受带GROUP BY的查询结果影响,那么就不能用WHERE子句来过滤,而要用HAVING子句
    语法
    SELECT select_expression, select_expression, ...
    FROM table_name
    GROUP BY groupby_expression, group_expression
    HAVING having_expression
    
    举例
    [$host] transwarp> SELECT acc_num, max(price*amount)
                     > FROM transactions
                     > WHERE trans_time<'20140630235959'
                     > GROUP BY acc_num
                     > HAVING max(price*amount)>5000;
    6513065 12866.0
    5224133 8023.999999999999
    3912384 6843.000000000001
    0700735 5250.0
    
    上例返回所有2014年上半年各账户超过5000元的最大单笔交易额。有两个过滤条件:WHERE子句中的过滤条件和查询结果无关,而HAVING子句中的过滤要在查询结束后才执行。
    注意:在WHERE子句中不能有聚合函数,因为Inceptor在执行GROUP BY子句之前就会执行WHERE子句。
    HAVING子句中可以含有聚合函数:
    [$host] transwarp> SELECT acc_num, max(price*amount)
                               > FROM transactions
                               > WHERE trans_time<'20140630235959'
                               > GROUP BY acc_num
                               > HAVING min(price*amount)>2000;
    3912384 6843.000000000001
    5224133 8023.999999999999
    6670192 4124.0
    
    上面例子查询2014年上半年单笔交易额至少有2000元的各个账户的最大单笔交易额。