mysql中过滤重复记录之distinct用法

下面我们就通过几个简单的 Query 示例来展示一下 DISTINCT 的实现。

1.首先看看通过松散索引扫描完成 DISTINCT 的操作:

 代码如下 复制代码
sky@localhost : example 11:03:41> EXPLAIN SELECT DISTINCT group_id
    -> FROM group_messageG
*************************** 1. row ***************************
           id: 1
  SELECT_type: SIMPLE
        table: group_message
         type: range
possible_keys: NULL
          key: idx_gid_uid_gc
      key_len: 4
          ref: NULL
         rows: 10
        Extra: Using index for group-by
1 row in set (0.00 sec)

我们可以很清晰的看到,执行计划中的 Extra 信息为“Using index for group-by”,这代表什么意思?为什么我没有进行 GROUP BY 操作的时候,执行计划中会告诉我这里通过索引进行了 GROUP BY 呢?其实这就是于 DISTINCT 的实现原理相关的,在实现 DISTINCT的过程中,同样也是需要分组的,然后再从每组数据中取出一条返回给客户端。而这里的 Extra 信息就告诉我们,MySQL 利用松散索引扫描就完成了整个操作。当然,如果 MySQL Query Optimizer 要是能够做的再人性化一点将这里的信息换成“Using index for distinct”那就更好更容易让人理解了,呵呵。

2.我们再来看看通过紧凑索引扫描的示例:

 代码如下 复制代码
sky@localhost : example 11:03:53>  EXPLAIN SELECT DISTINCT user_id
    -> FROM group_message
    -> WHERE group_id = 2G
*************************** 1. row ***************************
           id: 1
  SELECT_type: SIMPLE
        table: group_message
         type: ref
possible_keys: idx_gid_uid_gc
          key: idx_gid_uid_gc
      key_len: 4
          ref: const
         rows: 4
        Extra: Using WHERE; Using index
1 row in set (0.00 sec)

这里的显示和通过紧凑索引扫描实现 GROUP BY 也完全一样。实际上,这个 Query 的实现过程中,MySQL 会让存储引擎扫描 group_id = 2 的所有索引键,得出所有的 user_id,然后利用索引的已排序特性,每更换一个 user_id 的索引键值的时候保留一条信息,即可在扫描完所有 gruop_id = 2 的索引键的时候完成整个 DISTINCT 操作。

3.下面我们在看看无法单独使用索引即可完成 DISTINCT 的时候会是怎样:

 代码如下 复制代码
sky@localhost : example 11:04:40> EXPLAIN SELECT DISTINCT user_id
    -> FROM group_message
    -> WHERE group_id > 1 AND group_id < 10G
*************************** 1. row ***************************
           id: 1
  SELECT_type: SIMPLE
        table: group_message
         type: range
possible_keys: idx_gid_uid_gc
          key: idx_gid_uid_gc
      key_len: 4
          ref: NULL
         rows: 32
        Extra: Using WHERE; Using index; Using temporary
1 row in set (0.00 sec)

当 MySQL 无法仅仅依赖索引即可完成 DISTINCT 操作的时候,就不得不使用临时表来进行相应的操作了。但是我们可以看到,在 MySQL 利用临时表来完成 DISTINCT 的时候,和处理 GROUP BY 有一点区别,就是少了 filesort。实际上,在 MySQL 的分组算法中,并不一定非要排序才能完成分组操作的,这一点在上面的 GROUP BY 优化小技巧中我已经提到过了。实际上这里 MySQL 正是在没有排序的情况下实现分组最后完成 DISTINCT 操作的,所以少了 filesort 这个排序操作。

4.最后再和 GROUP BY 结合试试看:
 

 代码如下 复制代码
sky@localhost : example 11:05:06> EXPLAIN SELECT DISTINCT max(user_id)
    -> FROM group_message
    -> WHERE group_id > 1 AND group_id < 10
    -> GROUP BY group_idG
*************************** 1. row ***************************
           id: 1
  SELECT_type: SIMPLE
        table: group_message
         type: range
