jOOQ 子查询顺序

jOOQ Subquery in Order By

我在 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()

子查询不支持order by吗?

将子查询转换为 Field 有效:

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

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 的一列实际上 Field<T> 在 SQL,即标量子查询。但是让 Select<Record1<T>> 扩展 Field<T> 在 Java 中是不可能的。使用 Java 的泛型无法表达这一点。如果我们想这样做,我们必须 "overload" Select 类型本身并创建

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

在那种情况下,Select1<T1> 可能是一个特例,扩展了 Field<T1>,其他的不会参与这种类型层次结构。但为了实现这一点,我们必须复制整个 Select DSL API per projection degree,即复制 22 次,这可能不是值得。截至 jOOQ 3.13,已经有 67 Select.*Step types in the jOOQ API。这使得即使仅针对标量子查询也很难证明增强的合理性,即 Select1.

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

. While Select<Record1<T>> cannot extend Field<T>, we can accept Select<? extends Record1<T>> in plenty of API, as an overload to the usual T|Field<T> overloads. This has been done occasionally, and might be done more thoroughly throughout the API: https://github.com/jOOQ/jOOQ/issues/7240.

这对你没有帮助,因为你想在列表达式(Select)上调用 .desc(),而不是将它包装传递给一个方法,所以我们回到Java之前提到的限制。

Kotlin 和其他语言

但是,如果您使用的是 Kotlin 或其他能够以某种方式提供 "extension functions" 的语言,您可以使用这种方法:

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

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