我想为 H2 中的 IF 函数创建一个别名,以实现 MySQL 兼容性,如 此处要求。 Vituels 答案解释了如何使用 CREATE ALIAS 来做到这一点:
CREATE ALIAS IF NOT EXISTS `IF` AS $$
String ifFunction(boolean condition, String exp1, String exp2){
if(condition) {
return exp1;
} else {
return exp2;
}
}
$$;
如果您将别名与字符串参数一起使用,则此方法有效,但不适用于数字。如果我在别名定义中使用
Integer
而不是 String
,则相反。使用 Object
不适用于这两种类型。
有没有办法编写
ifFunction
以便它适用于任意数据类型?
这个类似问题的答案指出,如果多个方法具有不同数量的参数,则可以将多个方法绑定到别名。这对我不起作用,因为我需要相同数量的参数,但对于多种数据类型。
在H2中,函数有固定的返回类型,如果你想要动态返回类型,你可以使用Aggregate,就像这样:
import org.h2.api.Aggregate;
import java.lang.reflect.Array;
import java.sql.Connection;
import java.sql.SQLException;
public class IfFunction implements Aggregate {
boolean isTrue;
Object exp1;
Object exp2;
@Override
public void init(Connection connection) throws SQLException {
}
@Override
public int getInternalType(int[] ints) {
if (ints[1] <= 0) {
if (ints[2] <= 0) {
return 1;
}
return ints[2];
}
return ints[1];
}
@Override
public void add(Object o) throws SQLException {
if (o != null && o.getClass().isArray()) {
isTrue = (boolean) Array.get(o, 0);
exp1 = Array.get(o, 1);
exp2 = Array.get(o, 2);
} else {
throw new SQLException("o is not an array");
}
}
@Override
public Object getResult() throws SQLException {
return isTrue ? exp1 : exp2;
}
}
@Test
public void testIf() {
String ifFunction = "CREATE AGGREGATE `IF` FOR \"" + IfFunction.class.getName() + "\"";
em.createNativeQuery(ifFunction).executeUpdate();
assertEquals("a", em.createNativeQuery("select IF(1=1, 'a', 'b')").getResultList().get(0));
assertEquals("b", em.createNativeQuery("select IF(1=2, 'a', 'b')").getResultList().get(0));
assertEquals(1, em.createNativeQuery("select IF(1=1, 1, 2)").getResultList().get(0));
assertEquals(2, em.createNativeQuery("select IF(1=2, 1, 2)").getResultList().get(0));
assertEquals(1, em.createNativeQuery("select IF(1=1, 1, null)").getResultList().get(0));
assertEquals(2, em.createNativeQuery("select IF(1=2, null, 2)").getResultList().get(0));
assertNull(em.createNativeQuery("select IF(1=1, null, null)").getResultList().get(0));
}