如何在 jOOQ 中将分钟列添加到即时值

How to add minutes column to Instant value in jOOQ

给出这样的 table:

CREATE TABLE demo (
    id BIGINT PRIMARY KEY,
    offset_minutes INTEGER NOT NULL,
    scheduled_time TIMESTAMP WITH TIME ZONE
);

我想将 scheduled_time 更新为应用程序提供的时间加上 offset_minutes。在 PostgreSQL 上的普通 SQL 中,它看起来像

UPDATE demo
SET scheduled_time =
    timestamp with time zone '2022-09-12T01:23:45Z' +
        offset_minutes * interval '1 minute'
WHERE id = 12345;

在 jOOQ 中以独立于数据库引擎的方式表达这一点的最佳方式是什么?

这与人们想要将分钟添加到时间值的通常方式相反,其他 SO 问题很好地涵盖了这一点:在我的例子中,Instant 由代码和分钟数在数据库列中,而不是相反。

我能想到的最好办法是对分钟数进行浮点计算,因为我们可以将天数添加到 Instants:

dslContext.update(DEMO)
    .set(DEMO.SCHEDULED_TIME,
        DSL.instant(instant).add(DEMO.OFFSET_MINUTES.div(24.0 * 60.0)))
    .where(DEMO.ID.eq(id))
    .execute();

在 PostgreSQL 上,jOOQ 最终为 SET 子句的值生成一个 SQL 表达式:

(timestamp with time zone '2022-09-12 01:23:45+00:00' +
    ("public"."demo"."offset_minutes" / 1.44E3) * interval '1 day')

jOOQ 正在生成 interval '1 day' 的事实让我希望有一种方法可以告诉它将 day 更改为 minute 并避免浮点计算。如果可以避免,我永远不会对离散量进行浮点计算感到疯狂。

待处理的功能请求

解决您眼前的问题

有一个待处理的功能请求 #6723 添加对 DSL::offsetDateTimeAdd 的支持,这将允许向 TIMESTAMP WITH TIME ZONE 数据类型添加间隔。

它仍然不适用于 Instant 数据类型,我们需要对所有可能的日期时间算术变体进行另一个“重载”。

这两个都会在已经拥挤的 DSL class 中产生很多新方法,而不会真正添加很多新功能,因为它们正在做与现有 [=15] 类似的事情=] 或 localDateTimeAdd() 函数,只是为新类型提供相同的东西。

更具战略性、彻底的改变

在长期路线图上提出了一个很大的变化 #11088,这将允许更清晰地分离通常的两种类型 TU Field ]:

  • T 是“JDBC 类型”,即数据库理解的类型(例如 OffsetDateTime
  • U 是“用户类型”,即您希望在代码中看到的类型(例如 Instant

这样,将有一个方法接受 T = OffsetDateTime 和任意 U 类型(例如 Instant)。

立即为您解决

虽然上述任务需要时间才能正确完成,但您始终可以使用通常的逃生门并使用 plain SQL templating。例如

DSL.field("({0} + {1} * interval '1 minute')", 
    SQLDataType.INSTANT,
    DSL.instant(instant), 
    DEMO.OFFSET_MINUTES
);

您可以提取 hard-coded 参数(DSL.instant(instant)DEMO.OFFSET_MINUTES)并为上述内容创建一个可重用的函数,从而为 jOOQ 中缺少的功能创建一个迷你库。