【问题标题】:jOOQ agregate function over multiple tablesjOOQ 在多个表上的聚合函数
【发布时间】:2017-10-09 16:26:56
【问题描述】:

我们有一个存储记录的MAINTABLE。记录可以通过子表内的外键连接到CHILDTABLE1CHILDTABLE2内的子元素。

API 允许从MAINTABLE 接收对象列表。这些列表可以使用不同的策略(如字母等)进行排序。一种排序策略按最新的子元素对来自MAINTABLE 的对象进行排序。

例如:返回项目 (MAINTABLE) 排序在这些项目中的最新事件之后(CHILDTABLE1CHILDTABLE2)。

为此,我想要一个具有来自CHILDTABLES 的最大值的字段。如果用户想要使用此排序策略,则可以在 MAINTABLE 的“order by”语句中使用该字段。

想法:

// field with the highest creation date of any child element
Field<Object> maxDate = DSL.select(DSL.max(
                DSL.select(CHILDTABLE1.CREATION_DATE)
                .from(CHILDTABLE1)
                .where(CHILDTABLE1.FK.equal(MAINTABLE.ID))
                .asField()
                .union(
                   DSL.select(CHILDTABLE2.CREATION_DATE)
                  .from(CHILDTABLE2)
                  .where(CHILDTABLE1.FK.equal(MAINTABLE.ID))
                  .asField()
                )
        )).asField("maxDate");

// main query over MAINTABLE which orders by maxDate of any child element
List<Record> queryResults = jooq.select(*)
   .select(maxDate)
   .from(MAINTABLE)
   .orderBy(maxDate)
   .fetch();

此查询不起作用,因为无法计算 maxDate。我想为maxDate 创建一个新字段,以保持主查询整洁,并且因为“order by”语句将从另一种方法动态填充。这种其他方法不知道主查询中新创建的字段,但可以访问maxDate 字段。

任何建议都会很好。

【问题讨论】:

  • 从您表达问题的方式来看,我假设您希望从CHILDTABLE1CHILDTABLE2 之间的联合中获得MAX(CREATION_DATE)。但是你想用那个maxDate 做什么?我的意思是,与MAINTABLE 有什么关系?也许,你能用一些示例数据和更有意义的“主查询”来支持你的用例吗?
  • 感谢您的回复。在我的案例项目中,主查询返回一个对象列表。项目具有子元素任务和成员。项目、任务和成员具有所有 CREATION_DATE 字段。接收项目列表的 API 有不同的排序策略,如字母等。大多数排序策略很简单,只需在项目中使用一列。但在这种情况下,我想为在项目内部最新事件之后订购的项目实施订购策略。以便项目列表从创建新用户或任务的项目开始。

标签: sql aggregate-functions jooq


【解决方案1】:

让我们先看看如何用 SQL 编写这个查询。

据我了解,您想从MAINTABLE 中获取数据,并按CHILDTABLE[N] 中的最新对应条目排序。这可以按如下方式完成:

SELECT maintable.*
FROM maintable
JOIN (
  SELECT fk, max(creation_date) max_creation_date
  FROM (
    SELECT fk, creation_date
    FROM child_table1
    UNION ALL
    SELECT fk, creation_date
    FROM child_table2
  ) child_tables
  GROUP BY fk
) max_creation_dates
ON maintable.id = max_creation_dates.fk
ORDER BY max_creation_dates.max_creation_date DESC

当然,还有其他方法可以解决这个问题,例如您可以使用窗口函数或CROSS APPLY,具体取决于您的数据库。

把它翻译成 jOOQ

这是最简单的部分。在 jOOQ 中,您可以在“外部查询”中使用派生表之前将它们存储在局部变量中。我将重复使用与以前相同的名称:

Table<?> childTables = table(
   select(CHILD_TABLE1.FK, CHILD_TABLE1.CREATION_DATE)
  .from(CHILD_TABLE1)
  .unionAll(
   select(CHILD_TABLE2.FK, CHILD_TABLE2.CREATION_DATE)
  .from(CHILD_TABLE2)))
  .as("child_tables");

Table<?> maxCreationDates = table(
   select(
     childTables.field(CHILD_TABLE1.FK),
     max(childTables.field(CHILD_TABLE1.CREATION_DATE)).as("max_creation_date"))
  .from(childTables)
  .groupBy(childTables.field(CHILD_TABLE1.FK)))
  .as("max_creation_dates");

然后,您可以在实际查询中使用派生表:

using(configuration)
  .select(MAINTABLE.fields())
  .from(MAINTABLE)
  .join(maxCreationDates)
  .on(MAINTABLE.ID.eq(maxCreationDates.get(CHILD_TABLE1.FK)))
  .orderBy(maxCreationDates.get("max_creation_date").desc())
  .fetch();

以上暗示你有这个静态导入:

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

【讨论】:

  • 两个注意事项:1) 我需要maxcreationDate.find(...) 而不是maxCerationDates.get(..) 2) 我还在childTables 中包含MAINTABLECREATION_DATE。为了使代码看起来更干净,我使用.unionAll().unionAll()... 而不是.unionAll(.unionAll(...))
猜你喜欢
  • 2012-08-07
  • 1970-01-01
  • 2013-02-22
  • 2019-06-12
  • 1970-01-01
  • 2022-08-03
  • 1970-01-01
  • 2019-03-25
  • 1970-01-01
相关资源
最近更新 更多