使用JPA的Criteria API按日期间隔分组

问题描述 投票:2回答:1

我正在尝试使用JPA的Criteria API按日期间隔对实体进行分组。我使用这种查询实体的方式,因为这是服务API请求的服务的一部分,API请求可能会要求任何实体的任何字段,包括排序,过滤,分组和聚合。除按日期字段分组外,其他一切正常。我的基础DBMS i PostgreSQL。

举个最小的例子,这是我的实体类:

@Entity
@Table(name = "receipts")
public class DbReceipt {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private Date sellDate;
    // Many other fields
}

[此示例讨论了对“月”间隔进行分组(因此按年+月分组),但最终,我正在寻找一种解决方案,该解决方案可以让我按任意间隔进行分组,例如“年”,“天”或“ “分钟”。

我想要实现的是以下查询,但使用的是Criteria API:

SELECT TO_CHAR(sell_date, 'YYYY-MM') AS alias1 FROM receipts GROUP BY alias1;

我这样做的尝试是:

@Service
public class ReceiptServiceImpl extends ReceiptService {
    @Autowired
    private EntityManager em;

    @Override
    public void test() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
        Root<?> root = query.from(DbReceipt.class);
        Expression<?> expr = cb.function("to_char", String.class, root.get("sellDate"), cb.literal("YYYY-MM"));

        query.groupBy(expr);
        query.multiselect(expr);

        TypedQuery<Object[]> typedQuery = em.createQuery(query);
        List<Object[]> resultList = typedQuery.getResultList();
    }
}

我使用to_char函数而不是MONTH的原因,类似的原因是,我需要像2019-052020-05这样的实体不被分组在一起。为了使内容简短,我也将示例缩小到仅年份和月份,但目标是按任意日期间隔进行分组。

上面的代码创建以下查询(启用SQL日志记录),这将导致错误:

Hibernate: select to_char(dbreceipt0_.sell_date, ?) as col_0_0_ from receipts dbreceipt0_ group by to_char(dbreceipt0_.sell_date, ?)
24-05-2020 12:16:30.071 [http-nio-1234-exec-5] WARN  o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - SQL Error: 0, SQLState: 42803
24-05-2020 12:16:30.071 [http-nio-1234-exec-5] ERROR o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - ERROR: column "dbreceipt0_.sell_date" must appear in the GROUP BY clause or be used in an aggregate function
  Position: 16

对我来说,是因为整个表达式都放在查询的“ group by”部分中,而不只是别名。现在,我尝试为表达式分配别名(该别名返回Selection<T>并且groupBy接受表达式,因此我只能在multiselect中使用它),但这并没有影响查询的执行方式-没什么变化。

如何使用Criteria API如上所述实现按年和月的分组?也许除了使用to_char以外还有其他方法吗?也许有一种方法可以给groupBy方法赋予别名,从而使它按别名而不是整个表达式分组?

postgresql hibernate spring-boot jpa criteria-api
1个回答
0
投票

我认为这是休眠的错误。我已经使用EclipseLink尝试过您的代码,并且可以正常工作。让我显示我的代码,请记住,我必须使用数字而不是字符串,因为我使用的Derby DB没有TO_CHAR函数的等效项。

Expression<Integer> year = cb.function("YEAR", Integer.class, root.get("sellDate"));
Expression<Integer> month = cb.function("MONTH", Integer.class, root.get("sellDate"));
Expression<Integer> expr = cb.sum(month, cb.prod(12, year));
query.groupBy(expr);
query.multiselect(expr);

这将返回以下SQL:

SELECT (MONTH(MY_DATE) + (12 * YEAR(MY_DATE))) 
FROM MY_DATE_TABLE 
GROUP BY (MONTH(MY_DATE) + (12 * YEAR(MY_DATE)))

Post Scriptum:我认为这无关紧要,但是我将查询的返回类型从Object[]修改为Object

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