Jac*_*mok 5 postgresql hibernate jpa criteria-api spring-boot
我正在尝试使用 JPA 的 Criteria 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
}
Run Code Online (Sandbox Code Playgroud)
这个例子讨论了对我的“月”间隔进行分组(因此按年+月分组),但最后我正在寻找一种可以让我按任何间隔分组的解决方案,例如“年”、“日”或“分钟” ”。
我想要实现的是以下查询,但使用 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();
}
}
Run Code Online (Sandbox Code Playgroud)
我使用to_char
function 而 notMONTH
和 similar的原因是我需要像这样的实体2019-05
而2020-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
Run Code Online (Sandbox Code Playgroud)
对我来说,这是由于整个表达式被放入查询的“group by”部分,而不仅仅是别名。现在,我尝试为表达式分配一个别名(它返回Selection<T>
并且 groupBy 接受表达式,因此我只能在 中真正使用它multiselect
),但这并没有影响查询的执行方式 - 没有任何改变。
如何使用 Criteria API 实现上述按年和月分组?也许除了使用之外还有其他不同的方式to_char
?也许有一种方法可以为方法提供别名,groupBy
使其按别名而不是整个表达式进行分组?
我认为这是 PostgreSQL 中的一个错误(错误来自那里,而不是来自 Hibernate)。我已经尝试使用 EclipseLink + Derby 对您的代码进行了稍微修改的版本,并且运行良好。请注意,我必须使用数字而不是字符串,因为 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);
Run Code Online (Sandbox Code Playgroud)
这将返回以下 SQL:
SELECT (MONTH(MY_DATE) + (12 * YEAR(MY_DATE)))
FROM MY_DATE_TABLE
GROUP BY (MONTH(MY_DATE) + (12 * YEAR(MY_DATE)))
Run Code Online (Sandbox Code Playgroud)
请注意,没有用于在 JPA 标准查询中操作日期的可移植解决方案。如果要同时查询的组数不太高,我会采用更实用的方法,在 Java 中查找日期并将它们作为文字传递给查询生成器。
另一种解决方法是使用 a 进行查询groupBy(root.get("sellDate"))
,然后根据所需的时间段在 Java 中聚合结果。
Post Scriptum:我认为这不相关,但是我将查询的返回类型从 修改Object[]
为Object
。
归档时间: |
|
查看次数: |
987 次 |
最近记录: |