最近在给某网站的后台添加一系列的统计功能,遇到很多需要按条件计数的情况。尝试了几种方法,下面简要记录,供大家参考。

问题描述

为使讨论简单易懂,我将问题稍作简化,去掉诸多的背景。

从前有一个皇帝,他有50个妃子,这些妃子很没有天理的给他生了100,000个儿子,于是,皇帝很苦恼,海量的儿子很难管理,而且,他想知道每个妃子给他生了多少个儿子,从而论功行赏,这很难办。于是,皇帝请了一个程序员帮他编了一个程序,用数据库来存储所有的儿子的信息,这样就可以用程序来统计和管理啦。

数据库的结构如下:

id 皇子的唯一编号
mother 皇子母亲的唯一编号

皇帝把妃子分成了两个等级,天宫娘娘(编号小于25)和地宫娘娘(编号大于等于25),他想知道天宫娘娘们和地宫娘娘们的生育能力孰强孰弱。于是,程序员开始写SQL Query了。

方法1:使用GROUP BY

SQL Query

SELECT COUNT(*) FROM `prince` GROUP BY `mother` > 24;

执行结果

count(*)
50029
49971

在100,000行数据上的运行时间:0.0335 秒

分析

这种GROUP BY方法的最大问题在于:无法区分所得到的结果。这两个数字哪一个是天宫娘娘们所生的皇子数,哪一个是地宫娘娘们所生的皇子数呢?不知道。所以,尽管它统计出了总数,但是没有什么意义。

因此,为了区分统计结果,必须要把条件 mother > 24 也作为一个字段在结果集中作为一个字段体现出来,修改后的sql如下:

SELECT COUNT(*) AS `number`, `mother` > 24 AS `type` FROM `prince` GROUP BY `mother` > 24;

执行结果

number  type
50029 0
49971 1

条件表达式作为字段时,该字段的值就是该条件表达式的值,因此,对应我们的例子,type = 1 也就是表示 mother > 24 的值为1,因此,第二行中的数字代表地宫娘娘们所生的皇子数。

经过修改后,我们看出,天宫娘娘们略胜一筹。

优缺点

缺点是显而易见的,由于使用了条件表达式作为分组依据,它只能做二元的划分,对于要分成多类进行统计的情况不能够胜任。比如要分别统计1~10号、11~24号,25号~50号妃子的产子数,就无法实现了。

另外,由于使用了GROUP BY,因此涉及到排序,执行时间上要更长。

我暂时没有发现这种方法的优点。

方法2:使用嵌套的SELECT

使用嵌套的SELECT也可以达到目的,在每个SELECT子句中统计一个条件下的数据,然后用一个主SELECT把这些统计数据整合起来。

SQL Query

SELECT
( SELECT COUNT( * ) FROM `prince` WHERE `mother` >24 ) AS `digong`,
( SELECT COUNT( * ) FROM `prince` WHERE `mother` <=24 ) AS `tiangong`

执行结果

digong  tiangong
49971 50029

在100,000行数据上的运行时间:0.0216 秒

分析

这种嵌套SELECT的方法非常直观,就是分别统计各个条件下的数值,最后进行汇总,通俗易懂,跟自然语言没啥区别了。

优缺点

优点就是直观,而且速度也比GROUP BY要快。虽然是3条SELECT语句,看起来比GROUP BY的方案多了2条语句,但是它不涉及到排序,这就节省了很多时间。

缺点可能就是语句稍多,对语句数量有洁癖的同学可能会比较不舒服。

方法3:使用CASE WHEN

CASE WHEN语句的功能很强大,可以定义灵活的查询条件,很适合进行分类统计。

SQL Query

SELECT
COUNT( CASE WHEN `mother` >24 THEN 1 ELSE NULL END ) AS `digong`,
COUNT( CASE WHEN `mother` <=24 THEN 1 ELSE NULL END ) AS `tiangong`
FROM prince

执行结果

digong  tiangong
49971 50029

在100,000行数据上的运行时间:0.02365825 秒

分析

此方法的关键在于

COUNT( CASE WHEN `mother` >24 THEN 1 ELSE NULL END )

这里的COUNT和CASE WHEN联合使用,做到了分类计数。先使用CASE WHEN,当满足条件时,将字段值设置为 1, 不满足条件时,将字段值设置为NULL,接着COUNT函数仅对非NULL字段进行计数,于是,问题解决。

优缺点

优点嘛,此方法也不涉及到排序,因此运行时间上与方法2相当,SELECT语句减少到了 1 条。

缺点就是语句比较长,对语句长度有洁癖的同学可能会比较不舒服。

总结

对于确定分类的按条件计数,可以尽量不用GROUP BY,从而避免排序动作,加速Query的执行。

