JPA Criteria Builder按总和列排序

时间:2017-04-28 09:33:41

标签: java mysql jpa spring-data-jpa

我有以下SQL查询。

select colA, sum(colB) as colB from tableA group by colA order by colB desc;

我已经使用jpa标准构建器动态构建查询。

List<String> selectCols = new ArrayList<>();
selectCols.add("colA");
List<String> sumColumns = new ArrayList<>();
sumColumns.add("colB");
List<String> groupByColumns = new ArrayList<>();
groupByColumns.add("colA");
List<String> orderingColumns = new ArrayList<>();
orderingColumns.add("colB");

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cQuery = builder.createQuery(Tuple.class);
Root<T> root = cQuery.from(getDomainClass());

List<Selection<?>> selections = new ArrayList<>();
for (String column : selectCols) {
    selections.add(root.get(column).alias(column));
}

if (sumColumns != null) {
    for (String sumColumn : sumColumns) {
        selections.add(builder.sum(root.get(sumColumn)).alias(sumColumn));
    }
}

cQuery.multiselect(selections);

List<Expression<?>> groupByExpressions = new LinkedList<>();

for (String column : groupByColumns) {
    groupByExpressions.add(root.get(column));
}

cQuery.groupBy(groupByExpressions);

List<Order> orders = new ArrayList<>();

for (String orderCol : orderingColumns) {

    orders.add(builder.desc(root.get(orderCol)));

}

cQuery.orderBy(orders);

entityManager.createQuery(cQuery).getResultList();

我调试并检查了正在执行的确切sql语句。

select colA as col_1_0, sum(colB) as col_2_0 from tableA group by colA order by colB desc;

正在执行的结果sql语句没有colB的别名为colB。我正在使用MySql。令人惊讶的是,当sql模式设置为NO_ENGINE_SUBSTITUTION时,此语句将被执行并获得正确的结果。但是当sql模式为ONLY_FULL_GROUP_BY时,​​数据库会抛出错误说

  

ORDER BY子句的表达式#1不在GROUP BY子句中   包含非聚集列'colB',它不是功能上的   依赖于GROUP BY子句中的列;这是不相容的   的sql_mode = only_full_group_by

据我所知,在这种模式下,sql验证查询,我的查询失败。如何使用jpa条件构建器创建别名,以便执行的实际语句包含sum列的正确别名?

注意:我使用spring-data-jpa,这是存储库的自定义实现。我可以使用@Query注释手动编写查询,但查询的性质在group by,order by,where子句和select列上是动态的。因此需要动态标准构建器实现。

1 个答案:

答案 0 :(得分:1)

我认为你在orderingColumns中有错误,你可以添加colA代替colB

或者

for (String orderCol : orderingColumns) {
    orders.add(builder.desc(root.get(orderCol)));
}

你可以使用

orders.add(builder.desc(root.get("colA")));