必会!MySQL去重3种方法
必会!MySQL去重3种方法
在数据库操作中,去重是一个非常常见的需求。无论是统计独立访客数(UV),还是获取某个字段的唯一值列表,都需要用到去重操作。本文将介绍MySQL中常用的三种去重方法:distinct、group by和row_number窗口函数,并通过具体示例说明它们的使用场景和特点。
假设我们有一张名为task
的表,结构如下:
其中:
task_id
:任务IDorder_id
:订单IDstart_time
:开始时间
我们的目标是计算任务的总数量,但由于task_id
存在重复值,因此需要先进行去重处理。
distinct
distinct
是最常用的去重方法之一,适用于简单的去重场景。以下是使用distinct
计算任务总数的SQL语句:
select count(distinct task_id) task_num
from Task;
需要注意的是,distinct
通常效率较低,不适合用于展示去重后的具体值,一般与count
函数配合使用来计算条数。当distinct
后面有多个字段时,只有当所有字段的值都相同时,才会被认为是重复值。
group by
group by
子句也可以实现去重功能,同时还能进行分组统计。以下是使用group by
计算任务总数的SQL语句:
select count(task_id) task_num
from (select task_id
from Task
group by task_id) tmp;
group by
的一个优点是可以处理包含null
值的去重场景,而distinct
在处理null
值时可能会有不同表现。
row_number
在支持窗口函数的SQL方言(如Hive SQL、Oracle等)中,还可以使用row_number
窗口函数进行去重。以下是使用row_number
计算任务总数的SQL语句:
select count(case when rn=1 then task_id else null end) task_num
from (select task_id
, row_number() over (partition by task_id order by start_time) rn
from Task) tmp;
row_number
窗口函数通过为每一行分配一个唯一的行号来实现去重,其中partition by
用于指定分组字段,order by
用于指定组内排序字段。
distinct与group by的对比
为了更好地理解distinct
和group by
在去重中的使用差异,我们再来看一个示例表test
:
-- 下方的分号;用来分隔行
select distinct user_id
from Test; -- 返回 1; 2
select distinct user_id, user_type
from Test; -- 返回1, 1; 1, 2; 2, 1
select user_id
from Test
group by user_id; -- 返回1; 2
select user_id, user_type
from Test
group by user_id, user_type; -- 返回1, 1; 1, 2; 2, 1
select user_id, user_type
from Test
group by user_id;
-- Hive、Oracle等会报错,mysql可以这样写。
-- 返回1, 1 或 1, 2 ; 2, 1(共两行)。只会对group by后面的字段去重,就是说最后返回的记录数等于上一段sql的记录数,即2条
-- 没有放在group by 后面但是在select中放了的字段,只会返回一条记录(好像通常是第一条,应该是没有规律的)
通过这个示例,我们可以看到distinct
和group by
在处理多字段去重时的不同行为。distinct
会根据所有字段的组合进行去重,而group by
只对指定的字段进行去重,其他字段的值可能会出现随机性。
总结来说,三种去重方法各有优劣:
distinct
:使用简单,但效率较低,不适合展示具体值group by
:功能更强大,可以处理复杂场景,但语法相对复杂row_number
:灵活性高,适用于支持窗口函数的数据库,但学习成本较高
选择哪种方法取决于具体的应用场景和数据库支持情况。