我正在使用oracle 10g
和hibernate 3.3.2
。我之前在sql中使用过正则表达式,现在我第一次在HQL中使用它。
Query query = getSession().createQuery("From Company company
where company.id!=:companyId and
regexp_like(upper(rtrim(ltrim(company.num))), '^0*514619915$' )");
这是我的hql,当我在没有regex_like
功能的情况下运行它时,它按预期运行。但是我无法用regex_like
表达式执行它。
它说..
嵌套异常是org.hibernate.hql.ast.QuerySyntaxException: 意外的AST节点:(靠近第1行,第66列......
请帮助,如何在hibernate本机查询中使用regex_like
?或其他一些替代方案。
答案 0 :(得分:10)
实际上,除了PL / SQL中的条件语句之外,你无法将REGEXP_LIKE的结果与任何东西进行比较。
Hibernate似乎不接受没有returnType的自定义函数,因为你总是需要将输出与某些东西进行比较,即:
REGEXP_LIKE('bananas', 'a', 'i') = 1
由于Oracle不允许您将此函数的结果与任何结果进行比较,因此我提出了使用案例条件的解决方案:
public class Oracle10gExtendedDialect extends Oracle10gDialect {
public Oracle10gExtendedDialect() {
super();
registerFunction(
"regexp_like", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN,
"(case when (regexp_like(?1, ?2, ?3)) then 1 else 0 end)")
);
}
}
你的HQL应该是这样的:
REGEXP_LIKE('bananas', 'a', 'i') = 1
它会起作用:))
答案 1 :(得分:3)
你绝对可以使用任何类型的数据库特定功能,你希望使用Hibernate HQL(和JPQL,只要Hibernate是提供者)。你只需要告诉Hibernate这些功能。在3.3中,唯一的选择是提供自定义Dialect并从Dialect的构造函数中注册该函数。如果你看一下Dialect基类,你会看到许多注册函数的例子。通常最好扩展您当前使用的精确方言,并简单地提供您的扩展(此处,注册该功能)。
一个有趣的说明是Oracle没有将regexp_like归类为函数。他们将其归类为条件/谓词。我认为这主要是因为Oracle SQL没有定义BOOLEAN数据类型,即使他们的PL / SQL确实如此,我敢打赌regexp_like被定义为PL / SQL函数返回BOOLEAN ......
假设您当前使用的是Oracle10gDialect,您可以这样做:
public class MyOracle10gDialect extends Oracle10gDialect {
public Oracle10gDialect() {
super();
registerFunction(
"regexp_like",
new StandardSQLFunction( "regexp_like", StandardBasicTypes.BOOLEAN )
);
}
}
我不记得HQL解析器是否喜欢返回布尔值的函数,但是它本身就是一个谓词。您可能必须将true / false转换为其他内容并检查该返回:
public class MyOracle10gDialect extends Oracle10gDialect {
public Oracle10gDialect() {
super();
registerFunction(
"regexp_like",
new StandardSQLFunction( "regexp_like", StandardBasicTypes.INTEGER ) {
@Override
public String render(
Type firstArgumentType,
List arguments,
SessionFactoryImplementor factory) {
return "some_conversion_from_boolean_to_int(" +
super.render( firstArgumentType, arguments, factory ) +
")";
}
}
);
}
}
答案 2 :(得分:1)
您可以尝试使用标准LIKE运算符:
where company.num like '%514619915'
然后使用Java正则表达式过滤掉不需要的那些。这应该减少将返回的不需要的行数。
这不会使用索引,因为它以'%'开头。
答案 3 :(得分:0)
除非JPAQL / HQL提供了这样做的方法,否则您无法访问特定的数据库函数,也无法为正则表达式提供任何内容。因此,您需要编写本机SQL查询以使用正则表达式。
另一方面,非常重要的一点,一些同事(Oracle DBA)告诉我永远不要在oracle中使用正则表达式,因为它们无法编入索引,最终导致数据库执行完整的数据库扫描。如果表中有几个条目,那就没关系,但如果它有很多行,可能会削弱性能。
答案 4 :(得分:0)
对于那些使用带有sqlRestriction(Hibernate Version 4.2.7)的Hibernate标准的人
Criterion someCriterion = Restrictions.sqlRestriction("regexp_like (column_name, ?, 'i')", "(^|\\s)"+searchValue+"($|\\s|.$)", StringType.INSTANCE);
答案 5 :(得分:0)
或者另一种选择是在oracle中创建类似的函数,它将根据操作结果返回数值。像这样的东西
CREATE OR REPLACE FUNCTION MY_REGEXP_LIKE(text VARCHAR2, pattern VARCHAR2)
RETURN NUMBER
IS function_result NUMBER;
BEGIN
function_result := CASE WHEN REGEXP_LIKE(text, pattern)
THEN 1
ELSE 0
END;
RETURN(function_result);
END MY_REGEXP_LIKE;
您将可以使用
MY_REGEXP_LIKE('bananas', 'a') = 1