table表
字段1 字段2
id name
1 a
2 b
3 c
4 c
5 b
库结构大概这样,这只是一个简单的例子,实际状况会复杂得多。
好比我想用一条语句查询获得name不重复的全部数据,那就必须
使用distinct去掉多余的重复记录。
select distinct name from table
获得的结果是:
----------
name
a
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条件里?能,照样报错。
--------------------------------------------------------
下面方法可行:
select *, 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以前,否则会报错
在使用mysql时,有时须要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但每每只 用它来返回不重复记录的条数,而不是用它来返回不重记录的全部值。其缘由是distinct只能返回它的目标字段,而没法返回其它字段,这个问题让我困扰好久,用distinct不能解决的话,我只有用二重循环查询来解决,而这样对于一个数据量很是大的站来讲,无疑是会直接影响到效率的,因此浪费了我大量时间。
在表中,可能会包含重复值。这并不成问题,不过,有时您也许但愿仅仅列出不一样(distinct)的值。关键词 distinct用于返回惟一不一样的值。
表A:
示例1
select distinct name from A
执行后结果以下:
示例2
select distinct name, id from A
执行后结果以下:
其实是根据“name+id”来去重,distinct同时做用在了name和id上,这种方式Access和SQL Server同时支持。
示例3:统计
select count(distinct name) from A; --表中name去重后的数目, SQL Server支持,而Access不支持
select count(distinct name, id) from A; --SQL Server和Access都不支持
示例4
select id, distinct name from A; --会提示错误,由于distinct必须放在开头
在使用mysql时,有时须要查询出某个字段不重复的记录,这时可使用mysql提供的distinct这个关键字来过滤重复的记录,可是实际中咱们每每用distinct来返回不重复字段的条数(count(distinct id)),其缘由是distinct只能返回他的目标字段,而没法返回其余字段,例若有以下表user:
用distinct来返回不重复的用户名:select distinct name from user;,结果为:
这样只把不重复的用户名查询出来了,可是用户的id,并无被查询出来:select distinct name,id from user;,这样的结果为:
distinct name,id 这样的mysql 会认为要过滤掉name和id两个字段都重复的记录,若是sql这样写:select id,distinct name from user,这样mysql会报错,由于distinct必须放在要查询字段的开头。
因此通常distinct用来查询不重复记录的条数。
若是要查询不重复的记录,有时候能够用group by :
select id,name from user group by name;
1 前言
在我们编写 SQL 语句操做数据库中的数据的时候,有可能会遇到一些不太爽的问题,例如对于同一字段拥有相同名称的记录,咱们只须要显示一条,但实际上数据库中可能含有多条拥有相同名称的记录,从而在检索的时候,显示多条记录,这就有违我们的初衷啦!所以,为了不这种状况的发生,我们就须要进行“去重”处理啦,那么何为“去重”呢?说白了,就是对同一字段让拥有相同内容的记录只显示一条记录。
那么,如何实现“去重”的功能呢?对此,我们有两种方式能够实现该功能。
- 第一种,在编写 select 语句的时候,添加 distinct 关键词;
- 第二种,在编写 select 语句的时候,调用 row_number() over() 函数。
以上两种方式均可以实现“去重”功能,那二者之间有何异同呢?接下来,做者将给出详细的说明。
2 distinct
在 SQL 中,关键字 distinct 用于返回惟一不一样的值。其语法格式为:
SELECT DISTINCT 列名称 FROM 表名称
- 1
假设有一个表“CESHIDEMO”,包含两个字段,分别 NAME 和 AGE,具体格式以下:
观察以上的表,我们会发现:拥有相同 NAME 的记录有两条,拥有相同 AGE 的记录有三条。若是我们运行下面这条 SQL 语句,
/** * 其中 PPPRDER 为 Schema 的名字,即表 CESHIDEMO 在 PPPRDER 中 */
select name from PPPRDER.CESHIDEMO
- 1
- 2
- 3
- 4
- 5
将会获得以下结果:
观察该结果,我们会发如今以上的四条记录中,包含两条 NAME 值相同的记录,即第 2 条记录和第 3 条记录的值都为“gavin”。那么,若是我们想让拥有相同 NAME 的记录只显示一条该如何实现呢?这时,就须要用到 distinct 关键字啦!接下来,运行以下 SQL 语句,
select distinct name from PPPRDER.CESHIDEMO
- 1
将会获得以下结果:
观察该结果,显然我们的要求获得实现啦!可是,我们不由会想到,若是将 distinct 关键字同时做用在两个字段上将会产生什么效果呢?既然想到了,我们就试试呗,运行以下 SQL 语句,
select distinct name, age from PPPRDER.CESHIDEMO
- 1
获得的结果以下所示:
观察该结果,哎呀,貌似没有做用啊?她将所有的记录都显示出来了啊!其中 NAME 值相同的记录有两条,AGE 值相同的记录有三条,彻底没有变化啊!但事实上,结果就应该是这样的。由于当 distinct 做用在多个字段的时候,她只会将全部字段值都相同的记录“去重”掉,显然我们“可怜”的四条记录并不知足该条件,所以 distinct 会认为上面四条记录并不相同。空口无凭,接下来,我们再向表“CESHIDEMO”中添加一条彻底相同的记录,验证一下便可。添加一条记录后的表以下所示:
再运行以下的 SQL 语句,
select distinct name, age from PPPRDER.CESHIDEMO
- 1
获得的结果以下所示:
观察该结果,完美的验证了我们上面的结论。
此外,有一点须要你们特别注意,即:关键字 distinct 只能放在 SQL 语句中全部字段的最前面才能起做用,若是放错位置,SQL 不会报错,但也不会起到任何效果。
3 row_number() over()
在 SQL Server 数据库中,为我们提供了一个函数 row_number() 用于给数据库表中的记录进行标号,在使用的时候,其后还跟着一个函数 over(),而函数 over() 的做用是将表中的记录进行分组和排序。二者使用的语法为:
ROW_NUMBER() OVER(PARTITION BY COLUMN1 ORDER BY COLUMN2)
- 1
意为:将表中的记录按字段 COLUMN1进行分组,按字段 COLUMN2 进行排序,其中
- PARTITION BY:表示分组
- ORDER BY:表示排序
接下来,我们还用表“CESHIDEMO”中的数据进行测试。首先,给出没有使用 row_number() over() 函数时查询的结果,以下所示:
而后,运行以下 SQL 语句,
select PPPRDER.CESHIDEMO.*, row_number() over(partition by age order by name desc) from PPPRDER.CESHIDEMO
- 1
获得的结果以下所示:
从上面的结果能够看出,其在原表的基础上,多了一列标有数字排序的列。那么反过来分析我们运行的 SQL 语句,发现其确实按字段 AGE 的值进行分组了,也按字段 NAME 的值进行排序啦!所以,函数的功能获得了验证。
接下来,我们就研究如何用 row_number() over() 函数实现“去重”的功能。经过观察上面的结果,我们能够发现,若是以 NAME 分组,以 AGE 排序,而后再取每组的第一个记录或许就能够实现“去重”的功能啊!那么试试看,运行以下 SQL 语句,
/* * 其中 rn 表示最后添加的那一列 */
select * from (select PPPRDER.CESHIDEMO.*, row_number() over(partition by name order by age desc) rn from PPPRDER.CESHIDEMO) where rn = 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
运行后,获得的结果以下所示:
观察以上的结果,咱们发现,哎呀,数据“去重”的功能一不当心就被我们实现了啊!不过很遗憾,若是我们细心的话,会发现一个很不爽的事情,那就是在执行以上 SQL 语句进行“去重”的时候,有一条 NAME 值为“gavin”、AGE 值为“18”的记录被过滤掉了,可是在现实生活会中,同名不一样年龄的事情太正常了。