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

Spring Data JPA原生查询转DTO时PostgreSQL语法错误求助

问题解决:PostgreSQL语法错误(syntax error at or near "(")

报错信息

Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "("
  Position: 26

相关代码与环境

Repository层代码

@Query(value = "select new AgendamentoDTO(a.id, a.data, s.nome, p.nome, pro.nome) " + 
               "from agendamento a " + 
               "join pacientes p on p.id = a.paciente_id " + 
               "join profissionais pro on pro.id = a.profissional_id " + 
               "join servico s on s.id = a.servico_id", nativeQuery = true)
List<AgendamentoDTO> agendamentos3();

DTO类代码

@Data
@NoArgsConstructor
public class AgendamentoDTO {
    private Integer id;
    private String data;
    private String servico;
    private String paciente;
    private String profissional;

    public AgendamentoDTO(Integer id, String paciente, String data, String profissional, String servico) {
        this.id = id;
        this.data = data;
        this.servico = servico;
        this.paciente = paciente;
        this.profissional = profissional;
    }
}

使用环境

  • SpringData 2.7.0
  • 数据库:PostgreSQL

问题原因与解决办法

原因

开启nativeQuery = true后,执行的是PostgreSQL原生SQL,但你在语句里用了JPQL独有的new AgendamentoDTO(...)构造对象语法,PostgreSQL无法识别该语法,直接触发报错。

解决办法

方案1:关闭原生查询(推荐)

删除nativeQuery = true,让Spring Data执行JPQL查询,JPQL支持直接通过构造方法实例化DTO:

@Query(value = "select new AgendamentoDTO(a.id, p.nome, a.data, pro.nome, s.nome) " + 
               "from Agendamento a " + 
               "join a.paciente p " + 
               "join a.profissional pro " + 
               "join a.servico s")
List<AgendamentoDTO> agendamentos3();

注意两点:

  1. 把数据库表名替换为实体类名(比如agendamento改成Agendamento),用实体类属性名代替数据库列名;
  2. 构造参数顺序必须和DTO构造方法完全匹配——你的DTO构造方法参数顺序是id, paciente, data, profissional, servico,所以JPQL里要对应写成a.id, p.nome, a.data, pro.nome, s.nome,之前的顺序错误,就算语法修复也会导致字段赋值混乱。

方案2:保留原生查询,手动映射结果

如果必须用原生SQL,去掉new AgendamentoDTO(...),直接查询字段并设置别名,让Spring Data自动映射到DTO:

@Query(value = "select a.id, p.nome as paciente, a.data, pro.nome as profissional, s.nome as servico " + 
               "from agendamento a " + 
               "join pacientes p on p.id = a.paciente_id " + 
               "join profissionais pro on pro.id = a.profissional_id " + 
               "join servico s on s.id = a.servico_id", nativeQuery = true)
List<AgendamentoDTO> agendamentos3();

确保DTO的字段名和SQL里的别名完全一致,Spring Data就能自动把查询结果赋值到DTO对象中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:40:29