我想创建一个函数,尝试将一组值转换为用户指定的类型(默认为文本)。一个非常简单的函数如下所示:
CREATE OR REPLACE FUNCTION cast_to(variable jsonb, key text, target_type anyelement DEFAULT 'TEXT'::regtype) RETURNS anyelement as $$
begin
RETURN CAST(variable->>key AS target_type);
end
$$
language plpgsql;
我尝试了以下操作:
SELECT CAST('foo' AS 'text');
:提供语法错误SELECT CAST('foo' AS 'text'::regtype);
:与1相同的错误SELECT CAST('foo' AS pg_typeof(null::text));
说type pg_typeof does not exist
上一次尝试是,我可以传入目标类型的变量而不是文本表示形式。然后使用该函数将看起来像SELECT cast_to('text', NULL::text);
。
如何实现此功能或类似功能?
Edit:如注释中所建议,我尝试使用动态SQL。我运气不好。我创建了一个不使用任何变量的非常基本的案例:
CREATE OR REPLACE FUNCTION audit.cast_to() RETURNS text as $$
DECLARE
_sql TEXT := 'SELECT CAST($1 AS $2)';
out TEXT;
begin
EXECUTE _sql
USING 'foo', 'TEXT'
INTO out;
return out;
end
$$
language plpgsql;
但是会引发错误:
syntax error at or near "$2"
实际上,可以做到。即使没有动态SQL。表面上也很简单。
CREATE FUNCTION cast_to(_js jsonb, INOUT _target_type anyelement = NULL::text) AS
$func$
BEGIN
SELECT _js ->> pg_typeof(_target_type)::text
INTO _target_type;
END
$func$ LANGUAGE plpgsql;
db <>小提琴here
但是此简约功能包含了一些高级/棘手的细节:有关基础知识,请参见此处的最后一章:
难题的最后一部分是将text
运算符返回的->>
值转换为返回类型。一个简单的SQL函数对此严格要求,并且不接受text
,例如integer
。 (对于实际输入到多态输入参数的integer
也不适用。PL/ pgSQL函数尝试简单地将RETURN
定义也是如此。将需要显式强制转换。
CAST (expression AS type)
is not a normal function。短语法CAST (expression AS type)
也没有。这些是constructs或syntax elements。您可能已经注意到类型名称的位置没有单引号,即:as identifier。 (Or您错过了该详细信息,这是您报告的前3个语法错误的原因。)而且标识符不能在SQL中进行参数化。那将需要动态SQL。
然而,我们可以将表达式的expression::type
结果assign转换为(必需键入的)变量或参数,以轻松实现相同的结果。 expression::type
子句将实现这一点。为方便起见,我直接将其分配给text
参数INTO
。因此,INOUT
有几个用途:
定义多态返回类型。
定义用于JSON->>运算符的键名。该名称由_target_type
的type携带,我用_target_type
提取它-实际上返回了_target_type
,因此我们需要将that显式转换为文本。Note始终产生Postgres标准类型名称,例如:'integer',而不是'int'或'int4'。如果您的键名不同于默认的Postgres类型名,则必须像在原始设计中那样传递一个附加参数!
可以分配给pg_typeof()
参数(因此我们不需要regtype
变量)。
具有OUT
值:DECLARE
,因此可以省略第二个参数以仅返回DEFAULT
。您尝试在原始文件中尝试过此操作,但是超出了目标。= NULL::text
您可能希望将其中一些用途拆分为多个参数/变量。
因此可以完成。问题是:为什么要这样做?通常,有一个更快,更不麻烦的解决方案-即使更冗长。