如何在 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
由代码和分钟数在数据库列中,而不是相反。
我能想到的最好办法是对分钟数进行浮点计算,因为我们可以将天数添加到 Instant
s:
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,这将允许更清晰地分离通常的两种类型 T
和 U
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 中缺少的功能创建一个迷你库。
给出这样的 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
由代码和分钟数在数据库列中,而不是相反。
我能想到的最好办法是对分钟数进行浮点计算,因为我们可以将天数添加到 Instant
s:
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,这将允许更清晰地分离通常的两种类型 T
和 U
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 中缺少的功能创建一个迷你库。