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 相关文章推荐
jQuery自动切换/点击切换选项卡效果的小例子
Aug 12 Javascript
js修改input的type属性问题探讨
Oct 12 Javascript
javascript判断是否按回车键并解决浏览器之间的差异
May 13 Javascript
node.js中的favicon.ico请求问题处理
Dec 15 Javascript
JS获取IMG图片高宽的简单实例
May 17 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成"...")
Nov 28 Javascript
Javascript自定义事件详解
Jan 13 Javascript
codeMirror插件使用讲解
Jan 16 Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
Jul 13 Javascript
JavaScript实现学生在线做题计时器功能
Dec 05 Javascript
layer弹窗在键盘按回车将反复刷新的实现方法
Sep 25 Javascript
在Angular项目使用socket.io实现通信的方法
Jan 05 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
VFP与其他应用程序的集成
2006/10/09 PHP
PHP中执行MYSQL事务解决数据写入不完整等情况
2014/01/07 PHP
thinkphp3.2.2实现生成多张缩略图的方法
2014/12/19 PHP
解决php 处理 form 表单提交多个 name 属性值相同的 input 标签问题
2017/05/11 PHP
PHP单例模式实例分析【防继承,防克隆操作】
2019/05/22 PHP
基于PHP实现用户在线状态检测
2020/11/10 PHP
JQuery Tab选项卡效果代码改进版
2010/04/01 Javascript
js/ajax跨越访问-jsonp的原理和实例(javascript和jquery实现代码)
2012/12/27 Javascript
jquery操作 iframe的方法
2014/12/03 Javascript
jquery背景跟随鼠标滑动导航
2015/11/20 Javascript
AngularJS通过$location获取及改变当前页面的URL
2016/09/23 Javascript
js 提交form表单和设置form表单请求路径的实现方法
2016/10/25 Javascript
Bootstrap3 图片(响应式图片&图片形状)
2017/01/04 Javascript
Nodejs多站点切换Htpps协议详解及简单实例
2017/02/23 NodeJs
shiro授权的实现原理
2017/09/21 Javascript
jQuery实现获取选中复选框的值实例详解
2018/06/28 jQuery
分享vue里swiper的一些坑
2018/08/30 Javascript
原生js实现淘宝放大镜效果
2020/10/28 Javascript
如何通过JS实现转码与解码
2020/02/21 Javascript
python实现Flappy Bird源码
2018/12/24 Python
python plotly绘制直方图实例详解
2019/07/22 Python
Python人工智能之路 jieba gensim 最好别分家之最简单的相似度实现
2019/08/13 Python
使用Python画出小人发射爱心的代码
2019/11/23 Python
html5+css3进度条倒计时动画特效代码【推荐】
2016/03/08 HTML / CSS
Java servlet面试题
2012/03/04 面试题
J2EE中常用的名词进行解释
2015/11/09 面试题
医药工作者的求职信范文
2013/09/21 职场文书
庆八一活动方案
2014/01/25 职场文书
清正廉洁演讲稿
2014/05/22 职场文书
家长学校培训材料
2014/08/20 职场文书
2015年父亲节寄语
2015/03/23 职场文书
2015财务年度工作总结范文
2015/05/04 职场文书
复兴之路观后感3000字
2015/06/02 职场文书
萤火虫之墓观后感
2015/06/05 职场文书
天堂的孩子观后感
2015/06/11 职场文书
解决pytorch读取自制数据集出现过的问题
2021/05/31 Python