本资料为产品岗位作为日常工作参考,语言口语化
At 2019/4/22 By David.Yang
排重查询(使用DISTINCT运算符来消除结果集中的重复行)
针对现有业务数据进行查询时,会有重复的数据记录,
有时候我们需要进行排重的数据查询,为了避免重复数据,
我们通常使用DISTINCT进行处理。
语法:
SELECT DISTINCT
column[,column...]
FROM
table_name
WHERE
where_conditions;
这个查询语法我们在看完SELECT语法后应该比较熟悉了。
其中column可以是多个字段哦~
DISTINCT语句演示
为了进行数据演示,我们将学生表加入国家字段,代表各个学生的国际都是哪些。
不知道大家是否还记得怎么对数据表进行字段新增的?
SQL
ALTER TABLE `students` ADD `nationality` varchar(20) COMMENT '国籍' AFTER `age`;
然后把数据补进去。
然后呢?
校长先生想看看今年的学生招收情况,这些学生都来自哪些国家?
我们教导主任周伯通,这可就难为了,
因为他知道,想要知道所有学生的国籍呢,
这个简单啊,他会,
只要这么做就行了
SQL
SELECT
nationality
FROM
students;
周伯通一看好开心呀~
看,学生来自五湖四海,大江南北啊,有南宋的,有西辽的,有西夏的,
看来俺们这学校声誉不错啊。
等等,咋是南宋、南宋一样一样的呢?
可是这不行啊,校长要的是生源地,怎么还有重复的呢?
这可愁坏了教导主任周伯通。
怎么才能去掉重复的呢?
这旁边一看坐的谁啊?
老情敌一灯大师啊!
没办法,校长的任务还得干,
没什么不好意思的,问吧
“额,那啥,一灯”
“当年是我不对啊,抢了你媳妇儿瑛姑”
“你都当和尚了,也就不计较了,咱进行个学术讨论啊”
“讷啥,你看看我这校长给的统计生源的事儿,你给瞅一眼呗”
一灯答:“行”
“看老衲给你点拨一二”
一灯的SQL是这么写的
SQL
SELECT DISTINCT
nationality
FROM
students;
一灯“牛逼不,就一字儿”
“嗯… 嗯~”
以上,就说明了DISTINCT关键字是干什么的了,他成功的消除了重复项。
DISTINCT多列怎么用
一灯曰“再给你开个光,瞅瞅多个列会有啥效果”
SQL
SELECT DISTINCT
nationality, gender
FROM
students;
结果集会告诉你南宋下的生源有男、女性别,
西夏就不同了,只有姑娘,没有男娃儿。
以上假如我们还有学生的县府数据,上边的示例变通一下,
我们是不是就可以获得国籍– 府县了呢?
比如:
SELECT DISTINCT
nationality,州字段
FROM
students;
南宋– 京兆府
南宋– 延安府
南宋– 商州
南宋– 同州
南宋– 华州
…
如果不是有DISTINCT语句控制,你得到的数据将会是
南宋– 京兆府
南宋– 京兆府
南宋– 京兆府
…
南宋– 延安府
南宋– 延安府
南宋– 延安府
…
南宋– 商州
南宋– 商州
南宋– 商州
…
南宋– 同州
南宋– 华州
…
DISTINCT对NULL值的处理
我们再招一个洋学生,叫路易11,不设置他的国籍,
数据库对应国籍为NULL,我们看看会是什么结果?
SQL
SELECT DISTINCT nationality FROM students;
DISTINCT对NULL类型数据是不进行过滤的,
即返回结果集中会包含NULL的值。
那我们要排除NULL的空数据呢?
可以直接在WHERE条件中加以限制。
SQL
SELECTDISTINCTROW
nationality
FROM
students
WHERE
nationality IS NOT NULL;
注:后续过滤查询会讲解WHERE子句
DISTINCT对*值的处理
mysql> SELECT DISTINCT * FROM students;
这时候其实等价于:
SELECT DISTINCT
nationality,gender, xxx, xxx, xxx, …
FROM
students;
DISTINCT与LIMIT
我们前文提起过LIMIT,用来限制返回的数据记录条数,
这里也同样可以使用。
SQL
SELECT DISTINCTROW
nationality
FROM
students
LIMIT 3;
注:后续过滤查询会讲解LIMIT子句
DISTINCT与GROUP BY子句比较
GROUP BY看字面意思聚合,分组,我们大概就能想到,
他与DISTINCT多少有点关系,或能做差不多的事情,
你别说,还真是。
比如我们要用GROUP BY来实现生源地统计,该怎么做呢?
一灯大师会这么做:
SQL
SELECT
nationality
FROM
students
GROUP BY
nationality;
一灯说“瞅见没,一样一样的”
“不对呀,不是一样一样的撒,这不顺序不太一样么?和尚”
确实,顺序是不一样。
一般来说,DISTINCT和GROUP
BY字句能干差不多的事,
那我们要是给DISTINCT加个排序呢?
(别慌,排序我们后文会讲的,现在留个印象日后好相处)
SQL
SELECT DISTINCT
nationality
FROM
students
ORDER BY
nationality;
DISTINCT与聚合函数的组合使用
SQL当中有一些聚合函数,比如SUM/COUNT/AVG等等,
他们可以用来与DISTINCT组合使用进行一些业务场景的查询。
-- 统计班级性别的分布情况
SQL
SELECT
gender, COUNT(DISTINCT number)
FROM
students
GROUP BY
gender;
因为学号是学生的标记,我们通过DISTINCT就可以排除重复学号数据,
在通过COUNT进行计数统计,
后然通过gender进行分组;
再比如统计学生年龄分布,可以这么写:
SQL
SELECT
age, COUNT(DISTINCT number)
FROM
students
GROUP BY
age;
注:
此种场景不能脱离GROUP BY字句。
-- 统计学生最大年龄,并统计有多少人?
SQL
SELECT
max(age), COUNT(DISTINCT number)
FROM
students
WHERE
age = (SELECT max(age) FROM students);
当然你也可以加上条件进行查询,
比如看来自西夏的学生最大年龄是多少,有多少人?
SQL
SELECT
nationality, max(age), COUNT(DISTINCTnumber)
FROM
students
WHERE
nationality = '西夏'
AND
age = (SELECT max(age) FROM studentsWHERE nationality = '西夏');
SQL解释
ϒ 以上在WHERE当中使用了子查询,需要通过子查询先算出最大年龄是多少,再进行外围SQL的查询。
所以你如果这么写,就会报错
SQL ERROR
SELECT
max(age), COUNT(DISTINCT number)
FROM
students
WHERE
age = max(age);
错误提示:
为什么呢?
聚集函数也叫列函数,它们都是基于整列数据进行计算的,
而where子句则是对数据行进行过滤的(这里过滤是在一个记录里边过滤的,基于"行"),
在筛选过程中依赖“基于已经筛选完毕的数据得出的计算结果”是一种悖论,
这是行不通的。
更简单地说,因为聚集函数要对全列数据时行计算,
因而使用它的前提是:结果集已经确定!
而where子句还处于“确定”结果集的过程中,因而不能使用聚集函数。
ϒ 如果你需要再进一步限定WHERE条件,那么请再子查询和WHERE条件内进行条件的操作
比如前面例子,我只想统计来自西夏的学生,
那么你需要现统计出西夏学生的最大年龄,这个在子语句中实现,
这时候你已经得到了西夏的行数据中年龄列的最大值;
在外部WHERE查询时,时针对整体行进行查询,
所以他需要对条件【国籍=西夏】进行限定,使得过滤出【国籍=西夏】的数据。
WHERE和子语句组合使用使得你查询的数据保持正确性。
如果在子查询中使用了【国籍=西夏】的条件,
而WHERE并为进行条件过滤,那么你其实是在做这么一件事,
通过子语句得到一个最大值的年龄,比如16,
然后查询所有【国籍=所有】学生,年龄=16的学生,共有多少人。
SQL
SELECT
max(age), COUNT(DISTINCT number)
FROM
students
WHERE
age = (SELECT max(age) FROM students WHERE nationality = '西夏');
但其实西夏的最大年龄16岁,学生只有1个
正确结果
本篇章讲解了查询中消除重复行的相关语法,
到此你应该能够进行数据去重复业务上相关的数据操作。
Bye Bye.