我想创建一个函数,尝试将一组值转换为用户指定的类型(默认值为text)。一个非常简单的函数如下所示:
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);
。
如何实现此功能或类似功能?
编辑:如注释中所建议,我尝试使用动态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"
答案 0 :(得分:3)
实际上,可以做到。即使没有动态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
也不适用。尝试简单地RETURN
的PL / pgSQL函数也是如此。将需要显式强制转换。
CAST (expression AS type)
is not a normal function。短语法expression::type
也没有。这些是构造或语法元素。您可能已经注意到类型名称的位置没有单引号,即:作为 identifier 。 (或者,您错过了该详细信息,这是导致您报告的前3个语法错误的原因。)而且无法在SQL中对标识符进行参数化。那将需要动态SQL。
但是,我们可以毫不费力地 分配 将表达式的text
结果分配给(必须键入)变量或参数实现相同。 INTO
子句将实现这一目标。为了方便起见,我直接分配了INOUT
参数_target_type
。因此,_target_type
有几个用途:
定义多态返回类型。
定义用于JSON->>运算符的密钥名称。该名称由_target_type
的 type 携带,我用pg_typeof()
提取了它-实际上返回了regtype
,因此我们需要转换 that < / em>显式输入文字。
注意,它总是产生Postgres标准类型名称,例如:“整数”,而不是“ int”或“ int4”。如果您的键名与默认的Postgres类型名不同,则必须像在原始设计中那样传递一个附加参数!
用作可分配给的OUT
参数(因此我们不需要DECLARE
变量)。
具有附加的DEFAULT
值:= NULL::text
,因此可以省略第二个参数以仅返回text
。
您在原始影片中尝试过此操作,但 没能达到目标。DEFAULT 'TEXT'::regtype
您可能希望将其中一些用途拆分为多个参数/变量。
所以可以做到的。
问题是:您为什么要这样做?通常,即使更冗长,也有一个更快,更棘手的解决方案。