选择按其他属性分组的属性中具有最大值的表行

时间:2019-06-10 06:46:10

标签: spring jpa

我正在尝试在按任务名称分组的单个表中选择记录的最新实例。

以前,已经使用了本地@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));
        };
    }

1 个答案:

答案 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()。否则会在构建时抛出异常异常