构建涉及可选限制的动态 SQL 的最佳方法?

Best way to build dynamic SQL involving an optional limit?

在 JOOQ 中选择性地将 LIMIT 应用于查询的最佳方法是什么?我想 运行:

SelectSeekStepN<Record> readyToFetch = dslContext.select(selectFields).
    from(derivedTable).
    where(conditions).
    orderBy(orderForward);
if (length != Integer.MAX_VALUE)
    readyToFetch = readyToFetch.limit(length);

limit() returns SelectLimitPercentStep<Record> 不是 SelectSeekStepN<Record> 的子 class 所以我得到一个编译器错误。

另一方面,如果我将 readyToFetch 的 return 类型从 SelectSeekStepN<Record> 更改为与 return 类型兼容的 Select<Record> limit() 那么我就不能在 Select<Record> 上调用 limit()。我需要将其显式转换为 SelectSeekStepN<Record>.

有更好的方法吗?

也许JOOQ应该把Integer.MAX_VALUE当作一个特殊的值(没有限制)来让这种代码更容易写...

我深入研究了实现,发现还有另一种方法 limit(Number)null 值视为无限制。因此,代码可以写成:

Select<Record> readyToFetch = dslContext.select(selectFields).
    from(derivedTable).
    where(conditions).
    orderBy(orderForward).
    limit(length == Integer.MAX_VALUE ? null : length);

提供空操作以传递给 LIMIT

这样的子句

偶尔会有一个功能请求在 DSL API 中要求这样的 no-op 子句,这显然会很有帮助,特别是在 LIMIT 的情况下,目前还没有非 hacky 解决方法。不幸的是,除了您在问题中已经提到的解决方案之外,还没有好的解决方案来动态构建您的 SQL 查询。

对于大多数需要可选性的条款,类似于 DSL.noCondition() exists. A DSL.noTable() has been requested, but not yet implemented (as of jOOQ 3.14). Same with a "no-op" for LIMIT: https://github.com/jOOQ/jOOQ/issues/11551

使用动态获取正确的类型 SQL

您自己的问题已经包含了解决方案。这只是一个小的打字问题。您可能选择将中间步骤分配给 SelectSeekStepN,因为您的 IDE 建议使用这种类型。但是您可以改用任何超类型。

Select<Record> readyToFetch;
SelectLimitStep<Record> readyToLimit;

readyToFetch = readyToLimit = dslContext.select(selectFields).
    from(derivedTable).
    where(conditions).
    orderBy(orderForward);
if (length != Integer.MAX_VALUE)
    readyToFetch = readyToLimit.limit(length);
readyToFetch.fetch();

您可以从 ParserImpl 逻辑中获得一些灵感。它在所有地方都这样做。赋值表达式是一种祝福!

在条件表达式上使用类型推断的替代方法:

SelectLimitStep<Record> limit = dslContext.select(selectFields).
    from(derivedTable).
    where(conditions).
    orderBy(orderForward);

Result<?> result = (length != Integer.MAX_VALUE ? limit.limit(length) : limit).fetch();

使用 null 来明确表示缺少 LIMIT

使用 null 来表示缺少 LIMIT 是一个非常糟糕的主意,原因至少有 3 个:

  • 大多数 jOOQ API 将 (Field<?>) null 解释为 NULL 绑定值或 NULL 文字,从不作为缺失值。如果突然之间,我们仅在 LIMIT
  • 中为此目的使用 null,那将是非常令人惊讶的
  • 即使我们这样做了,我们也必须开始区分 null(对缺失值的内部解释)和 null(您作为用户向 jOOQ 提供的值 明确地)。所以,无论如何,我们在内部都需要一些 noLimit() 对象来进行区分,在这种情况下,为什么不将其公开为 API 而不是让你乱搞?
  • 一些方言支持 NULL 限制。 PostgreSQL 将其解释为不存在的 LIMIT(我觉得这很令人困惑,LIMIT 是“未知的”)。 Oracle 将其解释为 LIMIT 0,这更合理。其他方言(例如 MySQL)拒绝 LIMIT NULL 作为错误语法,这也是合理的。您建议 jOOQ 覆盖此行为并巧妙地重新解释它。我宁愿不要!