【发布时间】:2017-09-26 08:59:23
【问题描述】:
我有以下 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 子句和选择列上是动态的。因此需要动态标准构建器实现。
【问题讨论】:
-
您想通过选择列中的 sum(colB) 对结果进行排序吗?如果是这样,您是否尝试使用 builder.desc(builder.sum(root.get(orderCol))) 其中 orderCol 指向 colB ?
-
我想使用别名来做到这一点。因为我在运行时不知道按列排序是总和列还是普通列。这就是为什么我创建了 sum 列的别名作为列名本身。
-
好的,只是大声思考。您是否尝试将别名“colB”赋予与任何列名都不匹配的其他名称?
-
<snide-remark>生成一个简单的SQL语句需要这么多代码??显然,有这么多代码有助于弄错。</snide-remark> -
这么多代码使查询动态化。
标签: java mysql jpa spring-data-jpa