Mysql SQL查询DATEDIFF在H2中失败,其中模式是MYSQL

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql SQL查询DATEDIFF在H2中失败,其中模式是MYSQL相关的知识,希望对你有一定的参考价值。

背景:在我的一个项目中,我正在使用JUnit在Spring Batch上进行component testing。这里的应用程序DB是mysql。在Junit测试执行中,我让数据源切换

  • MYSQL和
  • H2(JDBC:H2:MEM:MYTESTDB; DB_CLOSE_DELAY = -1; DB_CLOSE_ON_EXIT = FALSE; MODE = MYSQL)

基于配置。使用MYSQL作为调试目的的数据源,使用H2在构建服务器中单独运行测试。

一切正常,直到在应用程序逻辑中我必须使用带有DATEDIFF的查询。

问题:查询失败

org.h2.jdbc.JdbcSQLException:SQL语句中的语法错误

原因:即使通过H2 run on MySQL mode它使用H2功能,这些功能也不同

MYSQL DATEDIFF definition is DATEDIFF(expr1,expr2)
 e.g. SELECT DATEDIFF('2010-11-30 23:59:59','2010-12-31') 
      ==> 1

H2 DATEDIFF definision is DATEDIFF(unitstring, expr1, expr2)
 unitstring =  { YEAR | YY | MONTH | MM | WEEK | DAY | DD | DAY_OF_YEAR
 | DOY | HOUR | HH | MINUTE | MI | SECOND | SS | MILLISECOND | MS }
 e.g. SELECT DATEDIFF(dd, '2010-11-30 23:59:59','2010-12-31') 
      ==> 1

解决方案尝试失败:我尝试编写自定义函数

 package com.asela.util;                                                                                                                                

 import java.lang.reflect.Field;                                                                                                                                                         
 import java.sql.Date;                                                                                                                                                                   
 import java.time.temporal.ChronoUnit;                                                                                                                                                   
 import java.util.Map;                                                                                                                                                                   
 import java.util.Objects;                                                                                                                                                               

 import org.h2.expression.Function;                                                                                                                                                      

 public class H2Function {                                                                                                                                                               
    public static long dateDifference(Date date1, Date date2) {                                                                                                                          
        Objects.nonNull(date1);                                                                                                                                                          
        Objects.nonNull(date2);                                                                                                                                                          
        return ChronoUnit.DAYS.between(date1.toLocalDate(), date2.toLocalDate());                                                                                                        
    }                                                                                                                                                                                    
 } 

并用H2设置它

DROP ALIAS IF EXISTS DATEDIFF;
CREATE ALIAS DATEDIFF FOR "com.asela.util.H2Function.dateDifference";

以上无法替换现有的DATEDIFF仍然失败了

org.h2.jdbc.JdbcSQLException:函数别名“DATEDIFF”已存在; SQL语句:

我可以尝试使用其他任何方法吗?

答案

针对问题找到了解决方法。访问H2功能映射并从那里删除DATEDIFF。然后添加替换功能。

package com.asela.util;

import java.lang.reflect.Field;
import java.sql.Date;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.Objects;

import org.h2.expression.Function;

public class H2Function {

    @SuppressWarnings("rawtypes")
    public static int removeDateDifference() {
        try {
              Field field = Function.class.getDeclaredField("FUNCTIONS");
              field.setAccessible(true);
              ((Map)field.get(null)).remove("DATEDIFF");
        } catch (Exception e) {
            throw new RuntimeException("failed to remove date-difference");
        }
        return 0;
    }

    public static long dateDifference(Date date1, Date date2) {
        Objects.nonNull(date1);
        Objects.nonNull(date2);
        return ChronoUnit.DAYS.between(date1.toLocalDate(), date2.toLocalDate());
    }
}

然后在架构中

CREATE ALIAS IF NOT EXISTS REMOVE_DATE_DIFF FOR "com.asela.util.H2Function.removeDateDifference";
CALL REMOVE_DATE_DIFF();
DROP ALIAS IF EXISTS DATEDIFF;
CREATE ALIAS DATEDIFF FOR "com.asela.util.H2Function.dateDifference";

以上是关于Mysql SQL查询DATEDIFF在H2中失败,其中模式是MYSQL的主要内容,如果未能解决你的问题,请参考以下文章

mysql语句查询问题

插入时间戳时的 H2 org.h2.jdbc.JdbcSQLSyntaxErrorException

DATEDIFF() 或 BETWEEN 用于 SQL 查询中的日期范围

如何在nHibernate中使用datediff sql函数?

sql mysql__datediff.sql

SQL查询两个日期的差-datediff函数