【问题标题】:port Oracle decode() using variadic, anyarray, and anyelement使用可变参数、anyarray 和 anyelement 移植 Oracle decode()
【发布时间】:2019-05-12 04:53:56
【问题描述】:

我需要从 Oracle 移植一个广泛使用 decode() 的存储过程。也就是说,我不能像guide 所建议的那样使用CASE WHEN expr THEN expr [...] ELSE 系列。

我想创建一个可变参数函数,但问题是:在 Oracle 中,该函数可以接受任意数量的键值对,并且键的类型不一定与值的类型匹配:

select decode(0  ,0,'a'  ,1,'b'  ,2,'c'  /*,...*/ ,'dflt') from dual;

我尝试使用anyarray

create or replace function decode(VARIADIC args anyarray) RETURNS text AS $$
  SELECT null::text;
$$ LANGUAGE SQL;

但这只有在所有参数都属于同一类型时才有效:

select decode(0,0,0); -- ok
select decode('x'::text,'x'::text,'x'::text); -- ok
select decode(0,0,'a'::text); -- No function matches the given name and argument types

如果无法获得所需的语法,请提供另一种传递 expr、对集和默认值的方法,同时保持它们在 Oracle 中的位置。

【问题讨论】:

  • 不是答案而是观察 decode 是 PostgreSQL system function handling binary string,可能不值得覆盖名称并将其更改为另一个名称,例如:xdecode
  • 我认为即使使用 C 函数也无法模仿 Oracle 的 decode。您必须在应用程序中触摸decodes。
  • 我没试过,但是OraFCE声称有Oracle兼容的decode()函数:github.com/orafce/orafce
  • @LaurenzAlbe - C 扩展提供了典型的“any” - 并且可以模拟任何功能 - 不幸的是 - 存在一些性能损失 - 高多少,取决于上下文。跨度>

标签: postgresql polymorphic-functions


【解决方案1】:

限制

这似乎是 PostgreSQL 的实现方式。阅读docs

35.4.5。具有可变数量参数的 SQL 函数

SQL 函数可以声明为接受可变数量的参数, 只要所有“可选”参数的数据类型相同。这 可选参数将作为数组传递给函数。这 通过将最后一个参数标记为 VARIADIC 来声明函数;这 参数必须声明为数组类型。

JSON

如果您找到一种方法将您的混合数组从 Oracle 导出为 JSON 格式,那么PostgreSQL JSON type 将处理它:

CREATE OR REPLACE FUNCTION xdecode(data json)
RETURNS TEXT AS
$BODY$
    -- Your implementation here
    SELECT NULL::TEXT;
$BODY$ LANGUAGE SQL;

这个函数接受一个 JSON 字符串,它可以是:

SELECT xdecode('[1, 2, 3.3, "a", true, null]'::json);

表格类型

如果您要解码的参数元组与 TABLE 类型匹配,则可以使用它:

CREATE TABLE foo(
    x INTEGER,
    y FLOAT,
    z TEXT
);

CREATE OR REPLACE FUNCTION xdecode2(data foo)
RETURNS TEXT AS
$BODY$
    SELECT row_to_json(data)::TEXT;
$BODY$ LANGUAGE SQL;

然后这个调用有效:

SELECT xdecode2((1, 2.1, 'x'))

很遗憾,我们不能使用泛型 RECORD 类型作为函数的输入参数。

CREATE OR REPLACE FUNCTION xdecode3(data RECORD)
RETURNS TEXT AS
$BODY$
    SELECT row_to_json(data)::TEXT;
$BODY$ LANGUAGE SQL;

加注:

ERROR: SQL functions cannot have arguments of type record
SQL state: 42P13

输入anyelement

正如@basin 所指出的,可以使用anyelement 模拟RECORD 类型:

CREATE OR REPLACE FUNCTION xdecode4(data anyelement)
RETURNS TEXT AS
$BODY$
    SELECT row_to_json(data)::TEXT;
$BODY$ LANGUAGE SQL;

SELECT xdecode4((1, 2.1, 'x'));

返回:

'{"f1":1,"f2":2.1,"f3":"x"}'

【讨论】:

  • 一个小提示:如果参数声明为anyelement,我们可以将泛型RECORD 传递给SQL 类型的函数。我们可以申请row_to_json(),但我们无法从中提取类型信息。
  • @basin 谢谢指出这一点,能解决你的问题吗?
猜你喜欢
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-23
相关资源
最近更新 更多