这是在JSONB上下文中使用的典型wrap function(重载非json foo()
函数),
-- suppose FUNCTION foo(text[], numeric, boolean) returns int.
CREATE FUNCTION foo(JSONB) RETURNS int AS $f$
SELECT foo(
(SELECT array_agg(x) FROM jsonb_array_elements_text($1->'list') t(x) ),
($1->>'lim')::numeric, -- why cast JSONB number to numeric?
($1->>'osort')::boolean -- idem for boolean
);
$f$ LANGUAGE SQL IMMUTABLE;
是否有一种优雅的方式将JSONB
字符串数组转换为SQL text
数组?如果内部表示显示其数据类型,为什么我们需要这个丑陋的numeric
和boolean
强制转换?
在好的@IgorRomanchenko讨论后编辑:
我的preocupation是
为什么PostreSQL 9.5 丢失了JSONB 内部数据类型信息和内部(数字和布尔)表示?
现在,运行时引擎使用CPU将 JSONB编号转换为文本和文本到 SQL numeric ,或者使用boolean将文本文本转换为布尔...理想(优化) )是“旁路”JSONB内部表示,或只是“二进制到二进制”(不解析为文本并将文本转换为二进制)。
在内部使用JSONB数据类型(jsonb_typeof
)时,PostgreSQL将更加优化和友好!
PS1:SELECT array_agg(x) FROM jsonb_array_elements_text()
示例仅放大并暴露相同的问题。在这种情况下,我们还需要一个直接的jsonb_array_to_array(x,type)
函数来绕过数组bynary表示。
PS2:CREATE CAST不是这个问题的解决方案,因为它会破坏原始的JSONB表示。
......怎么做?
Hum ...也许创建像::numericByPass
这样的替代强制类型来“绕过JSONB二进制数到SQL数”和::booleanByPass
“绕过JSONB boolean到SQL boolean”,所以,保留< / strong>内部表示,不将其解析为文本值。当然,如果运行时检查看到字符串而不是期望的数据类型,则会触发错误。
查看示例,我们看到上下文有义务使用number和boolean,用户不需要将它说给编译器。
SQL解析器可以使用这种隐式的“上下文义务”来自行完成,在编译时,转换为::numericByPass
和::booleanByPass
,保留JSONB内部表示。如果用户真的害怕字符串输入,则只有在这种情况下,用户才会添加明确的::numeric
和::boolean
元素。
答案 0 :(得分:1)
您需要运行时强制转换和检查,因为输入JSON没有定义任何结构。您无法检查此输入JSON是否包含带有文本数组的字段"list"
或带有整数的字段"lim"
。
以JSON:
为例{
"list":42,
"lim": [3,5],
"osort": "maybe"
}
当前函数将抛出类型转换异常,因为它具有运行时强制转换和检查。没有任何运行时检查,这个函数会做什么?
BTW如果你真的希望postgres为你做这件事 - 你可以启用从varchar
到int
和boolean
的隐式演员,如下文所示:Postgresql. CREATE CAST 'character varying' to 'integer'
这不是最好的主意,但它会奏效。
答案 1 :(得分:0)
您可以创建类似于 - &gt;&gt;的不同运算符产生不同的输出类型。例如, - &gt;#可以给你一个数字和 - &gt; |布尔值。
CREATE FUNCTION json_numeric(
j json
, e text
) RETURNS NUMERIC IMMUTABLE STRICT LANGUAGE SQL AS $$
SELECT (j->>e)::numeric
$$;
CREATE OPERATOR -># ( PROCEDURE = json_numeric, LEFTARG = json, RIGHTARG = text );
SELECT ('{"a": 42, "b": "1"}')::json -># 'a';
?column?
----------
42
(1 row)
SELECT ('{"a": 42, "b": "1"}')::json -># 'b';
?column?
----------
1
(1 row)
如果使用plpgsql,如果json_typeof()不正确,则可能会抛出错误,但请注意,这将比SQL版本慢得多(尽管在大多数用法中都不重要)。