首页 > 解决方案 > 如何使用 jooq 获取按聚合值排序的组

问题描述

我想使用 jooq 来实现这个查询:

SELECT bank_id, array_agg(id)
FROM aggregative_line_item
GROUP BY bank_id
ORDER BY sum(amount) desc;

现在,jooq 提供了 fetchGroups(),它完美地将值映射到 Map<String, List>

 create.selectFrom(aggregative_line_item)
            .fetchGroups(aggregative_line_item.bank_id, aggregative_line_item.id);

但是,我不明白如何按 sum() 值对返回的结果进行排序。

标签: javagroup-bygroupingaggregate-functionsjooq

解决方案


当您使用 时ResultQuery.fetchGroups(),您将在 Java 中而不是在 SQL 中对结果集进行分组。这有很多合理的案例,但就您而言,我认为您应该直接在 SQL 中执行所有操作,假设您使用的是 PostgreSQL,因为您已经ARRAY_AGG()在 SQL 查询中使用过。写吧:

Result<Record2<String, Integer[]>> result =
create.select(AGGREGATIVE_LINE_ITEM.BANK_ID, arrayAgg(AGGREGATIVE_LINE_ITEM.ID))
      .from(AGGREGATIVE_LINE_ITEM)
      .groupBy(AGGREGATIVE_LINE_ITEM.BANK_ID)
      .orderBy(sum(AGGREGATIVE_LINE_ITEM.AMOUNT).desc())
      .fetch();

这假设通常的静态导入,包括:

import static org.jooq.impl.DSL.*;

结果与您要查找的形式不完全一致,但您仍然可以调用fetchMap()结果,例如

Map<String, Integer[]> map = result.fetchMap(
  AGGREGATIVE_LINE_ITEM.BANK_ID, 
  arrayAgg(AGGREGATIVE_LINE_ITEM.ID)
);

或者,您可以将它们分配给局部变量并重用它们,而不是重复表达式:

Field<String> key = AGGREGATIVE_LINE_ITEM.BANK_ID;
Field<Integer[]> value = arrayAgg(AGGREGATIVE_LINE_ITEM.ID);

// And then:
Map<String, Integer[]> map = 
create.select(key, value)
      .from(AGGREGATIVE_LINE_ITEM)
      .groupBy(AGGREGATIVE_LINE_ITEM.BANK_ID)
      .orderBy(sum(AGGREGATIVE_LINE_ITEM.AMOUNT).desc())
      .fetchMap(key, value);

不过,如果您更喜欢List<Integer>类型而不是Integer[]类型,则可以使用 JDK CollectorAPIResultQuery.collect()代替:

Map<String, List<Integer>> map = 
create.select(AGGREGATIVE_LINE_ITEM.BANK_ID, arrayAgg(AGGREGATIVE_LINE_ITEM.ID))
      .from(AGGREGATIVE_LINE_ITEM)
      .groupBy(AGGREGATIVE_LINE_ITEM.BANK_ID)
      .orderBy(sum(AGGREGATIVE_LINE_ITEM.AMOUNT).desc())
      .collect(Collectors.toMap(
         r -> r.value1(),
         r -> Arrays.asList(r.value2())
      ));

推荐阅读