简体   繁体   English

JPA Criteria Builder的求和列顺序

[英]JPA Criteria Builder order by a sum column

I have the following SQL query. 我有以下SQL查询。

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

I have used jpa criteria builder to build the query dynamically. 我已经使用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();

I debugged and checked the exact sql statement that is getting executed. 我调试并检查了正在执行的确切sql语句。

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

The resultant sql statement that is getting executed doesn't have the alias for colB as colB. 正在执行的结果sql语句没有colB的别名作为colB。 I am using MySql. 我正在使用MySql。 Surprisingly, this statement gets executed and I get proper results when sql mode is set to NO_ENGINE_SUBSTITUTION. 出乎意料的是,当sql模式设置为NO_ENGINE_SUBSTITUTION时,该语句得到执行,并且得到了正确的结果。 But when the sql mode is ONLY_FULL_GROUP_BY, the database throws an error saying 但是,当sql模式为ONLY_FULL_GROUP_BY时,​​数据库抛出错误,提示

Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'colB' which is not functionally dependent on columns in GROUP BY clause; ORDER BY子句的表达式#1不在GROUP BY子句中,并且包含非聚合列'colB',该列在功能上不依赖于GROUP BY子句中的列; this is incompatible with sql_mode=only_full_group_by 这与sql_mode = only_full_group_by不兼容

I understand that in this mode, sql validates the query and my query fails. 我知道在这种模式下,sql会验证查询,而我的查询将失败。 How do I create an alias with jpa criteria builder so that the actual statement getting executed contains a proper alias for the sum column? 如何使用jpa条件构建器创建别名,以便实际执行的语句包含sum列的适当别名?

Note: I use spring-data-jpa and this is a custom implementation of repository. 注意:我使用spring-data-jpa,这是一个自定义的仓库实现。 I can manually write the query using @Query annotation but the nature of the queries are dynamic on group by, order by, where clauses and the select columns. 我可以使用@Query注释手动编写查询,但是查询的性质在group by,order by,where子句和select列上是动态的。 Hence the need for a dynamic criteria builder implementation. 因此,需要动态标准构建器实施。

Try sorting over the aggregate. 尝试对汇总进行排序。 In my experience, column aliases usually can't be referenced in the query itself. 以我的经验,列别名通常不能在查询本身中引用。

orders.add(builder.desc(builder.sum(sumColumn)));

i think so you have bug in orderingColumns , you schould add colA instead colB 我认为您在orderingColumns有错误,应该选择添加colA而不是colB

or instead 或者

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

you can use 您可以使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM