【问题标题】:Why can't H2 database parse a timestamp?为什么 H2 数据库不能解析时间戳?
【发布时间】:2021-10-06 01:09:48
【问题描述】:

我的项目使用的是 Oracle 数据库,一切正常。为了测试的目的,我设置了一个 H2 db。以下查询现在会引发错误:

"SELECT * FROM ERESIS.ECH_HISFAB f WHERE f.FG_ETAT = 'A' AND TO_DATE(DT_INS) > '30-AUG-18' ORDER BY f.CD_MAT"

错误:

Cannot parse "TIMESTAMP" constant "30-AUG-18"; SQL statement:

我可以通过设置 TO_DATE('30-AUG-2018') 之类的字符串来修复错误,但是更改查询类型会破坏目的,因为我已经确定查询有效(但我需要它来测试服务)。有什么办法可以绕过这个错误而不改变查询?

【问题讨论】:

  • DATETIMESTAMP 之间存在差异。此链接可能会有所帮助 - stackoverflow.com/questions/19141030/…
  • 为什么将 DATE 值存储在 varchar 列中?刚开始这真的很糟糕。
  • @Nik 知道服务器是如何工作的还是我错过了什么?
  • @a_horse_with_no_name 不是我的项目,我只需要为它编写测试。
  • @aratata 请检查这是否有帮助 - stackoverflow.com/questions/14138532/…

标签: java spring hibernate h2


【解决方案1】:

parsedatetime()应该可以将字符串转换为TIMESTAMP,请尝试使用-

"SELECT * FROM ERESIS.ECH_HISFAB f WHERE f.FG_ETAT = 'A' AND TO_DATE(DT_INS) > parsedatetime('30-AUG-2018', 'dd-MMM-yyyy') ORDER BY f.CD_MAT"

【讨论】:

    【解决方案2】:

    我在 H2 (1.4.200) 中遇到了类似的问题,它只有一种用于 TO_DATE(input) 方法“DD MON YYYY”的格式。 经过调试后,我发现 H2 使用枚举作为日期格式,但它没有作为第二个参数提供:org.h2.expression.function.ToDateParser.ConfigParam

    TO_DATE("DD MON YYYY")
    

    我做了一个解决方案,使用反射覆盖它,这样 sql 代码就不会改变。

    在我的单元测试中,我创建了一个实用方法,用于在 @BeforeClass 上实例化解决方法

      private static boolean h2WorkaroundApplied = false; //utility to apply workaround just one time 
      protected static synchronized void applyH2ToOracleCompatibilityWorkaround() {
        if (!h2WorkaroundApplied) {
          fixH2ToDateFormat(); //apply to_date  workaround
          h2WorkaroundApplied = true; //disable future changes of same workaround
        }
      }
    
    
    private static void fixH2ToDateFormat() {
        try {
          Class<?> classConfigParam = Arrays.stream(ToDateParser.class.getDeclaredClasses())
              .filter(c -> "ConfigParam".equals(c.getSimpleName()))
              .findFirst()
              .orElseThrow(); //get the enum inner class
    
          Object toDateEnumConstant = Arrays.stream(classConfigParam.getEnumConstants())
              .filter(e -> "TO_DATE".equals(((Enum) e).name()))
              .findFirst()
              .orElseThrow(); //get the enum constant TO_DATE
    
          Field defaultFormatStr = classConfigParam.getDeclaredField("defaultFormatStr"); //get the enum private field defaultFormatStr
          defaultFormatStr.setAccessible(true);
          defaultFormatStr.set(toDateEnumConstant, "YYYY-MM-DD"); //change with my date format used by production oracle DB.
    
        } catch (Exception e) {
          throw new UnsupportedOperationException(
              "The current H2 version doesn't support this workaround. Tested with version 1.4.200", e);
        }
      }
    

    【讨论】:

      猜你喜欢
      • 2012-12-17
      • 1970-01-01
      • 2017-02-02
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多