如果需要根据某个字段的值进行分类,而该字段的值是可变的,比如皇帝要统计每一个妃子的产子数,而他可能不停的再娶很多妃子,这种情况下,使用方法2和方法3就不太灵光了,还是使用一个GROUP BY来得简单便捷。

Mysql按条件计数的几种方法的更多相关文章

  1. MySQL数据库分表的3种方法

    原文地址:MySQL数据库分表的3种方法作者:dreamboycx 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目 ...

  2. mysql myisam转innodb的2种方法

      mysql myisam转innodb的2种方法 mysql中的myisam和innodb有什么区别.一个好比便利店,一个好比大型购物中心,他们是为了适应不同的场合而存在的.当流量比较小,我们可以 ...

  3. mysql 中添加索引的三种方法

    原文:http://www.andyqian.com/2016/04/06/database/mysqleindex/ 在mysql中有多种索引,有普通索引,全文索引,唯一索引,多列索引,小伙伴们可以 ...

  4. 【译】在React中实现条件渲染的7种方法

    原文地址:https://scotch.io/tutorials/7-ways-to-implement-conditional-rendering-in-react-applications 借助R ...

  5. MySQL中删除数据的两种方法

    转自:http://blog.csdn.net/apache6/article/details/2778878 1. 在MySQL中有两种方法可以删除数据: 一种是delete语句,另一种是trunc ...

  6. windows 下mysql每日定时备份的几种方法

    第一种:新建批处理文件 backup.dat,里面输入以下代码:  代码如下 复制代码 net stop mysql xcopy "C:/Program Files/MySQL/MySQL ...

  7. MySQL重置root密码的几种方法(windows+Linux)

    重置root密码的方法: windows系统下:1.停止mysql服务:2.新建文件init-root.txt,写上如下内容: update mysql.user set password = pas ...

  8. MYSQL数据库的导出的几种方法

    mysql的数据导出几种方法   从网上找到一些问题是关于如何从MySQL中导出数据,以便用在本地或其它的数据库系统之上:以及 将现有数据导入MySQL数据库中. 数据导出 数据导出主要有以下几种方法 ...

  9. python中统计计数的几种方法

    以下实例展示了 count() 方法的使用方法: 1 2 3 4 5 6 # !/usr/bin/python3   T = (123, 'Google', 'Runoob', 'Taobao', 1 ...

随机推荐

  1. Java高并发秒杀API之业务分析与DAO层

    根据慕课网上关于java高并发秒杀API的课程讲解用maven+ssm+redis实现的一个秒杀系统 参考了codingXiaxw's blog,很详细:http://codingxiaxw.cn/2 ...

  2. [Android] Android RxBus 用法学习总结

    事件总线的好处在于方便组件之间的交互,RxBus不是一个库,而是使用RxJava实现事件总线的一种思想. rxbus和eventbus相比较: RxJava 主要做异步.网络的数据处理,强大之处就是对 ...

  3. C++模板的使用以及常见问题

    最近的数据结构实验频繁地遇到了模板,之前对这一块接触不多,遇到了很多问题,放到这里总结一下. 模板的声明有两种:template <typename Type>或者template< ...

  4. java.lang.ClassCastException: com.sun.proxy.$Proxy27 cannot be cast to com.bbk.n002.service.QuestionService

    1 严重: Servlet /N002-1.0 threw load() exception 2 java.lang.ClassCastException: com.sun.proxy.$Proxy2 ...

  5. MySQL之数据表(五)

    1.数据表是数据库的重要内容,首先打开数据库. USE DATABASE; mysql> SHOW DATABASES;+--------------------+| Database |+-- ...

  6. (9)EvenOddJump

    一.问题描述 一只青蛙从数组(A)的每一个元素向数组尾部跳动.跳动规则如下: 当奇数跳的时候,就是第1.3.5.7....次进行移动时候,移动规则A[i] <= A[j],  并且A[j] = ...

  7. Vue学习第一天:Vue.js指令系统

    1. 如何使用Vue.js? 1.1 直接引入 - <script src="./statics/vue.min.js"></script> - 引入之后在 ...

  8. moment.js 时间戳转换

    1. 一段时间以0点为标准 : 2018-03-15 00:00:00- 2018-03-21 00:00:00 let startTime = moment('2018-03-15').format ...

  9. 使用Protobuf定义网络协议

    准备工具: 工具下载地址如下:https://github.com/protocolbuffers/protobuf/releases/tag/v3.6.1,主要使用到的文件有: protoc.exe ...

  10. 数据库并发控制及SQL Server的并发控制机制

    在多用户和网络环境下,数据库是一个共享资源,多个用户或应用程序同时对数据库的同一数据对象进行读写操作,这种现象称为对数据库的并发操作.显然并发操作可以充分利用系统资源,提高系统效率.虽然如此,但是如果 ...