【问题标题】:How to fetch groups ordered by aggregative value, using jooq如何使用 jooq 获取按聚合值排序的组
【发布时间】:2021-03-24 04:58:35
【问题描述】:

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

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

现在,jooq 提供了 fetchGroups(),可以完美地将值映射到 Map

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

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

【问题讨论】:

    标签: java group-by grouping aggregate-functions jooq


    【解决方案1】:

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

    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&lt;Integer&gt; 类型而不是 Integer[] 类型,则可以在 ResultQuery.collect() 上使用 JDK Collector API,而不是:

    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())
          ));
    

    【讨论】:

    • 值得一提的是 Result#intoGroup() 目前是使用 LinkedHashMap 实现的,它保证了初始顺序的保留(当然这是一个未记录的实现细节,可能会改变)
    • @AmitGoldstein:有道理。它在某些地方有记录,但在其他地方没有。虽然我们不保证 LinkedHashMap 的实现,但我们当然可以保证迭代顺序的稳定性(这是 LinkedHashMap 恰好做的)。我们会在不久的将来改进它:github.com/jOOQ/jOOQ/issues/11154
    猜你喜欢
    • 2015-02-10
    • 2014-11-17
    • 1970-01-01
    • 2014-08-30
    • 2013-02-03
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    相关资源
    最近更新 更多