possible_keys: idx_gid_uid_gc
          key: idx_gid_uid_gc
      key_len: 4
          ref: NULL
         rows: 32
        Extra: Using WHERE; Using index; Using temporary; Using filesort
1 row in set (0.00 sec)

最后我们再看一下这个和 GROUP BY 一起使用带有聚合函数的示例,和上面第三个示例相比,可以看到已经多了 filesort 排序操作了,正是因为我们使用了 MAX 函数的缘故。要取得分组后的 MAX 值,又无法使用索引完成操作,只能通过排序才行了。

在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值。其原因是distinct只能返回它的目标字段,而无法返回其它字段,这个问题让我困扰了很久

下面先来看看例子:

 代码如下 复制代码

   table
   id name
   1 a
   2 b
   3 c
   4 c
   5 b

库结构大概这样,这只是一个简单的例子,实际情况会复杂得多

比如我想用一条语句查询得到name不重复的所有数据,那就必须使用distinct去掉多余的重复记录

 

 代码如下 复制代码
   select distinct name from table

得到的结果是:

 

 代码如下 复制代码
   name
   a
   b
   c

好像达到效果了,可是,我想要得到的是id值呢?改一下查询语句吧:

 

 代码如下 复制代码
    select distinct name, id from table

结果会是:

 代码如下 复制代码

   id name
   1 a
   2 b
   3 c
   4 c
   5 b

distinct怎么没起作用?作用是起了的,不过他同时作用了两个字段,也就是必须得id与name都相同的才会被排除,我们再改改查询语句:

 

 代码如下 复制代码
select id, distinct name from table

很遗憾,除了错误信息你什么也得不到,distinct必须放在开头,难到不能把distinct放到where条件里?能,照样报错。。。。。。。

试了半天,也不行,最后在mysql手册里找到一个用法,用group_concat(distinct name)配合group by name实现了我所需要的功能,兴奋,天佑我也,赶快试试

报错。。。。。。。。。。。。郁闷。。。。。。。连mysql手册也跟我过不去,先给了我希望,然后又把我推向失望,好狠那。。。。

再仔细一查,group_concat函数是4.1支持,晕,我4.0的。没办法,升级,升完级一试,成功。。。。。。

终于搞定了,不过这样一来,又必须要求客户也升级了

突然灵机一闪,既然可以使用group_concat函数,那其它函数能行吗?

赶紧用count函数一试,成功,我。。。。。。。想哭啊,费了这么多工夫。。。。。。。。原来就这么简单。。。。。。

现在将完整语句放出:

 代码如下 复制代码

    select id,name, count(distinct name) from table group by name

结果:

 代码如下 复制代码

   id name count(distinct name)
   1 a 1
   2 b 1
   3 c 1

最后一项是多余的,不用管就行了,目的达到。。。。。

哦,对,再顺便说一句,group by 必须放在 order by 和 limit之前,不然会报错,差不多了,我继续忙碌。。。。。。

原文

这篇文章是我从别人那里转来的,在自己的项目中也遇到了这样的问题,我的sql语句是向下面这样写的:

 

 代码如下 复制代码

   SELECT attention_join.memberID,nickName,headpic,attention_join.time

    FROM attention_join

        JOIN member ON attention_join.memberID = member.memberID

        JOIN member_meta ON member.memberID = member_meta.memberID

    GROUP BY attention_join.memberID

    ORDER BY attention_join.time DESC

意思是 '按 加入/关注 小组的时间降序,查出小组内的会员' ,但是语句里并没有用到向上文说的count()关键字,这个也让我很不解,mysql没有详细的学习过,它的 group by 关键字的用法好像和 sqlserver 的有很大不同,这个等有时间了,在查查看吧,现在没有时间了

哦,对了,我的mysql版本是:

 服务器版本: 5.1.54-1 ubuntu4

 协议版本: 10

时间: 2024-11-02 00:23:39

mysql中过滤重复记录之distinct用法的相关文章

oracle中去重复记录 不用distinct

