将函数从 Oracle 转换为 PostgreSQL
Posted
技术标签:
【中文标题】将函数从 Oracle 转换为 PostgreSQL【英文标题】:Converting function from Oracle to 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。您的版本有许多严重的(安全)问题。帮自己一个忙,尽快升级到最新版本。
【参考方案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);
【讨论】:
以上是关于将函数从 Oracle 转换为 PostgreSQL的主要内容,如果未能解决你的问题,请参考以下文章
Oracle GoldenGate现在支持从 PostgreSQL 捕获数据