我正在尝试在按任务名称分组的单个表中选择记录的最新实例。
以前,已经使用了本地@Query,但是随着需求的增长,我们决定将其重写为Specification和JPA Criteria API。
简单的规范很清楚,但是我对创建谓词仅选择具有最新scheduleTime的实例感到困惑
任何建议都是有价值的,谢谢!
CREATE TABLE task
(
id text NOT NULL,
applicationid text NOT NULL,
taskname VARCHAR(255),
scheduletime TIMESTAMP WITH TIME ZONE
);
@Query("SELECT t " +
" FROM Task t " +
" WHERE t.applicationId = :applicationId" +
" AND t.id NOT IN " +
" (SELECT t1.id " +
" FROM Task t1, Task t2 " +
" WHERE t1.applicationId = t2.applicationId " +
" AND t1.taskname = t2.taskname " +
" AND t1.scheduleTime < t2.scheduleTime)")
Blockquote
数据:
+ ------------------------------------------- +
| id applicationId任务名scheduletime |
+ ------------------------------------------- +
| 1个app1 task1 2019-01-01 10:00 |
| 2 app1 task1 2019-01-01 10:20 |
| 3 app1 task2 2019-01-01 09:00 |
| 4 app1 task2 2019-01-01 09:20 |
+ ------------------------------------------- +
应导致:
+ ------------------------------------------- +
| id applicationId任务名scheduletime |
+ ------------------------------------------- +
| 2 app1 task1 2019-01-01 10:20 |
| 4 app1 task2 2019-01-01 09:20 |
+ ------------------------------------------- +
此代码给出了无法提取ResultSet的内容; SQL [n / a];嵌套的异常是org.hibernate.exception.SQLGrammarException:无法提取ResultSet
public static Specification<Task> recent(boolean recent) {
return (root, query, cb) -> {
if (recent) {
Subquery<Task> subquery = query.subquery(Task.class);
Root<Task> subRoot1 = subquery.from(Task.class);
Root<Task> subRoot2 = subquery.from(Task.class);
subquery.select(subRoot1);
subquery.where(cb.equal(subRoot2.get("applicationId"), subRoot1.get("applicationId")));
subquery.where(cb.equal(subRoot2.get("taskname"), subRoot1.get("taskname")));
subquery.where(cb.lessThan(subRoot1.get("scheduleTime"), subRoot2.get("scheduleTime")));
return cb.in(subquery).not();
}
return cb.isTrue(cb.literal(true));
};
}
答案 0 :(得分:0)
只需弄清楚该怎么做。这段代码有效:
public static Specification<Task> recent(boolean recent) {
return (root, query, builder) -> {
if (recent) {
Subquery<Instant> subquery = query.subquery(Instant.class);
Root<Task> subRoot = subquery.from(Task.class);
subquery.select(builder.greatest(subRoot.<Instant>get("scheduleTime")));
subquery.where(builder.equal(subRoot.get("applicationId"), root.get("applicationId")));
subquery.where(builder.equal(subRoot.get("taskname"), root.get("taskname")));
return builder.equal(root.get("scheduleTime"), subquery);
} else {
return builder.isTrue(builder.literal(true));
}
};
}
棘手的部分是将<Instant>
类型添加到subRoot.get()。否则会在构建时抛出异常异常