2017-07-21 48 views
2

这种解决方法并不适用如何将json数组转换为文本数组?

CREATE FUNCTION json_array_castext(json) RETURNS text[] AS $f$ 
    SELECT array_agg(x::text) FROM json_array_elements($1) t(x); 
$f$ LANGUAGE sql IMMUTABLE; 

-- Problem: 
SELECT 'hello'='hello'; -- true... 
SELECT (json_array_castext('["hello","world"]'))[1] = 'hello'; -- false! 

那么,如何获取文本的真实阵列? PS:与所谓的“头等公民”JSONb,同样的问题。


编辑:@OtoShavadze很好的答案后(注释解决了!),一个清单PostgreSQL开发者所需为什么x::text不是铸造?(使用pg 9.5.6)以及为什么它不会生成警告或错误?

+1

尝试'json_array_elements_text'而不是'json_array_elements' –

+0

是的!谢谢@OtoShavadze!请将其作为回答发布,以供我正式验收(!)。我正在编辑只为PostgreSQL开发人员制作清单;-) –

回答

1

尝试json_array_elements_text代替json_array_elements,并且您无需显式转换为文本(x::text),所以你可以使用:

CREATE or replace FUNCTION json_array_castext(json) RETURNS text[] AS $f$ 
    SELECT array_agg(x) FROM json_array_elements_text($1) t(x); 
$f$ LANGUAGE sql IMMUTABLE; 

为了您的附加问题

为什么X ::文字不是演员?

这是投也正因为如此,它不提供任何错误,但铸造JSON字符串时,文本是这样的:::text,Postgres的加引号的价值。

只是为了测试目的,让再次更改功能,原来的(因为它是在你的问题),并尝试:

SELECT 
(json_array_castext('["hello","world"]'))[1] = 'hello', 
(json_array_castext('["hello","world"]'))[1], 
'hello' 

正如你看到的,(json_array_castext('["hello","world"]'))[1]给人"hello"而不是hello。这就是为什么在比较这些值时得到了false

+0

谢谢Oto!这不是批评,请忽略,只是我的清单的一个补充:-) *在SQL中,铸造'char(N)'产生预期的没有引号的文本;在嵌入式语言或驱动程序中,铸造SQL-'text'会产生预期的没有引号的'string',铸造'string'会产生预期的没有引用的SQL -'text' ......这是普遍预期的行为... * –

1

对于PostgreSQL的这种丑恶的行为,有一个丑陋的铸造解决方案,运营商#>>'{}'

CREATE or replace FUNCTION json_array_castext(json) RETURNS text[] AS $f$ 
    SELECT array_agg(x#>>'{}') FROM json_array_elements($1) t(x); 
$f$ LANGUAGE sql IMMUTABLE; 

SELECT (json_array_castext('["hello","world"]'))[1] = 'hello'; -- true! 
1

奥托的answer是一个救星,但它确实有把我折磨我的大脑一个边界情况。由于演员的有损性质,除非你有一个空的json阵列,否则它会很好地工作。在这种情况下,你会期望返回一个空数组,但它实际上什么都不返回。作为一种解决方法,如果您只是将返回值与空数组连接起来,那么在实际返回时不会产生任何影响,但当您获得空数组时,请做正确的事情。以下是更新后的SQL函数(适用于jsonjsonb),它们实现了该解决方法。

CREATE or replace FUNCTION json_array_casttext(json) RETURNS text[] AS $f$ 
    SELECT array_agg(x) || ARRAY[]::text[] FROM json_array_elements_text($1) t(x); 
$f$ LANGUAGE sql IMMUTABLE; 

CREATE or replace FUNCTION jsonb_array_casttext(jsonb) RETURNS text[] AS $f$ 
    SELECT array_agg(x) || ARRAY[]::text[] FROM jsonb_array_elements_text($1) t(x); 
$f$ LANGUAGE sql IMMUTABLE; 

有这样一个在文档数据库整合成一个成熟的关系一个指向粗糙边缘的几个特点,但在Postgres的处理大多确实令人钦佩的工作。

+0

Hi @JoelB,Oto的解决方案的好处,对于空箱子。你的解决方案是优雅的,也许是最好的......但也许(需要测试性能!)更快的解决方案是'SELECT CASE WHEN $ 1 ='[]':: jsonb THEN array [] :: text [] ELSE(SELECT array_agg (x)FROM等)END'。 * json *相同,但使用'$ 1 :: text ='{}':: text'。 –

+0

哦,是的,这是一个彻头彻尾的破解,我相信你的建议会更高效。我主要担心的不是丢失数据,这可以防止。 –