Sequelize中用group by进行分组聚合查询


Posted in Javascript onDecember 12, 2016

一、SQL与Sequelize中的分组查询

1.1 SQL中的分组查询

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

GROUP BY语法

SELECT 列名, 聚合函数(列名)
FROM 表名
WHERE 列名 operator value
GROUP BY 列名 
[HAVING 条件表达式] [WITH ROLLUP]

在以上语句中:

聚合函数 - 分组查询通常要与聚合函数一起使用,聚合函数包括:

  •      COUNT()-用于统计记录条数
  •      SUM()-用于计算字段的值的总和
  •      AVG()-用于计算字段的值的平均值
  •      MAX-用于查找查询字段的最大值
  •      MIX-用于查找查询字段的最小值

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

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

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

1.2 Sequelize中的分组查询

使用聚合函数

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

  1. aggregate(field, aggregateFunction, [options])-通过指定的聚合函数进行查询
  2. sum(field, [options])-求和
  3. count(field, [options])-统计查询结果数
  4. max(field, [options])-查询最大值
  5. min(field, [options])-查询最小值

以上这些聚合函数中,可以通过options.attributesoptions.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);
})

生成的SQL语句如下:

SELECT `name`, sum(`price`) AS `sum` FROM `orders` AS `Orders` GROUP BY name HAVING COUNT('name')>1;

使用聚合参数

除直接使用聚合函数外,也可以在findAll()等方法中,指定聚合查询相关参数实现聚合查询。查询时,同样可以通过通过options.attributesoptions.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);
})

生成的SQL语句如下:

SELECT `name`, sum(`price`) AS `sum` FROM `orders` AS `Orders` GROUP BY name HAVING COUNT('name')>1;

二、使用示例

现在订单表,数据如下:

> 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 |
+---------+-------------+--------+-----------+---------------------+

2.1 简单使用

使用分组查询,统计每个客户的订单总额。

使用SQL语句,可以像下面这样查询:

> select name, SUM(price) from orders GROUP BY name;
+-----------+------------+
| name  | SUM(price) |
+-----------+------------+
| 张小三 |  230.00 |
| 王小五 |  99.00 |
| 赵小六 |  199.00 |
+-----------+------------+

而在Sequelize中可以像下面这样实现:

Order.findAll({attributes:['sum', [sequelize.fn('SUM', sequelize.col('name')), 'sum']], group:'name', raw:true}).then(function(result){
 console.log(result);
})

2.2 使用HAVING子句

统计订单数量大于1的用户的订单总金额。

使用SQL语句,可以像下面这样实现:

> select name, SUM(price) from orders GROUP BY name HAVING count(1)>1;
+-----------+------------+
| name  | SUM(price) |
+-----------+------------+
| 张小三 |  230.00 |
| 赵小六 |  199.00 |
+-----------+------------+

而使用Sequelize可以像下面这样查询:

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);
})

2.3 使用WITH ROLLUP子句

WITH ROLLUP子句是MySQL 5.5+新增的特性,用于汇总统计结果。但本文发布时,Sequelize还不支持该特性。

增加总和统计列:

> 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 |
+----+-----------+-----+---------------------+---------------------+

使用连接查询并分组查询,统计每个客户的订单总额。

使用SQL语句查询如下:

> select c.name, SUM(o.price) AS sum from customers AS c INNER JOIN orders AS o ON o.customerId =c.id GROUP BY c.name;

Sequelize中进行连接查询时,首先需要建立模型间的关联关系:

Order.belongsTo(Customer, {foreignKey: 'customerId'});

连接查询及分组:

var include = [{
 model: Customer,
 required: true,
 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);
})

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
关于textarea提交的内容无法换行的解决办法
Apr 09 Javascript
JS操作JSON要领详细总结
Aug 25 Javascript
jQuery事件绑定on()、bind()与delegate() 方法详解
Jun 03 Javascript
jQuery代码实现发展历程时间轴特效
Jul 30 Javascript
用JavaScript实现PHP的urlencode与urldecode函数
Aug 13 Javascript
js自定义回调函数
Dec 13 Javascript
基于JavaScript实现智能右键菜单
Mar 02 Javascript
Bootstrap Table中的多选框删除功能
Jul 15 Javascript
微信小程序form表单组件示例代码
Jul 15 Javascript
Vue 配合eiement动态路由,权限验证的方法
Sep 26 Javascript
js实现前面自动补全位数的方法
Oct 10 Javascript
JavaScript交换变量常用4种方法解析
Sep 02 Javascript
js原生之焦点图转换加定时器实例
Dec 12 #Javascript
IntersectionObserver API 详解篇
Dec 11 #Javascript
想学习javascript JS和jQuery哪个重要 先学哪个
Dec 11 #Javascript
基于javascript实现的购物商城商品倒计时实例
Dec 11 #Javascript
基于jquery实现的鼠标悬停提示案例
Dec 11 #Javascript
jquery滚动条插件(可以自定义)
Dec 11 #Javascript
jquery实现简单的瀑布流布局
Dec 11 #Javascript
You might like
几个学习PHP的网址
2006/11/25 PHP
用PHP生成静态HTML速度快类库
2007/03/18 PHP
ASP和PHP实现生成网站快捷方式并下载到桌面的方法
2014/05/08 PHP
基于jquery & json的省市区联动代码
2012/06/26 Javascript
固定表格行列(expression)在IE下适用
2013/07/25 Javascript
js获取触发事件元素在整个网页中的绝对坐标(示例代码)
2013/12/13 Javascript
jQuery+CSS3实现树叶飘落特效
2015/02/01 Javascript
JS实现下拉菜单赋值到文本框的方法
2015/08/18 Javascript
jQuery实现固定在网页顶部的菜单效果代码
2015/09/02 Javascript
跟我学习javascript的作用域与作用域链
2015/11/19 Javascript
jQuery操作iframe中js函数的方法小结
2016/07/06 Javascript
浅析JavaScript中作用域和作用域链
2016/12/06 Javascript
webpack优化之代码分割与公共代码提取详解
2019/11/22 Javascript
微信小程序用canvas画图并分享
2020/03/09 Javascript
Javascript ParentNode和ChildNode接口原理解析
2020/03/16 Javascript
[04:49]期待西雅图之战 2016国际邀请赛中国区预选赛WINGS战队赛后采访
2016/06/29 DOTA
python对字典进行排序实例
2014/09/25 Python
Python如何读取MySQL数据库表数据
2017/03/11 Python
对numpy Array [: ,] 的取值方法详解
2018/07/02 Python
python实现计算器功能
2019/10/31 Python
在Matplotlib图中插入LaTex公式实例
2020/04/17 Python
python 实现两个线程交替执行
2020/05/02 Python
Python numpy矩阵处理运算工具用法汇总
2020/07/13 Python
REISS英国官网:伦敦High Street最受欢迎品牌
2016/12/21 全球购物
意大利时尚精品店:Nugnes 1920
2020/02/10 全球购物
德国高尔夫商店:Par71.de
2020/11/29 全球购物
TCP/IP模型的分界线
2012/12/01 面试题
公务员培训心得体会
2013/12/28 职场文书
幼儿园大班新学期寄语
2014/01/18 职场文书
降消项目实施方案
2014/03/30 职场文书
销售团队口号大全
2014/06/06 职场文书
云冈石窟导游词
2015/02/04 职场文书
大学生个人简历自我评价
2015/03/11 职场文书
幼儿园2015年度工作总结
2015/04/01 职场文书
会计稽核岗位职责
2015/04/13 职场文书
JS继承最简单的理解方式
2021/03/31 Javascript