如何在SNO-SQL中按商品名去重并保留唯一非空ID记录
问题描述
我用SNO-SQL操作PRODUCT_LOOKUP表,表内存在商品名称相同但ID不同的重复行,还有部分ID为NULL。需求是去除商品名重复的行,任意保留一条ID非空的记录。
原表结构及数据:
| Product | ID |
|---|---|
| Apple | N5 |
| Apple | N5B |
| Banana | N4 |
| Kiwi | N5 |
| Kiwi | N5B |
| Lime | N4 |
| Mango | N3 |
| Pear | N5B |
目标表结构及数据:
| Product | ID |
|---|---|
| Apple | N5 |
| Banana | N4 |
| Kiwi | N5B |
| Lime | N4 |
| Mango | N3 |
| Pear | N5B |
我尝试了以下DISTINCT语句,但没达到预期效果:
SELECT DISTINCT PRODUCT, ID, FROM PRODUCT_LOOKUP WHERE PRODUCT IN ('APPLE', 'BANANA', 'KIWI', 'LIME', 'MANGO', 'PEAR') AND ID IS NOT NULL -- 原始表中有一些ID为NULL的行,我想忽略它们 ORDER BY PRODUCT ASC
解决方案
问题出在DISTINCT是对整个结果行去重,而你需要的是按PRODUCT分组,每组只保留一条非空ID的记录。可以用以下两种方法实现:
方法1:分组聚合(任意取一个非空ID)
SELECT PRODUCT, MIN(ID) AS ID -- 也可以用MAX(ID),两种都能实现“任意保留一条”的需求 FROM PRODUCT_LOOKUP WHERE PRODUCT IN ('APPLE', 'BANANA', 'KIWI', 'LIME', 'MANGO', 'PEAR') AND ID IS NOT NULL GROUP BY PRODUCT ORDER BY PRODUCT ASC
通过GROUP BY PRODUCT将相同商品的行归为一组,再用MIN()或MAX()提取该组内的一个非空ID,直接实现按商品名去重的目标。
方法2:窗口函数(灵活控制保留规则)
如果需要更明确地指定保留哪条记录(比如按ID排序取第一条),可以用ROW_NUMBER()窗口函数:
WITH ranked_products AS ( SELECT PRODUCT, ID, ROW_NUMBER() OVER (PARTITION BY PRODUCT ORDER BY ID) AS rn -- 可修改ORDER BY规则调整保留的记录 FROM PRODUCT_LOOKUP WHERE PRODUCT IN ('APPLE', 'BANANA', 'KIWI', 'LIME', 'MANGO', 'PEAR') AND ID IS NOT NULL ) SELECT PRODUCT, ID FROM ranked_products WHERE rn = 1 ORDER BY PRODUCT ASC
PARTITION BY PRODUCT按商品名分组,ROW_NUMBER()给每组内的行编号,取编号为1的行即可完成去重。
原语句失效原因
DISTINCT会把PRODUCT和ID的组合作为重复判断依据,比如Apple-N5和Apple-N5B是两行不同的记录,所以都会被保留,无法实现按商品名去重的需求。
内容的提问来源于stack exchange,提问作者Rue
相关产品推荐
相关产品推荐

