как использовать регулярное выражение Oracle, как в Hibernate HQL?

Я использую 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.зимовать.бумага HQL.АСТ.QuerySyntaxException: неожиданный узел AST: (около строки 1, столбец 66.....

пожалуйста, помогите, как я могу использовать regex_like в hibernate собственный запрос? Или какая-то другая альтернатива.

6 ответов


фактически, вы не можете сравнить результат REGEXP_LIKE ни с чем, кроме условных операторов в PL/SQL.

Hibernate, похоже, не принимает пользовательскую функцию без returnType, так как вам всегда нужно сравнивать вывод с чем-то, i.e:

REGEXP_LIKE('bananas', 'a', 'i') = 1

поскольку Oracle не позволяет сравнивать результат этой функции ни с чем, я придумал решение, используя условие case:

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 (и JPQL, пока Hibernate является поставщиком). Вы просто должны рассказать Hibernate об этих функциях. В 3.3 единственный вариант для этого-предоставить пользовательский диалект и зарегистрировать функцию из конструктора диалекта. Если вы посмотрите на базовый класс диалекта, вы увидите много примеров регистрации функций. Обычно лучше всего расширить точный диалект, который вы используете в настоящее время и просто предоставьте свои расширения (здесь, регистрируя функцию).

интересно отметить, что Oracle не классифицирует regexp_like как функцию. Они классифицируют его как условие/предикат. Я думаю, что это в основном потому, что Oracle SQL не определяет логический тип данных, хотя их PL/SQL делает, и я бы поспорил, что regexp_like определяется как функция PL/SQL, возвращающая BOOLEAN...

предполагая, что вы в настоящее время используете Oracle10gDialect, вы do:

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 DBAs) сказали мне никогда не использовать regexes в oracle, так как они не могут быть индексированы, что заканчивается в БД, выполняющей полное сканирование БД. Если в таблице есть несколько записей, то все в порядке, но если в ней много строк, это может испортить представление.


для тех, кто использует критерий спящего режима с sqlRestriction (Hibernate версии 4.2.7)

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

или другой вариант-создать аналогичную функцию в oracle, которая вернет числовое значение на основе результата операции. Что-то вроде этого!--3-->

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