如何让SQL的WHERE IN()查询不忽略重复条目?
解决重复餐食ID的成分统计问题
问题核心:使用IN子句时,重复的餐食ID会被自动去重,导致同一餐食的成分只被统计一次,无法满足重复餐食的累加需求。
解决方案:用临时数据集关联替代IN子句
通过构造包含所有重复ID的临时数据集,再与原表关联,确保每个ID实例都被纳入计算。
修改后的SQL查询(以PostgreSQL为例,不同数据库VALUES语法可能略有差异)
SELECT s.nazwa, SUM(ps.wartosc * (pwp.wartosc / 100)/pwp.liczba_porcji_posilku) as ilosc_skladnika, s.jednostka, s.grupa_skladnikow_odzywczych FROM -- 这里传入所有餐食ID,包括重复项 (VALUES (1), (3), (4), (1), (5) ) AS temp(posilek_id) JOIN posilki_produkty pwp ON pwp.posilek_id = temp.posilek_id JOIN produkty_skladniki ps USING (produkt_id) JOIN skladniki s USING (skladnik_id) GROUP BY skladnik_id, s.nazwa, s.jednostka, s.grupa_skladnikow_odzywczych ORDER BY s.kolejnosc
Java端适配代码(以JPA原生查询为例)
修改mealService.checkIngredientsOverall方法,动态生成包含所有重复ID的VALUES子句,避免SQL注入:
public List<Object[]> checkIngredientsOverall(List<Long> ids) { StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("SELECT s.nazwa, SUM(ps.wartosc * (pwp.wartosc / 100)/pwp.liczba_porcji_posilku) as ilosc_skladnika, s.jednostka, s.grupa_skladnikow_odzywczych "); sqlBuilder.append("FROM (VALUES "); // 生成带参数占位符的VALUES部分 for (int i = 0; i < ids.size(); i++) { if (i > 0) { sqlBuilder.append(", "); } sqlBuilder.append("(?").append(i).append(")"); } sqlBuilder.append(") AS temp(posilek_id) "); sqlBuilder.append("JOIN posilki_produkty pwp ON pwp.posilek_id = temp.posilek_id "); sqlBuilder.append("JOIN produkty_skladniki ps USING (produkt_id) "); sqlBuilder.append("JOIN skladniki s USING (skladnik_id) "); sqlBuilder.append("GROUP BY skladnik_id, s.nazwa, s.jednostka, s.grupa_skladnikow_odzywczych "); sqlBuilder.append("ORDER BY s.kolejnosc"); Query query = entityManager.createNativeQuery(sqlBuilder.toString()); // 绑定每个ID参数 for (int i = 0; i < ids.size(); i++) { query.setParameter("" + i, ids.get(i)); } return query.getResultList(); }
如果用MyBatis,可通过<foreach>标签简化VALUES生成:
<select id="checkIngredientsOverall" resultType="java.lang.Object[]"> SELECT s.nazwa, SUM(ps.wartosc * (pwp.wartosc / 100)/pwp.liczba_porcji_posilku) as ilosc_skladnika, s.jednostka, s.grupa_skladnikow_odzywczych FROM (VALUES <foreach collection="ids" item="id" separator=","> (#{id}) </foreach> ) AS temp(posilek_id) JOIN posilki_produkty pwp ON pwp.posilek_id = temp.posilek_id JOIN produkty_skladniki ps USING (produkt_id) JOIN skladniki s USING (skladnik_id) GROUP BY skladnik_id, s.nazwa, s.jednostka, s.grupa_skladnikow_odzywczych ORDER BY s.kolejnosc </select>
原理说明
临时数据集保留了所有重复的餐食ID,通过JOIN操作让每个ID对应的餐食成分都被计算一次,最终SUM函数会自动累加重复餐食的成分值,完全匹配需求。
内容的提问来源于stack exchange,提问作者Callz
相关产品推荐
相关产品推荐

