【问题标题】:Timestamp literal in JPQL typed query with Hibernate使用 Hibernate 的 JPQL 类型化查询中的时间戳文字
【发布时间】:2018-10-05 12:35:02
【问题描述】:

有没有办法通过 Hibernate 在 JPQL 查询中使用时间戳文字?

在 JPQL 查询中应该放置一个常量时间戳来比较。 现在它是这样工作的

TypedQuery<TestEntity> query = entityManager
.createQuery("select t from TestEntity t where greatest(nvl(t.f1, :nullDate), nvl(t.f2, :nullDate)) between :date1 and :date2")
.setParameter("date1", date1)
.setParameter("date2", date2)
.setParameter("nulllDate", LocalDateTime.of(1970, 1, 1, 0, 0, 0, 1))

我已经尝试(解决方案找到 herehere)将查询更改为以下内容

select t from TestEntity t where greatest(nvl(t.f1, {ts '1970-01-01 00:00:00:000000001'}), nvl(t.f2, {ts '1970-01-01 00:00:00:000000001'})) between :startChanges and :endChanges

但运行时出错

org.hibernate.QueryException: unexpected char: '{' [select t from TestEntity t where greatest(nvl(t.f1, {ts '1970-01-01 00:00:00:000000001'}), nvl(t.f2, {ts '1970-01-01 00:00:00:000000001'})) between :startChanges and :endChanges]

我的设置是
Java 8
JPA 2.1
Spring Boot 1.4.2.RELEASE
Hibernate 5.1.0.Final(也与 5.2.16.Final 一起转载)
甲骨文 11.2

UPD: 也许它不在规范中,但是使用上面的代码将最大/nvl 函数正确地从 JPQL 传递到 SQL。我尝试将greatest/nvl 包装在function 中,但仍不接受文字。

【问题讨论】:

  • JPA 规范在哪里定义了 greatest 的 JPQL 函数?或nvl?答:不会
  • @DN1 我已将查询字符串替换为更严格的 JPQL,通过“函数”调用最大/nvl,但它不会改变任何内容。它仍然接受参数并为其生成相同的 SQL,同时为文字抛出 unexpected char: '{' 错误。 select t from TestEntity t where function('greatest', function('nvl', t.f1, {ts '1970-01-01 00:00:00.000000001'}), function('nvl', t.f2, {ts '1970-01-01 00:00:00.000000001'})) between :startChanges and :endChanges
  • 根据@987654323,我可以使用 JDBC 转义语法(您使用的大括号和“ts”)与我的 JPA 提供程序没有问题(恕我直言,您的语法使用是有效的) @ 可以尝试一个不带函数调用的简单查询,并使用 JDBC 转义语法来检查您的 JPA 提供程序是否首先正确处理它,然后添加 FUNCTIONs。
  • @DN1 我尝试了一个非常基本的查询,没有条件,但有文字。它会导致相同的错误,看起来 Hibernate 5.1.0 不支持时间戳文字,至少使用这种语法。这至少是早期版本的问题stackoverflow.com/questions/8386109/…
  • 听起来你需要对它们提出错误

标签: java hibernate jpa jpql


【解决方案1】:

我在我的环境中准备了一个测试,它会返回结果:

Calendar calendar = Calendar.getInstance();
calendar.setTime(date1);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

date1 = calendar.getTime();

calendar.setTime(date2);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

date2 = calendar.getTime();

TypedQuery<TestEntity> query = entityManager
.createQuery("select t from TestEntity t where greatest(nvl(t.f1, TO_TIMESTAMP('1970-01-01 00:00:00,000000001', 'YYYY-MM-DD HH24:MI:SS,FF9')), nvl(t.f2, TO_TIMESTAMP('1970-01-01 00:00:00,000000001', 'YYYY-MM-DD HH24:MI:SS,FF9')) between :date1 and :date2")
.setParameter("date1", date1)
.setParameter("date2", date2);

我希望这就是你要找的。​​p>

编辑: 修改查询以添加TO_TIMESTAMP 函数。 @dfche 确认它正在工作

【讨论】:

  • 感谢您的代码,它也适用于我。但我试图避免将 nullDate 设置为参数,而是使用内联文字。
  • 你想使用字符串文字还是类?
  • @Alberto,TO_TIMESTAMP 是无效的 JPQL,请阅读 JPA 手册。该 JPA 手册会告诉您正在使用的表单的“时间戳文字”是完全有效的,而这个 JPA 提供者不喜欢它
  • 这对我有用:String consulta = "SELECT e FROM ExcepcionHistorico e WHERE greatest(nvl(tim_procx, TO_TIMESTAMP('2015-01-01 00:00:00,000000001', 'YYYY-MM-DD HH24:MI:SS,FF9')), nvl(tim_recept, TO_TIMESTAMP('2016-01-01 00:00:00,000000001', 'YYYY-MM-DD HH24:MI:SS,FF9'))) BETWEEN :date3 and :date4";。结果:Hibernate: select &lt;fields&gt; where greatest(nvl(excepcionh0_.tim_procx, TO_TIMESTAMP('2015-01-01 00:00:00,000000001', 'YYYY-MM-DD HH24:MI:SS,FF9')), nvl(excepcionh0_.tim_recept, TO_TIMESTAMP('2016-01-01 00:00:00,000000001', 'YYYY-MM-DD HH24:MI:SS,FF9'))) between ? and ?
  • @Alberto TO_TIMESTAMP 工作正常,谢谢。根据我的(非常简短的)测试,这两种形式(TIMESTAMP/TO_TIMESTAMP)在本机 SQL 选择方面没有性能差异。
猜你喜欢
  • 2023-03-23
  • 2019-02-26
  • 2020-08-18
  • 2020-11-20
  • 2014-08-01
  • 2021-11-10
  • 2019-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多