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 相关文章推荐
JS跨域代码片段
Aug 30 Javascript
页面元素绑定jquery toggle后元素隐藏的解决方法
Mar 27 Javascript
JavaScript中的对象序列化介绍
Dec 30 Javascript
jQuery对JSON数据进行排序输出的方法
Jun 24 Javascript
JS实现图片平面旋转的方法
Mar 01 Javascript
Javascript缓存API
Jun 14 Javascript
原生JS封装ajax 传json,str,excel文件上传提交表单(推荐)
Jun 21 Javascript
AngularJs  E2E Testing 详解
Sep 02 Javascript
Angular1.x自定义指令实例详解
Mar 01 Javascript
vue jsx 使用指南及vue.js 使用jsx语法的方法
Nov 11 Javascript
vue 配置多页面应用的示例代码
Oct 22 Javascript
微信小程序如何实现精确的日期时间选择器
Jan 21 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中变量及部分适用方法
2008/03/27 PHP
php实现快速排序法函数代码
2012/08/27 PHP
页面中iframe相互传值传参
2009/12/13 Javascript
jquery photoFrame 图片边框美化显示插件
2010/06/28 Javascript
js Html结构转字符串形式显示代码
2011/11/15 Javascript
异步javascript的原理和实现技巧介绍
2012/11/08 Javascript
jQuery 获取浏览器所在的IP地址的小例子
2013/11/08 Javascript
JS中的异常处理方法分享
2013/12/22 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
JS实现淡蓝色简洁竖向Tab点击切换效果
2015/10/06 Javascript
jQuery-1.9.1源码分析系列(十一)DOM操作续之克隆节点
2015/12/01 Javascript
浅谈Angular4实现热加载开发旅程
2017/09/08 Javascript
详解vue项目首页加载速度优化
2017/10/18 Javascript
Vue使用Element实现增删改查+打包的步骤
2020/11/25 Vue.js
[07:03]显微镜下的DOTA2第九期——430圣堂刺客杀戮秀
2014/06/20 DOTA
[00:59]DOTA2荣耀之路1:Doom is back!weapon X!
2018/05/22 DOTA
python Flask实现restful api service
2017/12/04 Python
python使用numpy读取、保存txt数据的实例
2018/10/14 Python
利用python GDAL库读写geotiff格式的遥感影像方法
2018/11/29 Python
Python实现账号密码输错三次即锁定功能简单示例
2019/03/29 Python
Python assert语句的简单使用示例
2019/07/28 Python
PyTorch加载自己的数据集实例详解
2020/03/18 Python
使用Django实现把两个模型类的数据聚合在一起
2020/03/28 Python
python如何使用代码运行助手
2020/07/03 Python
猎人靴英国官网:Hunter Boots
2017/02/02 全球购物
美国户外烹饪产品购物网站:Outdoor Cooking
2020/01/10 全球购物
现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset
2012/11/09 面试题
建材业务员岗位职责
2013/12/08 职场文书
ktv中秋节活动方案
2014/01/30 职场文书
电教室标语
2014/06/20 职场文书
企业领导班子四风对照检查材料
2014/09/27 职场文书
幼儿园工作总结2015
2015/04/01 职场文书
保密法制宣传月活动总结
2015/05/07 职场文书
房产电话营销开场白
2015/05/29 职场文书
WCG2010 星际争霸决赛 Flash vs Goojila 1 星际经典比赛回顾
2022/04/01 星际争霸
springboot入门 之profile设置方式
2022/04/04 Java/Android