一、SQL与Sequelize中的分组查询

1.1 SQL中的分组查询

SQL查询中,通 GROUP BY 语名实现分组查询。 GROUP BY 子句要和聚合函数配合使用才能完成分组查询,在 SELECT 查询的字段中,如果没有使用聚合函数就必须出现在 ORDER BY 子句中。分组查询后,查询结果为一个或多个列分组后的结果集。

GROUP BY 语法

GROUP BY 子名-用于指定分组的字段

HAVING 子名-用于过滤分组结果,符合条件表达式的结果将会被显示

WITH ROLLUP 子名-用于指定追加一条记录,用于汇总前面的数据

1.2 Sequelize中的分组查询

使用聚合函数

Sequelize提供了聚合函数,可以直接对模型进行聚合查询:

  • aggregate(field, aggregateFunction, [options])-通过指定的聚合函数进行查询
  • sum(field, [options])-求和
  • count(field, [options])-统计查询结果数
  • max(field, [options])-查询最大值
  • min(field, [options])-查询最小值
  • 以上这些聚合函数中,可以通过 options.attributes options.attributes 属性指定分组相关字段,并可以通过 options.having 指定过滤条件,但没有直接指定 WITH ROLLUP 子句的参数。

    如,使用 .sum() 查询订单数量大于1的用户订单额:

    Order.sum( 'price' , {attributes:[ 'name' ], group: 'name' , plain: false , having:[ 'COUNT(?)>?' , 'name' , 1]}).then( function (result){
    console.log(result);

    使用聚合参数

    除直接使用聚合函数外,也可以在 findAll() 等方法中,指定聚合查询相关参数实现聚合查询。查询时,同样可以通过通过 options.attributes options.attributes 属性指定分组相关字段,并可以通过 options.having 指定过滤条件。与直接使用聚合函数查询不一样,通过参数构建聚合查询时,要以数组或对象形式设置 options.attributes 参数中的聚合字段,并需要通过 sequelize.fn() 方法传入聚合函数。

    如,使用 .findAll() 查询订单数量大于1的用户订单额:

    Order.findAll({attributes:[ 'name' , [sequelize.fn( 'SUM' , sequelize.col( 'price' )), 'sum' ]], group: 'name' , having:[ 'COUNT(?)>?' , 'name' , 1], raw: true }).then( function (result){
    console.log(result);
    > select * from orders;
    + ---------+-------------+--------+-----------+---------------------+
    | orderId | orderNumber | price | name | createdOn   |
    + ---------+-------------+--------+-----------+---------------------+
    |  1 | 00001  | 128.00 | 张小三 | 2016-11-25 10:12:49 |
    |  2 | 00002  | 102.00 | 张小三 | 2016-11-25 10:12:49 |
    |  4 | 00004  | 99.00 | 王小五 | 2016-11-25 10:12:49 |
    |  3 | 00003  | 199.00 | 赵小六 | 2016-11-25 10:12:49 |
    + ---------+-------------+--------+-----------+---------------------+
    > select name , SUM (price) from orders GROUP BY name ;
    + -----------+------------+
    | name | SUM (price) |
    + -----------+------------+
    | 张小三 |  230.00 |
    | 王小五 |  99.00 |
    | 赵小六 |  199.00 |
    + -----------+------------+
    Order.findAll({attributes:[ 'sum' , [sequelize.fn( 'SUM' , sequelize.col( 'name' )), 'sum' ]], group: 'name' , raw: true }).then( function (result){
    console.log(result);
    > select name , SUM (price) from orders GROUP BY name HAVING count (1)>1;
    + -----------+------------+
    | name | SUM (price) |
    + -----------+------------+
    | 张小三 |  230.00 |
    | 赵小六 |  199.00 |
    + -----------+------------+
    Order.findAll({attributes:[ 'sum' , [sequelize.fn( 'SUM' , sequelize.col( 'name' )), 'sum' ]], group: 'name' , having:[ 'COUNT(?)>?' , 'name' , 1], raw: true }).then( function (result){
    console.log(result);
    > select name , SUM (price) from orders GROUP BY name WITH ROLLUP ;
    + -----------+------------+
    | name | SUM (price) |
    + -----------+------------+
    | 张小三 |  230.00 |
    | 王小五 |  99.00 |
    | 赵小六 |  199.00 |
    | NULL |  528.00 |
    + -----------+------------+

    2.4 连接查询与分组

    为了管理方便,我们会将不同的信息保存在不同的表中。如,我们会将订单信息放在一张表中,而将客户信息保存在另一张表中。对于存在关联关系的两张表,我们会使用连接查询来查找关联数据,在进行连接查询时,同样可以以使用聚合函数。

    订单表如下:

    > select * from orders;
    + ---------+-------------+--------+------------+---------------------+
    | orderId | orderNumber | price | customerId | createdOn   |
    + ---------+-------------+--------+------------+---------------------+
    |  1 | 00001  | 128.00 |   1 | 2016-11-25 10:12:49 |
    |  2 | 00002  | 102.00 |   1 | 2016-11-25 10:12:49 |
    |  3 | 00003  | 199.00 |   4 | 2016-11-25 10:12:49 |
    |  4 | 00004  | 99.00 |   3 | 2016-11-25 10:12:49 |
    + ---------+-------------+--------+------------+---------------------+
    > select * from customers;
    + ----+-----------+-----+---------------------+---------------------+
    | id | name | sex | birthday   | createdOn   |
    + ----+-----------+-----+---------------------+---------------------+
    | 1 | 张小三 | 1 | 1986-01-22 08:00:00 | 2016-11-25 10:16:35 |
    | 2 | 李小四 | 2 | 1987-11-12 08:00:00 | 2016-11-25 10:16:35 |
    | 3 | 王小五 | 1 | 1988-03-08 08:00:00 | 2016-11-25 10:16:35 |
    | 4 | 赵小六 | 1 | 1989-08-11 08:00:00 | 2016-11-25 10:16:35 |
    + ----+-----------+-----+---------------------+---------------------+
    attributes: [ 'name' ],
    Order.findAll({include:include, attributes:[[sequelize.fn( 'SUM' , sequelize.col( 'price' )), 'sum' ]], group: 'Customer.name' , having:[ 'COUNT(?)>?' , 'name' , 1], raw: true , rollup: true }).then( function (result){
    console.log(result);