You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 12:47:50