как использовать регулярное выражение 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