首页 > 解决方案 > 按顺序排列的 jOOQ 子查询

问题描述

我在 MySQL 8 数据库上按顺序使用子查询:

select * from series 
order by (select max(competition.competition_date) from competition 
          where competition.series_id = series.id) desc

但我没有找到用 jOOQ 做到这一点的方法。

我尝试了以下查询,但这无法编译:

dsl
   .selectFrom(SERIES)
   .orderBy(dsl.select(DSL.max(COMPETITION.COMPETITION_DATE))
               .from(COMPETITION).where(COMPETITION.SERIES_ID.eq(SERIES.ID)).desc())
   .fetch()

按顺序不支持子查询吗?

标签: javamysqljooq

解决方案


Select<R> extends Field<R>

有一个待处理的功能请求#4828Select<R> extend Field<R>. 这似乎很诱人,因为对于那些支持它的方言,jOOQ 已经在某种程度上支持嵌套记录。

但是我怀疑在这种情况下这是否真的是一个好主意,因为我所知道的(即我在哪里尝试过的)没有数据库支持投影多个列的标量子查询。可以在行值表达式谓词中使用这样的子查询,例如

(a, b) IN (SELECT x, y FROM t)

但这是另一回事,因为它仅限于谓词,而不是任意列表达式。jOOQ 已经通过各种DSL.row()重载支持它,例如

row(A, B).in(select(T.X, T.Y).from(T))

Select<Record1<T>> extends Field<T>

这绝对是可取的,因为SELECT仅投影一列类型的语句T实际上SQL 中的一个Field<T>,即标量子查询。但是在 Java 中让Select<Record1<T>>扩展Field<T>是不可能的。没有办法使用 Java 的泛型来表达这一点。如果我们想这样做,我们必须“重载”Select类型本身并创建

  • Select1<T1> extends Select<Record1<T1>>
  • Select2<T1, T2> extends Select<Record2<T1, T2>>
  • 等等

在那种情况下,Select1<T1>可能是一个特殊情况,扩展Field<T1>,而其他的将不参与这种类型层次结构。但是为了实现这一点,我们必须为每个投影度Select复制整个DSL API ,即复制 22 次,这可能不值得。jOOQ API中已经有67种类型,截至 jOOQ 3.13。这使得即使仅针对标量子查询(即针对.Select.*StepSelect1

使用DSL.field(Select<Record1<T>>)及相关API

你已经找到了正确的答案。虽然Select<Record1<T>>不能扩展Field<T>,但我们可以接受Select<? extends Record1<T>>大量的 API,作为对通常重载的T|Field<T>重载。偶尔会这样做,并且可能会在整个 API 中更彻底地完成:https ://github.com/jOOQ/jOOQ/issues/7240 。

它对您没有帮助,因为您想调用.desc()列表达式 (the Select),而不是 wrap 将其传递给方法,所以我们回到了前面提到的 Java 限制。

Kotlin 和其他语言

但是,如果您使用 Kotlin 或其他具有某种方式提供“扩展功能”的语言,则可以使用以下方法:

inline fun <T> Select<Record1<T>>.desc(): SortField<T> {
    return DSL.field(this).desc();
}

jOOQ 将来可能会开箱即用地提供这些:https ://github.com/jOOQ/jOOQ/issues/6256


推荐阅读