数值超出范围减去 jOOQ 中的日期

Posted

技术标签:

【中文标题】数值超出范围减去 jOOQ 中的日期【英文标题】:Numeric value out of range subtracting dates in jOOQ 【发布时间】:2015-05-18 07:42:08 【问题描述】:

我正在尝试使用 H2 数据库 (v1.4.185) 比较 jOOQ (v3.5.0) 中的日期,但如果比较太大,我会得到“数值超出范围”。

比如下面这张表

CREATE TABLE example (
    id INT AUTO_INCREMENT,
    deadline TIMESTAMP,
    PRIMARY KEY (id)
);

并使用以下示例代码(未显示 jOOQ 的代码生成步骤)

DSLContext dsl = DSL.using(getDataSource(dbUrl), SQLDialect.H2);

ExampleRecord exampleRecord = dsl.newRecord(EXAMPLE);
exampleRecord.setDeadline(Timestamp.valueOf("2001-01-10 12:15:30"));
exampleRecord.store();

dsl.selectFrom(EXAMPLE)
        .where(EXAMPLE.DEADLINE.sub(
              DayToSecond.valueOf(Duration.ofDays(30).toMillis()))
        .le(currentTimestamp()))
        .fetch().forEach(record -> System.out.println(record.getDeadline()));

产生以下错误

Exception in thread "main" org.jooq.exception.DataAccessException: 
SQL [select "EXAMPLE"."ID", "EXAMPLE"."DEADLINE" from "EXAMPLE" 
where dateadd('ms', cast(? as bigint), "EXAMPLE"."DEADLINE") 
    <= current_timestamp()]; 
Numeric value out of range: "-2592000000"; 
SQL statement:
        select "EXAMPLE"."ID", "EXAMPLE"."DEADLINE" from "EXAMPLE" 
where dateadd('ms', cast(? as bigint), "EXAMPLE"."DEADLINE") 
    <= current_timestamp() [22003-185]

【问题讨论】:

【参考方案1】:

对我来说,这似乎是 H2 中的一个缺陷。 H2 的DATEADD() function expects the number of units added to be of type int。当然,在以毫秒为单位进行操作时,这没有任何意义。 I've reported it on the H2 user group。让我们看看他们怎么说。如果这在 H2 中无法纠正,我们将在 jOOQ 中解决它,就像我们对 Sybase 和其他数据库所做的那样。

解决方法:

Field.sub(Number) 方法在用于日期时间算术时已经从时间戳中减去天数(如 Oracle)。所以,你可以写出同样的表达式:

EXAMPLE.DEADLINE.sub(30)

另一种选择是改用DSL.timestampAdd()

timestampAdd(EXAMPLE.DEADLINE, -30, DatePart.DAY);

第三种选择是使用纯 SQL:

public static Field<Timestamp> mySub(Field<Timestamp> field, Number days) 
    return DSL.field("dateadd('day', 0, 1)", Timestamp.class, val(-days), field);

【讨论】:

使用天数反而效果很好。谢谢! (感谢创建 jOOQ - 我现在永远不会使用任何其他数据库访问技术!) @artbristol:谢谢你的好话。我们会继续为您服务 @artbristol:Noel Grandin from H2 has accepted the issue and fixed it。这将在下一个 H2 版本中工作,所以我们不会在 jOOQ 中解决它【参考方案2】:

这个错误对我来说没有意义。生成的 SQL (bigint) 表明 jOOQ 知道参数是 long-2592000000 在限制范围内。

我想知道引号是由错误消息添加的,还是DayToSecond.toMillis() 可能返回String 而不是long。除了我期待一个不同的错误消息(加上一个编译错误)。

为了安全起见,尝试通过用常量替换代码来降低表达式的复杂性:

dsl.selectFrom(EXAMPLE)
    .where(EXAMPLE.DEADLINE.sub(-2592000000L))
    ...

只是为了看看这对错误有何影响。

【讨论】:

感谢您的建议。使用常量会得到相同的错误。 DayToSecond.toMillis() 返回 DayToSecond 扩展 Number,但问题与 doublelong 输入相同(尽管生成的 SQL 不同,例如 cast(? as double)) :-/ H2 和 jOOQ 的哪个版本?也许在创建错误消息时设置一个断点,然后上堆栈查看代码的哪一部分抱怨。 是的,我想我必须深入研究代码。我已经用版本号更新了问题。我基本上在等待@Lukas Eder 出现并挽救这一天:-)

以上是关于数值超出范围减去 jOOQ 中的日期的主要内容,如果未能解决你的问题,请参考以下文章

PDO PHP - PDOException - 数值超出范围:1264 第 1 行的列“customer_id”的值超出范围

从 Access 导出到 Excel 时出现日期超出范围错误

索引超出范围 Python 数值迭代

查询在 MySQL 中有效,但不能通过 Lumen/Laravel - 数值超出范围:1416

UCanAccess 数据异常:数值超出范围

Vigenere密码,如何处理超出字符值范围的序数值