用distinct关键字只能过滤查询字段中所有记录相同的(记录集相同),而如果要指定一个字段却没有效果,另外distinct关键字会排序,效率很低 . select distinct name from t1 能消除重复记录,但只能取一个字段,现在要同时取id,name这2个字段的值. select distinct id,name from t1 可以取多个字段,但只能消除这2个字段值全部相同的记录 所以用distinct达不到想要的效果,用group by   可以解决这个问题. 例如要显示

mysql中删除重复记录sql语句

删除重复记录方法一: 1. 新建一个临时表  代码如下 复制代码 create table tmp as select * from youtable group by  name(name为不希望有重复的列) 2. 删除原来的表  代码如下 复制代码 drop table youtable 3. 重命名表  代码如下 复制代码 alter table tmp rename youtable 但是这个方法有个问题,由临时表转变过来的最终表,其表结构会和原来的不一致,需要手工更改.这个问题,待解决

sql中查询重复记录与删除重复记录

1.查找全部重复记录  代码如下 复制代码 Select * From 表 Where 重复字段 In (Select 重复字段 From 表 Group By 重复字段 Having Count(*)>1) 2.过滤重复记录(只显示一条)  代码如下 复制代码 Select * From HZT Where ID In (Select Max(ID) From HZT Group By Title) 注:此处显示ID最大一条记录 SQL Server删除重复行是我们最常见的操作之一,下面就为您

sql 过滤重复记录和查询重复记录

--查询一个表中有效去掉重复的记录,UserID为自增长主键,RoleID为重复字段  代码如下 复制代码 SELECT MIN(UserID) AS UserID, RoleID FROM tmpTable GROUP BY RoleID SELECT RoleID FROM tmpTable GROUP BY RoleID HAVING (COUNT(*) > 1) 获取重复记录 SELECT DISTINCT * FROM tmpTable 过滤重复记录

看实例学VFP:去除查询结果中的重复记录

在看实例学VFP:将查询结果输出为表或文本文件以及之前的几个关于select语句应用的例子中,组合框控件Combo1的数据方面的属性我们是这样设置的:RowSourceType属性值设置为"1-值",RowSource属性值设置为"部门,性别,学历",即在设计时已经将组合框控件的数据源固定了.但这种处理方式在有的情况下是不合理的,比如本文要做这样一个例子:希望在运行时可以在组合框控件里选择"部门",按"部门"来查询.我们已经知

select-关于mysql中查询重复数据的疑问

问题描述 关于mysql中查询重复数据的疑问 我有一个表叫做sc. 现在要查询score中有相同分数的信息, 查询的sql语句是 select * from sc where score in (select score from sc group by score having count(score)>1); 我很好奇的是group by的执行顺序是比 having先执行啊, 按道理,执行了之后重复的score值是没有的,怎么还能再用having 来查出count(score)>1 的重复

MySQL中删除重复数据的简单方法_Mysql

MYSQL里有五百万数据,但大多是重复的,真实的就180万,于是想怎样把这些重复的数据搞出来,在网上找了一圈,好多是用NOT IN这样的代码,这样效率很低,自己琢磨组合了一下,找到一个高效的处理方式,用这个方式,五百万数据,十来分钟就全部去除重复了,请各位参考. 第一步:从500万数据表data_content_152里提取出不重复的字段SFZHM对应的ID字段到TMP3表 create table tmp3 as select min(id) as col1 from data_content

mysql中模糊查询的四种用法介绍_Mysql

下面介绍mysql中模糊查询的四种用法: 1,%:表示任意0个或多个字符.可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示. 比如 SELECT * FROM [user] WHERE u_name LIKE '%三%' 将会把u_name为"张三","张猫三"."三脚猫","唐三藏"等等有"三"的记录全找出来. 另外,如果需要找出u_name中既有"三"又有

SQL Server中删除重复记录的SQL语句

方法:  代码如下 复制代码            select distinct * into #tmp from tablename  drop table tablename  select * into tablename from #tmp drop table # tmp 常有时候遇到需要删除SQL Server中的重复记录,这里有一些常用的删除重复记录的SQL, 最常用的 T-SQL 语句:  代码如下 复制代码 DELETE FROM [dbo].[myTable] WHERE