Mysql语句数据去重--distict关键字失效原因分析及处理

 一、问题描述

        前两天本人于项目中接到了一个数据统计的活儿,由于系统还不具备数据导出的功能,所以需要手动利用sql语句来进行数据导出,执行的sql语句如下(由于隐私问题,现将具体的字段和表名以及结果隐藏):

SELECT
	b.xxx'楼层名称',
	IFNULL( c.xxx, '其他' ) '模块名称',
	IFNULL( d.xxxx, '无' ) '事项类型名称',
	e.xxx '大厅名称',
	IFNULL(a.xxx,'无') '事项名称',
	IFNULL(a.xxxx,'无') '办理人姓名',
	a.xxx '办理人手机',
	a.xxx '办理人身份证号',
	a.xxx '签到时间',
	g.xxx '预约码',
	CASE a.`xxxx`
	WHEN 1 THEN '已预约'
	WHEN 2 THEN '已签到'
	WHEN 3 THEN '已办理'
	WHEN 4 THEN '取消预约'
	WHEN 5 THEN '预约未办'
	WHEN 6 THEN '签到失败'
	WHEN 8 THEN '签到未办'
	WHEN 9 THEN '过号'
	WHEN 10 THEN '已重新取号'
	ELSE '无'
	END AS '状态',
	a.xxx '评价时间',
	IFNULL(g.xxx,'无') '叫号时间',
	g.xxx '窗口号',
	IFNULL(a.xxx,'无') '办理人',
	a.xxx'预约目标时间',
	CASE a.xxx
	WHEN '1' THEN '微信'
	WHEN '2' THEN '网上'
	ELSE '无'
	END '预约来源',
	a.xxx'预约二维码',
	CASE a.xxx
	WHEN 1 THEN '未修改'
	WHEN 2 THEN '已修改'
	ELSE '无'
	END '小程序修改办理人员状态',
	CASE a.update_period_status
	WHEN 1 THEN '未修改'
	WHEN 2 THEN '已修改'
	ELSE '无'
	END '小程序修改代预约时间状态',
	a.xxx'办理人id',
	CASE a.xxx
	WHEN 1 THEN '政务中心'
	WHEN 2 THEN '社保医保'
	WHEN 3 THEN '税务'
	WHEN 4 THEN '不动产'
	ELSE '无'
	END '预约类型',
	RIGHT(a.xxx,19) '时间节点key标识'
FROM
	xxx a
	LEFT JOIN xxx b ON a.xxx= b.xxx
	LEFT JOIN xxx c ON a.xxx= c.xxx
	LEFT JOIN xxx d ON a.xxx= d.xxx
	LEFT JOIN xxx e ON a.xxx= e.xxx
	LEFT JOIN xx.xxxf ON a.xxx = f.xxx
	LEFT JOIN xxxg ON f.xxx= g.`xxx`
WHERE
	LEFT ( xxx, 10 ) = '2023-10-17'

        上述的sql语句在数据库中查询的结果如下(同样,关键数据也进行了隐藏):

         从上述查询结果中可以看出,数据中存在很多主键order_id重复的情况,为了将数据去重,我在查询字段前添加了“distinct”关键字,希望可以对数据进行去重,结果添加完distinct关键字后,重复数据依旧存在,这时我对distinct去重的功能产生了质疑。

二、distinct关键字失效原因分析

        通过上网查询资料,我发现原来并不是distinct关键字失效了,而是因为distinct关键字是对写在它后面的全部字段生效的。现自制一张测试数据表--study表:

        在上述数据表中执行以下sql语句:

select distinct `name`,`subject`,score from study

         执行结果如下:

        可见,该执行语句只是将查询结果完全一致的数据排除了, 姓名相同,科目不同的“乐乐”的数据则没有排除。

        所以只有select后面所有要查询的字段都是一致的,distinct关键字才会将重复数据筛选掉,而不是将distinct字段放到主键前,就能筛选出主键不重复的数据(说到底还是学艺不精啊。。。居然想靠一个distinct关键字直接筛选出主键不重复的数据)

三、解决方案

        既然已经知道了distinct关键字没有生效的原因,那么现在我们就来看一下怎么合理筛选出符合需求的不重复数据

需求一:筛选出不同的姓名、科目或者分数

        筛选不重复的单一字段,只需要在字段前添加distinct关键字即可

select distinct `name` from study

        查询结果如下,即为不重复的姓名项

需求二: 筛选出每一个人分数最高的科目

        错误查询:

select distinct `name`,score from study group by `name`

        如果你单纯按照上 方代码进行查询,查询出不同的姓名、分数并且按照姓名分组,这样查询出来的结果就是不同姓名下第一条数据的分数。乐乐如果语文的成绩和数学的成绩互换,那查询结果就不符合需求,结果如下:

        所以需要在查询条件上对最大分数进行查询,sql在查询出最大分数的时候,同时也会把最大分数对应的那一条数据的其他字段进行带出,就能满足查询需求了,代码及运行结果如下:

        正确查询:

select name,max(score),`subject` from study group by `name`

         查询结果:

 四、结语

        最后说明一下我最初查询过程中犯的错误,查询出那么多条重复数据,是因为在进行左连接的时候,出现了一对多的情况。主表一条数据,在关联表中可以找到多条对应的关联数据,这样主表数据就会在多条查询结果中重复显示,只有子表的那些字段可能会显示不同,但是由于我查询的字段过多,所以没有一时间确认出来重复的原因。

        如果在sql查询中,你能确认出重复的字段是哪几个,并且重复数据中选择哪一条也无那么大关系的话,也可以直接用group by语句来针对重复的字段进行分组,也可以做到去重。

        那么以上,就是我从这次业务中总结出来的问题,确实很基础,但是希望可以提醒自己,也可以给大家提示一下,避免我这种错误。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值