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

QueryDSL转SQL时第二个常量出现$p引发语法错误

问题

在SpringBoot项目中为了性能优化使用QueryDSL编写查询逻辑,代码如下:

Double aSumAll = select(tableA.sumColumn.sum())
        .from(tableA)
        .where(tableA.tableAnother.id.eq(tableAnotherId))
        .fetchOne();
if (aSumAll == null) aSumAll = 1.0;
Double bSumAll = select(tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight).sum())
        .from(tableA)
        .innerJoin(tableA.tableAnotherB, tableAnotherB)
        .where(tableA.tableAnother.id.eq(tableAnotherId))
        .fetchOne();
if (bSumAll == null) bSumAll = 1.0;

return select(Projections.constructor(tableAResponseDto.class,
        tableA.id,
        tableAnotherD.id,
        tableAnotherD.unitNm,
        tableAnotherC.id,
        tableAnotherC.itemNm,
        tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight),
        tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight)
                .divide(Expressions.constant(aSumAll)),
        tableA.sumColumn,
        tableA.sumColumn
                .divide(Expressions.constant(bSumAll)),
        Expressions.constant(bSumAll),
        Expressions.constant(aSumAll)))
        .from(tableA)
        .innerJoin(tableA.tableAnotherB, tableAnotherB)
        .innerJoin(tableA.tableAnotherB.tableAnotherC, tableAnotherC)
        .innerJoin(tableA.tableAnotherD, tableAnotherD)
        .where(tableA.tableAnother.id.eq(tableAnotherId))
        .orderBy(tableA.id.asc())
        .fetch();

生成的SQL中,第二个除法表达式的cast语句出现了$p参数(标注处):

select
    fpo1_0.id,
    fpo1_0.another_d_id,
    fup1_0.unit_nm,
    fp1_0.another_c_id,
    oi1_0.item_nm,
    (fpo1_0.sum_column*oi1_0.weight),
    ((fpo1_0.sum_column*oi1_0.weight)/cast(3084.3474 as float(53))),
    fpo1_0.sum_column,
    (fpo1_0.sum_column/cast(1834.3474 as float($p))) -- here
from
    table_a fpo1_0 
join
    table_another_b fp1_0 
        on fp1_0.id=fpo1_0.another_b_id 
join
    table_another_c oi1_0 
        on oi1_0.id=fp1_0.another_c_id
join
    table_another_d fup1_0 
        on fup1_0.id=fpo1_0.another_d_id 
where
    fpo1_0.another_id = 'testValue' 
    and fpo1_0.table_another_id=9 
order by
    fpo1_0.id;

这导致语法错误:

ERROR: syntax error at or near "$"

尝试将.divide方法中的Expressions.constant(aSumAll)和Expressions.constant(bSumAll)替换为直接使用aSumAll、bSumAll,问题仍未解决。请问为何会出现该$p参数?

分析与解决

原因

这是QueryDSL处理Double类型常量时的类型转换BUG:

  • 当传入Double类型常量(无论是通过Expressions.constant()还是直接传变量),QueryDSL自动推断SQL类型时,错误地将float类型的精度参数识别为绑定参数(即$p),而非直接写入固定精度值。
  • 该问题多出现于QueryDSL与PostgreSQL等数据库的适配逻辑中,底层类型处理模块未正确处理Double常量的精度配置。

解决方法

  1. 显式指定常量的SQL类型
    使用Expressions.constant()时明确指定类型,避免自动推断出错:

    // 方式1:指定Java类型
    tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight)
            .divide(Expressions.constant(aSumAll, Double.class))
    // 方式2:指定数据库特定类型(如PostgreSQL的Float8Type)
    tableA.sumColumn.divide(Expressions.constant(bSumAll, Float8Type.DEFAULT))
    
  2. 绕开自动类型转换
    将Double值转为字符串后再转为数值表达式,规避类型推断逻辑:

    tableA.sumColumn.divide(Expressions.asNumber(bSumAll.toString()))
    
  3. 升级QueryDSL版本
    该BUG在QueryDSL 5.x及以后的稳定版本中已被修复,直接升级依赖即可解决底层适配问题。

内容的提问来源于stack exchange,提问作者Vincent

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 10:53:11