MySQL 如何在MySQL中获取列中每个不同值的计数?
在进行数据分析和处理时,我们常常需要统计某个列中每个不同值的数量,以便进行进一步分析。MySQL作为最常用的关系型数据库之一,自然也提供了相应的功能来满足这个需求。本文将介绍如何在MySQL中获取列中每个不同值的计数。
阅读更多:MySQL 教程
定义示例数据
在介绍具体的操作之前,我们先定义一个示例数据来演示。
CREATE TABLE `example` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- 插入示例数据
INSERT INTO `example` (`name`) VALUES ('Alice');
INSERT INTO `example` (`name`) VALUES ('Bob');
INSERT INTO `example` (`name`) VALUES ('Charlie');
INSERT INTO `example` (`name`) VALUES ('Alice');
INSERT INTO `example` (`name`) VALUES ('Bob');
INSERT INTO `example` (`name`) VALUES ('Dave');
该示例数据表中有两个列,分别是id
和name
。我们将主要对name
列进行统计和分析。
方法一:使用COUNT和GROUP BY
MySQL中最简单的获取列中每个不同值的计数的方法是通过使用COUNT和GROUP BY语句。具体步骤如下:
SELECT name, COUNT(*) AS count FROM example GROUP BY name;
运行上述代码后,会输出以下结果:
+---------+-------+
| name | count |
+---------+-------+
| Alice | 2 |
| Bob | 2 |
| Charlie | 1 |
| Dave | 1 |
+---------+-------+
从输出结果可以看出,该示例数据表中有4个不同的名字,每个名字出现的次数也被正确地统计出来了。
在上述代码中,我们首先使用SELECT语句选择了name
列和COUNT(*)
函数的结果,并将结果赋值给别名count
。然后使用GROUP BY语句对name
列进行分组,这样就可以对每个不同的名字进行统计了。
方法二:使用DISTINCT和COUNT
除了使用COUNT和GROUP BY语句之外,我们也可以使用DISTINCT和COUNT语句来实现同样的功能。具体步骤如下:
SELECT name, COUNT(DISTINCT name) AS count FROM example;
运行上述代码后,会输出以下结果:
+---------+-------+
| name | count |
+---------+-------+
| Alice | 1 |
| Bob | 1 |
| Charlie | 1 |
| Dave | 1 |
+---------+-------+
从输出结果可以看出,该示例数据表中有4个不同的名字,每个名字出现的次数也被正确地统计出来了。
在上述代码中,我们使用SELECT语句选择了name
列和COUNT(DISTINCT name)
函数的结果,并将结果赋值给别名count
。DISTINCT
关键字用来去除重复的name
,这样就可以对每个不同的名字进行统计了。
方法三:使用子查询
除了以上两种方法之外,我们还可以使用子查询的方式来获取列中每个不同值的计数。具体步骤如下:
SELECT name, (SELECT COUNT(*) FROM example WHERE example.name = t.name) AS count FROM (SELECT DISTINCT name FROM example) AS t;
运行上述代码后,会输出以下结果:
+---------+-------+
| name | count |
+---------+-------+
| Alice | 2 |
| Bob | 2 |
| Charlie | 1 |
| Dave | 1 |
+---------+-------+
从输出结果可以看出,该示例数据表中有4个不同的名字,每个名字出现的次数也被正确地统计出来了。
在上述代码中,我们首先使用子查询(SELECT DISTINCT name FROM example)选择了去重后的name
集合,并将结果赋值给别名t
。然后再次使用子查询(SELECT COUNT(*) FROM example WHERE example.name = t.name),对t
中的每个不同的名字name
进行统计。这样就可以得到每个不同名字的计数了。
性能比较
在实际的应用中,以上三种方法都可以完成获取列中每个不同值的计数的任务。但是它们在性能上有所差异。我们可以通过对比它们的执行计划来发现这种差异。
使用EXPLAIN语句可以查看MySQL执行查询语句的详细计划。我们将以下代码分别使用以上三种方法进行查询并查看它们的执行计划。
方法一:使用COUNT和GROUP BY
EXPLAIN SELECT name, COUNT(*) AS count FROM example GROUP BY name;
执行以上代码后,会输出以下执行计划:
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------+
| 1 | SIMPLE | example | NULL | index | NULL | PRIMARY | 4 | NULL | 6 | 100.00 | Using index; Using temporary; Using filesort |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------+
从执行计划可以看出,这种方法使用了索引(Using index),但是也使用了临时表(Using temporary)和文件排序(Using filesort)等操作,这些操作会对性能造成一定的影响。
方法二:使用DISTINCT和COUNT
EXPLAIN SELECT name, COUNT(DISTINCT name) AS count FROM example;
执行以上代码后,会输出以下执行计划:
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | example | NULL | index | NULL | PRIMARY | 4 | NULL | 6 | 100.00 | Using index |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
从执行计划可以看出,这种方法也使用了索引(Using index),但是没有使用临时表或文件排序等操作,比方法一更为高效一些。
方法三:使用子查询
EXPLAIN SELECT name, (SELECT COUNT(*) FROM example WHERE example.name = t.name) AS count FROM (SELECT DISTINCT name FROM example) AS t;
执行以上代码后,会输出以下执行计划:
+----+--------------------+------------+------------+--------+---------------+---------+---------+--------------------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+------------+------------+--------+---------------+---------+---------+--------------------+------+----------+-----------------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | |
| 2 | DERIVED | example | NULL | index | NULL | PRIMARY | 4 | NULL | 6 | 100.00 | Using index |
| 3 | DEPENDENT SUBQUERY | example | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.t.name | 1 | 100.00 | Using index condition |
+----
从执行计划可以看出,这种方法使用了多个操作(ALL、index、eq_ref等),其中子查询(SELECT DISTINCT name FROM example)产生的表需要全表扫描(ALL),这会对性能造成不利影响。
综合以上三种方法的执行计划,可以发现方法二(DISTINCT和COUNT)的性能最好,这也是比较常用的方法。
结论
统计列中每个不同值的计数在数据分析和处理中是一项很基础和必要的工作。在MySQL中,我们可以通过使用COUNT和GROUP BY、DISTINCT和COUNT,以及子查询等多种方法来实现该需求。这些方法的性能和实现方式各不相同,在选择的时候需要根据实际情况进行权衡。在一般情况下,使用DISTINCT和COUNT函数来获取列中每个不同值的计数是一个效率较高且简单易懂的做法。