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 相关文章推荐
javascript div 遮罩层封锁整个页面
Jul 10 Javascript
JS仿flash上传头像效果实现代码
Jul 18 Javascript
谈谈Jquery中的children find 的区别有哪些
Oct 19 Javascript
跟我学习javascript的循环
Nov 18 Javascript
jQuery插件imgPreviewQs实现上传图片预览
Jan 15 Javascript
jquery使用Cookie和JSON记录用户最近浏览历史
Apr 19 Javascript
JS控制弹出悬浮窗口(一览画面)的实例代码
May 30 Javascript
第七篇Bootstrap表单布局实例代码详解(三种表单布局)
Jun 21 Javascript
jQuery实现定位滚动条位置
Aug 05 Javascript
BootStrap Validator使用注意事项(必看篇)
Sep 28 Javascript
JS弹性运动实现方法分析
Dec 15 Javascript
js前端面试之同步与异步问题详解
Apr 03 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
轻松入门: 煮好咖啡的七个诀窍
2021/03/03 冲泡冲煮
PHP集成FCK的函数代码
2008/09/27 PHP
使用zend studio for eclipse不能激活代码提示功能的解决办法
2009/10/11 PHP
微信第三方登录(原生)demo【必看篇】
2017/05/26 PHP
javascript知识点收藏
2007/02/22 Javascript
统计jQuery中各字符串出现次数的工具
2012/05/03 Javascript
nodejs教程 安装express及配置app.js文件的详细步骤
2013/05/11 NodeJs
浅析JQuery UI Dialog的样式设置问题
2013/12/18 Javascript
AngularJS 指令的交互详解及实例代码
2016/09/14 Javascript
jQuery实现的右下角广告窗体跟随效果示例
2016/09/16 Javascript
Jquery根据浏览器窗口改变调整大小的方法
2017/02/07 Javascript
详解用Node.js写一个简单的命令行工具
2018/03/01 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
Vue-cli@3.0 插件系统简析
2018/09/05 Javascript
javascript实现文本框标签验证的实例代码
2018/10/14 Javascript
jQuery选择器之层次选择器用法实例分析
2019/02/19 jQuery
js事件触发操作实例分析
2019/06/21 Javascript
js定义类的方法示例【ES5与ES6】
2019/07/30 Javascript
Vue中jsx不完全应用指南小结
2019/11/01 Javascript
Vue filter 过滤当前时间 实现实时更新效果
2019/12/20 Javascript
JavaScript对象原型链原理解析
2020/01/22 Javascript
Python 内置函数memoryview(obj)的具体用法
2017/11/23 Python
分享Python切分字符串的一个不错方法
2018/12/14 Python
python使用PIL实现多张图片垂直合并
2019/01/15 Python
基于Python打造账号共享浏览器功能
2019/05/30 Python
Python re 模块findall() 函数返回值展现方式解析
2019/08/09 Python
python的help函数如何使用
2020/06/11 Python
解析Python 偏函数用法全方位实现
2020/06/26 Python
使用phonegap操作数据库的实现方法
2017/03/31 HTML / CSS
清洁工表扬信
2014/01/08 职场文书
社区党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
派出所正风肃纪剖析材料
2014/10/10 职场文书
锦旗赠语
2015/06/23 职场文书
公司业务员管理制度
2015/08/05 职场文书
如何正确理解python装饰器
2021/06/15 Python
springboot创建的web项目整合Quartz框架的项目实践
2022/06/21 Java/Android