当前位置: 首页 > 知识库问答 >
问题:

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

弓智明
2023-03-14

背景:在我的一个项目中,我正在使用JUnit对Spring批处理进行组件测试。这里的应用数据库是MYSQL。在Junit测试执行中,我让数据源在

  • MYSQL和
  • H2(jdbc:H2:mem:MYTESTDB;DB\u CLOSE\u DELAY=-1;DB\u CLOSE\u ON\u EXIT=FALSE;MODE=MYSQL)

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

一切都很好,直到在应用程序逻辑中我不得不使用带有DATEDIFF的查询。

问题:查询失败

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

原因:即使通过H2在MySQL模式下运行,它也使用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仍然失败

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

我可以尝试其他方法来实现这一点吗?

共有1个答案

虞华彩
2023-03-14

找到了一个解决问题的方法。访问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";
 类似资料:
  • 所以我有一个小游戏,它使用LuaJIT和LuaPower的MySQL客户端库。 现在,我已经成功地建立了连接,并且我还能够选择表,例如,但是我无法将任何数据插入表中。 错误本身是: 致命错误[未处理的异常]:尝试调用未初始化的函数指针 这是我的Lua代码,因此您可以理解我正在尝试做什么: 不幸的是,查询似乎是不正确的格式,或者至少没有真正的线索,我可以让这种情况发生。 我似乎无法进一步调试它。但我

  • 问题内容: 编辑:我更改了名称,因为存在类似的SO问题如何在添加大查询时解决SpreadSheetAddRows函数崩溃的问题?在那里描述了我的问题,所以我更简洁地表达了自己的看法……问题是电子表格Addrows,我的查询结果以我认为合适的大小(1600行,27列)轰炸了整个服务器,但听起来比他的18,000行少了很多 我正在使用通过Coldfusion 9.0.1 cfstoredproc访问的

  • 在分布式架构中, 如SOA或者微服务架构,你不能担保服务调用如你所预想的一样好。有时候服务会宕机、网络被挖断、网络变慢等,所以你需要容忍这些状况。 rpcx支持四种调用失败模式,用来处理服务调用失败后的处理逻辑, 你可以在创建XClient的时候设置它。 FailMode的设置仅仅对同步调用有效(XClient.Call), 异步调用用,这个参数是无意义的。 Failfast 示例: failfa

  • 我正在尝试使用以下查询更新表 但是,得到以下异常: 当我使用这样的更新给出子句时,它更新了该特定项。 有人能指出为什么我不能执行查询和如何解决这个问题吗?

  • 问题内容: 我遇到的情况是,卡实体具有某个人的外键。 此人的默认获取类型为LAZY。我可以在查询中为EAGER指定获取类型: 谢谢你的帮助。 问题答案: 你试过了吗 对于QueryDSL 4.0.2+

  • 我有一个名为user的实体,如下所示: 我还有一个用户摘要类,它旨在返回以进行分页和排序: 这与所有其他实体一起似乎在h2中很好地初始化,从控制台我看到如下内容: 和 甚至: 现在,我已经设置了控制器、服务和存储库... 控制器: 服务:公共接口UserService扩展了UserDetailsService{ 存储库:公共界面UserRepository扩展了JpaRepository{ 最后,