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

Spring+Hibernate+H2使用FORMATDATETIME报错:unexpected token: 'yyyy.MM.dd'

解决HQL中使用FORMATDATETIME时报错"unexpected token: 'yyyy.MM.dd'"的问题

兄弟,这个问题我之前踩过坑,核心原因很明确:你用的是Hibernate的HQL(Hibernate Query Language)写查询,但FORMATDATETIME是H2数据库的原生SQL函数,HQL本身并不认识它,所以解析的时候会把yyyy.MM.dd当成未知令牌报错。

先把你给出的代码贴出来方便对照:

实体类代码

@Entity
public class Match {
    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    private Long id;
    private Date started;
    private Long time;
    /* Getters and setters here */
}

仓库类代码(片段)

@Repository
public interface MatchRepository extends CrudRepository<Match, Long> {
    @Query("SELECT IFNULL(sum(m.time), 0) FROM Match m where m.time >= 180000 AND m.time <= 1200000")
    long getTotalQualifiedTime();
    // 你提到的带FORMATDATETIME的查询应该类似这种(推测)
    // @Query("SELECT FORMATDATETIME(m.started, 'yyyy.MM.dd') FROM Match m")
    // List<String> getFormattedStartDates();
}

接下来给你两种可行的解决方案,按需选择:


方案1:直接用原生SQL查询(适配H2)

如果你只需要适配H2数据库,最直接的方式是把查询标记为原生SQL,让Hibernate跳过HQL解析,直接把语句传给H2执行。只需要在@Query注解里加nativeQuery=true参数,同时注意H2的FORMATDATETIME参数顺序(第一个是日期,第二个是格式):

@Repository
public interface MatchRepository extends CrudRepository<Match, Long> {
    // 原生SQL示例:格式化started字段
    @Query(value = "SELECT FORMATDATETIME(m.started, 'yyyy.MM.dd') FROM Match m", nativeQuery = true)
    List<String> getFormattedStartDates();

    // 你的原有统计查询也可以改成原生SQL(如果需要)
    @Query(value = "SELECT IFNULL(sum(m.time), 0) FROM Match m where m.time >= 180000 AND m.time <= 1200000", nativeQuery = true)
    long getTotalQualifiedTime();
}

方案2:用HQL的FUNCTION语法(保持跨库兼容性)

如果你以后可能切换数据库(比如换成MySQL、PostgreSQL),建议用HQL提供的FUNCTION语法,让Hibernate自动把函数调用转换成对应数据库的原生实现:

@Repository
public interface MatchRepository extends CrudRepository<Match, Long> {
    // HQL方式:通过FUNCTION调用数据库原生函数
    @Query("SELECT FUNCTION('formatdatetime', m.started, 'yyyy.MM.dd') FROM Match m")
    List<String> getFormattedStartDates();
}

这种方式的好处是,后续换数据库时,只要目标数据库有同名的日期格式化函数(或者配置Hibernate的函数映射),不用大幅修改查询语句。


额外小提醒

  • 检查你的H2版本,确保FORMATDATETIME函数是支持的(H2 1.4.197及以上版本都支持)。
  • 如果查询里同时用到聚合和日期格式化,记得加分组(比如GROUP BY FUNCTION('formatdatetime', m.started, 'yyyy.MM.dd')),避免分组错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:47:09