2017-07-21 67 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

哦,是的,這是一個徹頭徹尾的破解,我相信你的建議會更高效。我主要擔心的不是丟失數據,這可以防止。 –