如何在Hibernate HQL中使用Oracle的regexp_like?

我正在使用oracle 10ghibernate 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表达式执行它。

它说..

嵌套exception是org.hibernate.hql.ast.QuerySyntaxException:意外的AST节点:(靠近第1行,第66列……

请帮助,如何在hibernate本机查询中使用regex_like ? 或其他一些替代方法。

实际上,除了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 

它会工作:)

你绝对可以使用Hibernate HQL所希望的任何类型的特定于数据库的函数(只要Hibernate是提供者,就可以使用JPQL)。 你只需要告诉Hibernate这些function。 在3.3中,唯一的选择是提供自定义Dialect并从Dialect的构造函数中注册该函数。 如果你看一下基础Dialect类,你会看到许多注册函数的例子。 通常最好扩展您当前使用的精确方言,并简单地提供您的扩展(此处,注册该function)。

有趣的是,Oracle没有将regexp_like归类为函数。 他们将其归类为条件/谓词。 我认为这主要是因为Oracle SQL没有定义BOOLEAN数据类型,即使他们的PL / SQL确实如此,我敢打赌regexp_like被定义为返回BOOLEAN的PL / SQL函数…

假设您当前使用的是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 ) + ")"; } } ); } } 

您可以尝试使用标准LIKE运算符:

 where company.num like '%514619915' 

然后使用Java正则表达式过滤掉不需要的那些。 这应该减少将返回的不需要的行数。

这不会使用索引,因为它以’%’开头。

除非JPAQL / HQL提供了这样做的方法,否则您无法访问特定的数据库函数,也无法为正则表达式提供任何内容。 因此,您需要编写本机SQL查询以使用正则表达式。

在另一个非常重要的问题上,一些同事(Oracle DBA)告诉我永远不要在oracle中使用正则表达式,因为它们无法编入索引,最终导致数据库执行完整的数据库扫描。 如果表有几个条目,那么没关系,但是如果它有很多行,它可能会削弱性能。

对于那些使用带有sqlRestriction的Hibernate标准的人(Hibernate Version 4.2.7)

  Criterion someCriterion = Restrictions.sqlRestriction("regexp_like (column_name, ?, 'i')", "(^|\\s)"+searchValue+"($|\\s|.$)", StringType.INSTANCE); 

或者另一种选择是在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