Sequelize如何实现单字段去重并返回关联其他字段查询
问题根因
DISTINCT的作用范围是SELECT子句返回的整行所有字段的组合,并非只作用于你单独包裹的单个字段:
- 你第一段写法生成的原生SQL大致为:
SELECT DISTINCT(`fruit`) AS `FRUIT`, `colour` AS `COLOUR` FROM `fruit_vendors`;
这条SQL判定重复的规则是fruit和colour两个字段的值同时相等才会去重,因此(apple, green)和(apple, red)会被识别为两条不同记录全部返回,自然达不到按fruit单字段去重的效果。
- 当你移除colour字段仅查询DISTINCT fruit时,去重判断维度只剩fruit一个字段,因此可以正常返回去重结果。
正确实现方案
你的需求核心是按fruit字段分组,每组仅返回1条记录的fruit、colour值,应该用GROUP BY实现,而非DISTINCT。
通用兼容写法(全数据库支持)
如果对同fruit下取哪个colour没有强制规则,或需要取最值,直接按fruit分组,用聚合函数取colour即可:
fruitVendor.findAndCountAll({ attributes: [ 'fruit', [Sequelize.fn('ANY_VALUE', Sequelize.col('colour')), 'colour'] ], group: ['fruit'] })
如果使用的数据库不支持ANY_VALUE(如低版本PostgreSQL),可以把聚合函数替换为MIN或MAX,比如Sequelize.fn('MIN', Sequelize.col('colour')),对你提供的示例数据来说,返回结果正好是[{fruit : apple, colour : green},{fruit : banana, colour : yellow}],完全符合预期。
指定取值规则的写法
如果需要明确指定同fruit下取哪条记录的colour(比如取price最高的记录对应的colour),可以用窗口函数实现:
fruitVendor.findAll({ attributes: ['fruit', 'colour'], where: Sequelize.literal(`id IN ( SELECT id FROM ( SELECT id, ROW_NUMBER() OVER (PARTITION BY fruit ORDER BY price DESC) AS rn FROM fruit_vendors ) AS tmp WHERE rn = 1 )`) })
提示:使用
findAndCountAll搭配group参数时,返回的count值是分组后的总条数,和去重后的结果数量一致;如果用窗口函数写法,需要单独编写count查询逻辑。
内容的提问来源于stack exchange,提问作者Sukil S
相关产品推荐
相关产品推荐

