SQL语句去重是用distinct还是用group by呢?

本文探讨了distinct和groupby在数据库中的作用,分别介绍了它们用于去重和聚合统计的特点,通过实例说明了如何正确选择和使用这两种方法,以提高数据处理效率。

distinct简单来说就是用来去重的
group by的设计目的则是用来聚合统计的
两者在能够实现的功能上有些相同之处,但应该仔细区分,因为用错场景的话,效率相差可以倍计。

单纯的去重操作使用distinct,速度是快于group by的。

distinct支持单列、多列的去重方式。
单列去重的方式简明易懂,即相同值只保留1个。 多列的去重则是根据指定的去重的列信息来进行,即只有所有指定的列信息都相同,才会被认为是重复的信息
干巴巴的说不好理解,示例一下:

示例数据表中的数据:
mysql> select * from talk_test;
±—±------±-------+
| id | name | mobile |
±—±------±-------+
| 1 | xiao9 | 555555 |
| 2 | xiao6 | 666666 |
| 3 | xiao9 | 888888 |
| 4 | xiao9 | 555555 |
| 5 | xiao6 | 777777 |
±—±------±-------+

进行单列去重后的结果:
mysql> select distinct(name) from talk_test;
±------+
| name |
±------+
| xiao9 |
| xiao6 |
±------+
2 rows in set (0.01 sec)

mysql> select distinct(mobile) from talk_test;
±-------+
| mobile |
±-------+
| 555555 |
| 666666 |
| 888888 |
| 777777 |
±-------+
**只会保留指定的列的信息

进行多列去重后的结果:
mysql> select distinct name,mobile from talk_test;
±------±-------+
| name | mobile |
±------±-------+
| xiao9 | 555555 |
| xiao6 | 666666 |
| xiao9 | 888888 |
| xiao6 | 777777 |
±------±-------+
**只有所有指定的列信息都相同,才会被认定为重复的信息
group by使用的频率相对较高,但正如其功能一样,它的目的是用来进行聚合统计的,虽然也可能实现去重的功能,但这并不是它的长项。

所以只是单纯去重复的话 还是选用distinct吧 如果进行数据统计还是使用group by 的好

====================================
作者:沙漠渔
来源:沙漠渔溏
链接:http://www.sammery.com/archives/47.html
版权声明:内容遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

### SQL语句实现数据的方法 SQL中实现数据的方法主要有以下几种: #### 1. 使用 `DISTINCT` 关键字 `DISTINCT` 是SQL中最常用的方法,它可以除查询结果中的复记录。适用于只需要获取唯一值的情况。 ```sql SELECT DISTINCT column_name FROM table_name; ``` 例如,如果想从 `task` 表中获取唯一的 `task_id`,可以使用如下语句: ```sql SELECT DISTINCT task_id FROM task; ``` 注意:`DISTINCT` 只能对一列或多列组合进行,当多列组合时,只有所有列的值都相同才会被认为是复记录[^3]。 #### 2. 使用 `GROUP BY` 子句 `GROUP BY` 通常用于分组聚合操作,但它也可以起到的作用。通过将需要的字段放在 `GROUP BY` 子句中,可以达到与 `DISTINCT` 类似的效果。 ```sql SELECT column_name FROM table_name GROUP BY column_name; ``` 例如,从 `task` 表中获取唯一的 `task_id`: ```sql SELECT task_id FROM task GROUP BY task_id; ``` 这种方法在某些数据库系统中性能可能优于 `DISTINCT`,特别是在处理大数据量时[^1]。 #### 3. 使用窗口函数 `ROW_NUMBER()` 在支持窗口函数的数据库(如 Hive SQL、Oracle 等)中,可以使用 `ROW_NUMBER()` 函数来为每条记录分配一个行号,并根据某个排序规则选择每个分组的第一条记录,从而实现。 ```sql SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY column_name ORDER BY another_column) AS rn FROM table_name ) t WHERE rn = 1; ``` 例如,假设我们想从 `task` 表中根据 `start_time` 并保留最早的一条记录: ```sql SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY task_id ORDER BY start_time) AS rn FROM task ) t WHERE rn = 1; ``` 此方法特别适合需要保留完整记录信息并且只保留某一分组内的第一条记录的情况。 #### 4. 删除复数据 如果目标是删除表中的复数据,而不是仅仅查询非复记录,则可以使用 `DELETE` 语句结合子查询来完成。 ```sql DELETE FROM table_name WHERE rowid NOT IN ( SELECT MIN(rowid) FROM table_name GROUP BY column1, column2, ... ); ``` 例如,在 `users` 表中删除基于 `name` 和 `age` 字段的复记录: ```sql DELETE FROM users WHERE user_id NOT IN ( SELECT t1.user_id FROM ( SELECT MIN(user_id) AS user_id FROM users GROUP BY name, age ) t1 ); ``` 这种方法可以有效地清除表中的冗余数据,但需要注意备份数据以防止误删要信息[^2]。 #### 5. 将非复数据拷贝到新表 如果不想直接修改原表,而是希望将非复数据复制到一张新的表中,可以使用如下语句: ```sql INSERT INTO new_table SELECT * FROM old_table WHERE primary_key IN ( SELECT MIN(primary_key) FROM old_table GROUP BY duplicate_columns ); ``` 例如,将 `ac_event` 表中按 `event_time` 和 `door_index_code` 分组后保留最小 `ac_event_id` 的记录插入到 `ac_event_copy` 表中: ```sql INSERT INTO ac_event_copy SELECT * FROM ac_event WHERE ac_event_id IN ( SELECT MIN(ac_event_id) FROM ac_event GROUP BY event_time, door_index_code ); ``` 这种方式适用于需要保留原始数据的同时创建一个后的副本表的情况[^4]。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值