JPA CriteriaQuery 计算用于 where 谓词的日期时间差异

问题描述 投票:0回答:4

我正在尝试从数据库中选择两个字段之间的时间差小于或大于某个值的实体。在标准 SQL 中,这可以使用 TIMESTAMPDIFF 函数轻松完成:

SELECT * from run where TIMESTAMPDIFF(SECOND, run.end_time, run.start_time) > 60;

但是,JPA 2.0 中似乎没有任何等效项。

我已经尝试了我能想到的一切,包括这里的建议:使用 TIMESTAMPDIFF 与 JPA 标准查询和 hibernate 作为提供者

predicate.getExpressions().add(criteriaBuilder.greaterThanOrEqualTo(criteriaBuilder.function("TIMESTAMPDIFF", Long.class, criteriaBuilder.literal("SECOND"), root.get(Run_.endTime), root.get(Run_.startTime)), minSeconds))

根本不起作用,因为我专门尝试计算较长的持续时间(60/90 天)。 TIMEDIFF 解决方案没有帮助,因为可以返回的最大 TIMEDIFF 是 35 天。还有其他方法可以实现这一点吗?

java jpa
4个回答
5
投票

这里是

的等效 JPA Criteria Query 的解释

SELECT * from run where TIMESTAMPDIFF(SECOND, run.end_time, 运行.start_time) > 60;

首先,您必须创建单位表达式并从

BasicFunctionExpression
扩展它,其中以“SECOND”参数作为单位并仅覆盖其
rendor(RenderingContext renderingContext)
方法。

import java.io.Serializable;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.expression.function.BasicFunctionExpression;

public class UnitExpression extends BasicFunctionExpression<String> implements Serializable {

  public UnitExpression(CriteriaBuilderImpl criteriaBuilder, Class<String> javaType,
      String functionName) {
    super(criteriaBuilder, javaType, functionName);
  }

  @Override
  public String render(RenderingContext renderingContext) {
    return getFunctionName();
  }
}

然后您可以在 JPA 标准查询中使用此单位表达式。

    CriteriaBuilder cb = session.getCriteriaBuilder();
    CriteriaQuery<Run> cq = cb.createQuery(Run.class);
    Root<Run> root = cq.from(Run.class);

    Expression<String> second = new UnitExpression(null, String.class, "SECOND");
    Expression<Integer> timeDiff = cb.function(
        "TIMESTAMPDIFF",
        Integer.class,
        second,
        root.<Timestamp>get(Run_.endTime),
        root.<Timestamp>get(Run_.startTime));
    List<Predicate> conditions = new ArrayList<>();
    conditions.add(cb.greaterThan(timeDiff, 60));
    cq.where(conditions.toArray(new Predicate[]{}));
    return session.createQuery(cq);

它正在工作。


2
投票
Expression<String> month = new MyFunctionExpression(null, String.class, "MONTH");
Expression<Integer> diff = builder.function("timestampdiff", Integer.class, month, root.get(Run_.endTime), root.get(Run_.startTime));
predicates.add(builder.gt(diff, 60));

MyFunctionExpression 扩展了 BasicFunctionExpression 并重写了 render 方法。

@Override
public String render(RenderingContext renderingContext) {
    return getFunctionName();
}

1
投票

抱歉,JPA 不支持 datediff 函数。如果您使用 eclipselink,您可以使用 FUNC 关键字,它调用 DB 的本机函数。否则,您需要使用本机查询。


0
投票

出现此错误:

您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在第 1 行的 ''SECOND'、abc.email_date、xyz.last_click_date)>=5)) 和 (lead0' 附近使用的正确语法

解决了处理程序执行引起的异常:org.springframework.dao.InvalidDataAccessResourceUsageException:无法提取ResultSet; SQL [不适用];嵌套异常是 org.hibernate.exception.SQLGrammarException:无法提取 ResultSet

在 AWS 日志中收到此错误,但单元测试用例运行正常。我该如何解决这个问题?

© www.soinside.com 2019 - 2024. All rights reserved.