【问题标题】:How do I convert oracle regexp_substr to PostgreSQL using HQL如何使用 HQL 将 oracle regexp_substr 转换为 PostgreSQL
【发布时间】:2021-10-15 15:04:42
【问题描述】:

我正在尝试将 OracleDB HQL where 子句转换为 PosgreSQL。 HQL 使用的是 PosgreSQL 方言。

这两个查询都直接在数据库上运行,没有任何问题。

Oracle数据库:

...
where  
( LPAD(regexp_substr(someTable.someColumn, '\d+', 1,1), 3, ' ') = ' 40' 
AND LPAD(regexp_substr(someTable.someColumn, '\d+', 1,2), 3, ' ') = ' 20');

PosgreSQL:

...
where
( LPAD(( SELECT array_to_string(a, '') from regexp_matches(someTable.someColumn, '\d+', 'g') as a limit 1 offset 0), 3, ' ') = ' 40' 
AND LPAD(( SELECT array_to_string(a, '') from regexp_matches(someTable.someColumn, '\d+', 'g') as a limit 1 offset 1), 3, ' ') = ' 20' );

更改代码后,我在运行时一直低于 hql 异常:

java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: 
unexpected token: regexp_matches near line 1

我还注册了下面的函数自定义方言类,但效果不佳:

public class CustomPostgresqlDialect extends PostgreSQL82Dialect  {

    public CustomPostgresqlDialect() {
    super();
    registerFunction( "regexp_matches", new StandardSQLFunction( "regexp_matches", StandardBasicTypes.STRING ) );
    }   
}

如果我继续使用原始 regexp_substr 版本,则会出现 PostgreSQL 异常:

org.postgresql.util.PSQLException: ERROR: function regexp_substr(character varying, unknown, integer, integer) does not exist

请建议是否有办法转换此类查询,以便 HQL 不会解析它。 此外,我无法切换到原生查询创建,因为 HQL 生成的部分很大。

非常感谢

【问题讨论】:

  • 我认为您的 Postgres 解决方案太复杂了。你到底想在那里实现什么?我认为regexp_split_to_array() 可能会更简单

标签: java postgresql oracle hibernate hql


【解决方案1】:

您似乎想从同一个正则表达式中检查多个匹配项。在 Postgres 中,这样做的方法是在正则表达式上使用 g 标志,以便它返回所有匹配项,而不仅仅是第一个。

我认为不是这个:

LPAD(( SELECT array_to_string(a, '') from regexp_matches(someTable.someColumn, '\d+', 'g') as a limit 1 offset 1)

你可以这样做

LPAD(regexp_matches(someTable.someColumn, '\d+', 'g')[1])

使用第一种方法,您必须更改传递给 HQL 函数的索引。另一个问题是 StandardSQLFunction 类不适合这个,因为你的实现太定制了。您必须实现自己的渲染器。

public class PgRegexMatcher implements SQLFunction {

    public boolean hasArguments() { return true; }
    public boolean hasParenthesesIfNoArguments() { return true; }
    public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
        return StandardBasicTypes.STRING;
    }

    public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException {
        StringBuilder sb = new StringBuilder()
        sb.append("regexp_matches(")
          .append(arguments.get(0))
          .append(", '\d+', 'g')[")
          .append(arguments.get(1))
          .append("]");
        return sb.toString();
    }
}

现在在 HQL 中,您可以将其用作 regexp_func(sometable.column1, x)regexp_func 是您注册的任何名称),它将在您的 Postgresql 方言中生成 regexp_matches(sometable.column1, '\d+', 'g')[x],您似乎已经为您的 Oracle 提供了一个方言想通了。

因为这里的数组索引从 1 开始,您可以在不调整方言之间的值的情况下执行此操作。

【讨论】:

  • 非常感谢。所以我缺少渲染部分。顺便说一句,我不得不使用完整查询 SELECT array_to_string(a, '') from regexp_matches(someTable.someColumn, '\d+', 'g') 而不是建议: regexp_matches(someTable.someColumn, '\d+', 'g') [1] 与 pgAdmin 一样,它确实在 "[" 或附近出现语法错误而失败
  • 啊,看来我误解了regexp_matches 返回的内容。它返回数组元素的行,其中每个数组的1 索引是完整的马赫数,后续索引对应于捕获组(如果有)。很高兴我的其他回答有所帮助。
猜你喜欢
  • 2015-11-11
  • 2023-01-17
  • 2019-03-04
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 2018-09-26
  • 2023-02-01
  • 2017-05-09
相关资源
最近更新 更多