【问题标题】:Converting function from Oracle to PostgreSQL将函数从 Oracle 转换为 PostgreSQL
【发布时间】:2015-09-12 14:18:57
【问题描述】:

我正在努力将某些东西从 Oracle 转换为 PostgreSQL。在Oracle文件中有一个函数:

instr(string,substring,starting point,nth location)

或在我的文件中

instr(string,chr(10),instr(string,substring),1)

在 PostgreSQL 中这不存在,所以我查找了一个等效函数。我发现:

position(substring in string)

但这不允许起始位置和第n 个位置参数。

有没有办法让这个函数从给定点开始?或者在 PostgreSQL 中是否有更好的函数可以指定起始位置和第 n 个位置?

这必须在 PostgreSQL 8.2.15 上工作,因为这是我们在数据库上运行的版本。

【问题讨论】:

  • 如果需要对部分字符串进行操作,有substring(string [from int] [for int])。也许有更简单的解决方案,但您没有向我们展示您的输入或预期输出。
  • 您确定版本 8.2.15 吗? 8.2 自 2011 年 12 月起停产,您还缺少 8 个次要版本:最新的 8.2 版本是 8.2.23。您的版本有许多严重的(安全)问题。帮自己一个忙,尽快升级到最新版本。

标签: oracle postgresql database-migration plpgsql


【解决方案1】:

最简单的形式:

instr(string, substring) ::= strpos(string, substring)

带有position 参数:

对于一个正的position 值:

instr(string, substring, position) ::= strpos(substr(string, position), substring) + position - 1

对于一个负的position 值:

instr(string, substring, position) ::= strpos(substr(string, char_length(string) + position + 1), substring) + char_length(string) + position

带有occurrence 参数:

这在 PostgreSQL 中不存在。你似乎不需要它(示例给出了occurrence = 1),但如果你这样做了,那么你需要编写一个函数,递归地处理从第二个版本中提取的子字符串。

所以:

instr(string,chr(10),instr(string,substring),1)

变成

strpos(substr(string, strpos(string, substring)), chr(10)) + strpos(string, substring) - 1

【讨论】:

    【解决方案2】:

    Postgres 中的函数strpos(str, sub) 相当于Oracle 中的instr(str, sub)。可惜函数没有第三个和第四个参数,所以Postgres中的表达式一定比较复杂。

    函数substr(str, n) 给出从n 位置开始的str 子串。

    instr(str, ch, instr(str, sub), 1);                               --oracle
    strpos(substr(str, strpos(str, sub)), ch) + strpos(str, sub) - 1; --postgres
    

    由于instr()是一个强大的函数,我在plpgsql中编写了它以满足自己的需要。

    create or replace function instr(str text, sub text, startpos int = 1, occurrence int = 1)
    returns int language plpgsql immutable
    as $$
    declare 
        tail text;
        shift int;
        pos int;
        i int;
    begin
        shift:= 0;
        if startpos = 0 or occurrence <= 0 then
            return 0;
        end if;
        if startpos < 0 then
            str:= reverse(str);
            sub:= reverse(sub);
            pos:= -startpos;
        else
            pos:= startpos;
        end if;
        for i in 1..occurrence loop
            shift:= shift+ pos;
            tail:= substr(str, shift);
            pos:= strpos(tail, sub);
            if pos = 0 then
                return 0;
            end if;
        end loop;
        if startpos > 0 then
            return pos+ shift- 1;
        else
            return length(str)- length(sub)- pos- shift+ 3;
        end if;
    end $$;
    

    一些检查(来自OLAP DML Functions 的示例):

    select instr('Corporate Floor', 'or', 3, 2);  -- gives 14
    select instr('Corporate Floor', 'or', -3, 2); -- gives 2
    

    Postgres 8.2 中没有 reverse() 函数。你可以使用这个:

    -- only for Postgres 8.4 or earlier!
    create or replace function reverse(str text)
    returns text language plpgsql immutable
    as $$
    declare
        i int;
        res text = '';
    begin
        for i in 1..length(str) loop
            res:= substr(str, i, 1) || res;
        end loop;
        return res;
    end $$;
    

    【讨论】:

    • instr 函数不正确,注意是否复制:instr('1aba2bab3', 'aba', -1) 结果 3 应该是 2; instr('1aba2bab3', 'ab', -1) 结果 7 - 正确; instr('1aba2bab3', 'b', -1) 结果 7 应该是 8; instr('1aba2bab3', '3', -1) 结果 8 应该是 9;
    • @Ice2burn - 谢谢,上次return 有错误,已更正。
    • 现在一切都好,谢谢。正在寻找 RightPos 函数,你的解决方案是我找到的唯一一个
    【解决方案3】:

    您可以在 postgres 中使用 split_part() 函数

    参考以下链接

    https://www.postgresqltutorial.com/postgresql-split_part/

    SELECT SPLIT_PART('A,B,C', ',', 2);
    

    【讨论】:

      猜你喜欢
      • 2018-09-26
      • 2022-01-17
      • 1970-01-01
      • 2023-01-17
      • 2021-01-10
      • 2015-11-11
      • 1970-01-01
      • 2023-02-01
      相关资源
      最近更新 更多