要使用类型(“ TEXT”)的字符串表示形式键入的文本值(TEXT)

问题描述 投票:1回答:1

我想创建一个函数,尝试将一组值转换为用户指定的类型(默认为文本)。一个非常简单的函数如下所示:

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;

我尝试了以下操作:

  1. SELECT CAST('foo' AS 'text');:提供语法错误
  2. SELECT CAST('foo' AS 'text'::regtype);:与1相同的错误
  3. [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 postgresql polymorphism plpgsql dynamic-sql
1个回答
0
投票

实际上,可以做到。即使没有动态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)也没有。这些是constructssyntax elements。您可能已经注意到类型名称的位置没有单引号,即:as identifier。 (Or您错过了该详细信息,这是您报告的前3个语法错误的原因。)而且标识符不能在SQL中进行参数化。那将需要动态SQL。

然而,我们可以将表达式的expression::type结果assign转换为(必需键入的)变量或参数,以轻松实现相同的结果。 expression::type子句将实现这一点。为方便起见,我直接将其分配给text参数INTO。因此,INOUT有几个用途:

  1. 定义多态返回类型。

  2. 定义用于JSON->>运算符的键名。该名称由_target_typetype携带,我用_target_type提取它-实际上返回了_target_type,因此我们需要将that显式转换为文本。Note始终产生Postgres标准类型名称,例如:'integer',而不是'int'或'int4'。如果您的键名不同于默认的Postgres类型名,则必须像在原始设计中那样传递一个附加参数!

  3. 可以分配给pg_typeof()参数(因此我们不需要regtype变量)。

  4. 具有OUT值:DECLARE,因此可以省略第二个参数以仅返回DEFAULT。您尝试在原始文件中尝试过此操作,但是= NULL::text超出了目标。

您可能希望将其中一些用途拆分为多个参数/变量。

因此可以完成。问题是:为什么要这样做?通常,有一个更快,更不麻烦的解决方案-即使更冗长。

© www.soinside.com 2019 - 2024. All rights reserved.