目标是根据客户的UTC时间(也就是说,应将客户的时区偏移量添加到时间戳中),按月/日/小时对使用GMT 0时间戳存储的数据进行分组。
在SQL中,查询应该看起来像(按天分组时):
SELECT *
FROM myentity
GROUP BY dayofweek ( date_add (mytimestampcolumn, INTERVAL timezonedifference hours ))
在JPA中,以下代码运行良好,因为"星期几"是JPA的已知(注册)函数:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
Expression<Integer> timeUnitFunction = criteriaBuilder.function("dayofweek", Integer.class, from.<Date>get("timestampColumn"));
query.groupBy(timeUnitFunction);
然而,它没有考虑时区偏移,所以我想使用另一个db函数,并将第二行更改为类似的内容:
criteriaBuilder.function("dayofweek", Integer.class, criteriaBuilder.function("date_add", Date.class, "hour", timezoneDifferece, from.<Date>get("timestampColumn")))
据我所见,只有ADD_DATE
和ADD_TIME
没有注册JPA函数。
使用自定义方言来计算简单的时区偏移量似乎有些过头了。
任何关于可操作时间戳或任何其他方式以获得所需结果的替代JPA注册函数的建议(在不同的时区偏移上按月/日/小时正确分组)都将不胜感激。
编辑:正如Neil所评论的,date_add和任何其他SQL函数都可以由CriteriaBuilder
的函数方法调用。
然而,我无法提供date_add所需的"INTERVAL-expr-unit"格式的参数(使用CriteriaBuilder.literal
创建字符串表达式不起作用)。
使用SQL"convert_tz"函数以字符串文字作为时区值,解决了问题。
您可以使用cb.function(sqlFuncName, args)
方法来调用任何SQL函数。参数是表达式,根据SQL函数的需要传入任意数量。如果这些参数是文字,则可以使用cb.literal(value)
将其转换为表达式。
也许有了这些组件,你就可以生成符合你目的的东西。请注意,通过调用SQL函数,您可能会失去RDBMS的可移植性,但这可能与您的情况无关。