最开始写查询语句的时候,我一直卡在distinct怎么用这个问题上,总以为加上它就能自动把重复的数据清理干净,结果连着跑了好几次语句,返回的结果还是乱糟糟的,重复行依旧堆在那里,当时盯着屏幕愣了很久,怀疑是不是语法写错了。
一开始的思路很简单,直接把distinct放在字段前面,只写单独一列的时候,效果看着还算正常,重复的值确实被合并掉了。然后顺手多加了一个字段,问题马上就冒出来了。那时候没意识到,distinct判断重复,看的是整一行所有字段组合起来的结果,不是单独盯着某一列。两个字段里只要有任意一处内容不一样,整行就不会被判定成重复,自然不会被去掉。那次折腾了半个多小时,反复删改字段顺序,来回执行,才慢慢摸到这个点。
同事在旁边看到,说他平时习惯把distinct写在select之后,所有字段之前,位置是固定的,不能随便插到字段中间。试过把它挪到第二个字段前面,直接报语法错误,弹窗提示语句不合法。这下记牢了,它的位置没得挑,只能紧跟在select后面。
有一回想统计去重之后一共有多少条记录,直接套上count,写成count(distinct字段)。跑出来的数字和直接distinct查出来的行数对上了,这个用法倒是意外的顺手。只是当时也发现一个情况,空值null会被distinct当成一样的值,多条null记录最后只会保留一条,这个细节之前完全没考虑到,差一点统计错数量。
这只是我的个人感受,不是标准答案。
还有个容易踩的地方,distinct和orderby放在一起的时候,排序的字段必须出现在distinct后面的字段列表里面。之前试过单独用一个不在查询列里的字段排序,执行直接失败。我当时想偷懒,不想把排序字段展示出来,最后只能调整查询字段,把需要排序的字段一并带上,再接受结果里多出这一列。
很多人会拿distinct和groupby放在一块对比,我自己平时很少去强行区分谁更好用,只是凭写语句时候的需求选。单纯只想去掉重复行、拿到干净的数据集,就用distinct;需要顺带做求和、计数这类聚合计算的时候,才会换groupby。不是说谁替代谁,只是适配的场景不一样。
也试过在多表关联查询里面加distinct,关联之后笛卡尔积会产生大量临时重复数据,加上之后结果干净很多。但能明显感觉到查询速度变慢了,数据量大的时候延迟会更明显。后来慢慢养成习惯,不是看到重复行就无脑加distinct,先回头看看关联条件是不是写的有问题,能从源头减少重复,就不依赖这个关键字去兜底。
有时候翻网上的示例,好多示例只放单字段的简短写法,复杂的多字段场景讲得很浅,很容易让人形成片面的理解。我就是被这种简短示例误导,以为它只对第一个字段生效,踩了那次多字段的坑之后,才明白它的判断单元是整行数据。
现在写语句前,会先想清楚自己到底要按哪些维度来去重,把这些维度对应的字段全部写进去,少一个字段,去重逻辑就和预想的不一样。不会再抱着一个模糊的认知,随便敲上distinct就去执行。
上次改完那条出错的SQL之后,关掉数据库客户端,没再继续测试别的写法。