JPA原生查询获取下周到期条目时出现SQL语法错误求助
问题分析与解决方案
你的报错核心原因不是CURRENT_DATE和INTERVAL的语法问题,而是你在nativeQuery = true的原生SQL中使用了JPQL特有的new model.dto.EntryDTO(...)构造DTO的语法——PostgreSQL原生SQL根本不认识这种Java类构造的写法,所以解析到model.dto里的.时直接抛出语法错误,对应报错里的Position:21。
两种修复方案
方案1:改用JPQL(推荐,更符合JPA规范)
去掉nativeQuery = true,使用JPQL语法查询,同时调整日期逻辑(JPQL支持CURRENT_DATE,加一周可以直接用CURRENT_DATE + 7):
@Query(value = "SELECT new model.dto.EntryDTO(v.name, e.eNumber, e.dueDate, e.amount, eScan.scanTimestamp) " + "FROM Entry e " + "JOIN EntryScan eScan ON e.eNumber = eScan.eNumber " + "JOIN Ve v ON e.vId = v.id " + "WHERE e.dueDate BETWEEN CURRENT_DATE AND CURRENT_DATE + 7") List<EntryDTO> findAllDueNextWeek();
注意:
- JPQL中要使用Java实体类的属性名(比如
e.eNumber而非数据库字段e.e_number),确保和你的实体类定义一致 - 如果Entry和EntryScan实体间有关联关系,可以简化JOIN写法:
JOIN e.entryScan eScan,无需手动写ON条件
方案2:保持原生查询,通过结果映射获取DTO
如果必须用原生SQL,需要去掉JPQL的new语法,通过以下方式转换为DTO:
方式A:手动转换Object[]
先查询返回原始数组,再在业务层转换为DTO:
@Query(value = "SELECT v.name, e.e_number, e.due_date, e.amount, es.scan_timestamp " + "FROM entry e " + "JOIN entry_scan es ON e.e_number = es.e_number " + "JOIN ve v ON e.v_id = v.id " + "WHERE e.due_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '1 week'", nativeQuery = true) List<Object[]> findAllDueNextWeekRaw(); // 业务层转换逻辑 public List<EntryDTO> getDueNextWeekEntries() { return findAllDueNextWeekRaw().stream() .map(row -> new EntryDTO( (String) row[0], (String) row[1], (Date) row[2], (BigDecimal) row[3], (Timestamp) row[4] )) .collect(Collectors.toList()); }
方式B:使用@SqlResultSetMapping自动映射
在DTO类上定义结果集映射规则:
@SqlResultSetMapping( name = "EntryDTOMapping", classes = @ConstructorResult( targetClass = EntryDTO.class, columns = { @ColumnResult(name = "name", type = String.class), @ColumnResult(name = "e_number", type = String.class), @ColumnResult(name = "due_date", type = Date.class), @ColumnResult(name = "amount", type = BigDecimal.class), @ColumnResult(name = "scan_timestamp", type = Timestamp.class) } ) ) public class EntryDTO { // 匹配映射规则的构造函数 public EntryDTO(String name, String eNumber, Date dueDate, BigDecimal amount, Timestamp scanTimestamp) { // 构造逻辑 } // 其他属性、方法 }
然后查询时指定映射:
@Query(value = "SELECT v.name, e.e_number, e.due_date, e.amount, es.scan_timestamp " + "FROM entry e " + "JOIN entry_scan es ON e.e_number = es.e_number " + "JOIN ve v ON e.v_id = v.id " + "WHERE e.due_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '1 week'", nativeQuery = true, resultSetMapping = "EntryDTOMapping") List<EntryDTO> findAllDueNextWeek();
补充说明
你原来的PostgreSQL日期语法CURRENT_DATE AND (CURRENT_DATE + INTERVAL '1 week')是完全正确的,不需要修改——问题出在原生查询和JPQL语法的混用。
内容的提问来源于stack exchange,提问作者Programmer2B
相关产品推荐
相关产品推荐

