构建涉及可选限制的动态 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 覆盖此行为并巧妙地重新解释它。我宁愿不要!
在 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
(您作为用户向 jOOQ 提供的值 明确地)。所以,无论如何,我们在内部都需要一些noLimit()
对象来进行区分,在这种情况下,为什么不将其公开为 API 而不是让你乱搞? - 一些方言支持
NULL
限制。 PostgreSQL 将其解释为不存在的LIMIT
(我觉得这很令人困惑,LIMIT
是“未知的”)。 Oracle 将其解释为LIMIT 0
,这更合理。其他方言(例如 MySQL)拒绝LIMIT NULL
作为错误语法,这也是合理的。您建议 jOOQ 覆盖此行为并巧妙地重新解释它。我宁愿不要!
null
,那将是非常令人惊讶的