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

问题描述

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

从前有一个皇帝,他有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. svn Edge访问规则配置

    权限的配置方法: 首先在用户页面定义用户,然后在版本库页面,手工填写访问规则. 以下面的配置为例(实际配置中应删除“//”及其后的注释): [groups]               //定义用户组 ...

  2. node中glob模块

    glob glob允许使用规则,从而获取对应规则匹配的文件 node的glob模块允许你使用 * 等符号,来写一个glob规则,像在shell里一样,获取匹配对应规则文件 安装 npm install ...

  3. 前端面试题整理—HTTP篇

    1.常见的HTTP方法有哪些? GET: 用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器 POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用PO ...

  4. [Android] Android v4包CompoundButtonCompatLollipop.class重复问题

    用 Butter Knife  8.8.1  导致v4包CompoundButtonCompatLollipop.class重复问题 详细错误如下: Error:Execution failed fo ...

  5. Linq中Sum和Group的使用

    ].AsEnumerable() group c by c.Field<int>("Name") into s select new { ID = s.Select(m ...

  6. getaddrinfo函数

    一.功能 对于IPv4和IPv6均适用,可以处理名字到地址以及服务到端口这两种变换,返回的是一个sockaddr结构而不是一个地址队列 二.函数原型 #include <netdb.h> ...

  7. idea JRebe插件激活方法

    具体方法请看创始人博客及github

  8. tensorflow---文字识别

    读取数据的三种方法: 1. feeding : providing data when running each step : classifier.eval(feed_dict={input:my_ ...

  9. CF920E Connected Components?

    CF luogu 先讲两个靠谱的做法 1.首先因为有n个点,m条不存在的边,所以至少存在一个点,和m/n个点之间没边,所以把这个点找出来,连一下其他相连的点,这样还剩m/n个点没确定在哪个联通块,而这 ...

  10. 第26月第28天 avplayer cache

    1.urlsession https - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticati ...