2017-06-14 77 views
1

我做了一個簡單的函數來用新值更新一個jsonb:PostgreSQL的9.4 - 無效的輸入語法轉換爲JSONB

CREATE OR REPLACE FUNCTION jsonupdate(
    IN "pJson" jsonb, IN "pNewValues" jsonb) 
    RETURNS jsonb AS 
$BODY$ 

DECLARE 

    jsonreturn jsonb; 

BEGIN 

    jsonreturn := (SELECT json_object_agg(keyval.key, keyval.value::jsonb) 
      FROM (SELECT key, 
         CASE WHEN "pNewValues" ? key THEN 
         (SELECT "pNewValues" ->> key) 
         ELSE 
         value 
         END 
        FROM jsonb_each_text("pJson")) keyval);    

    RETURN jsonreturn; 

END; $BODY$ 
    LANGUAGE plpgsql IMMUTABLE 
    COST 100; 

樣品輸入和輸出:

IN:SELECT jsonupdate('{"a" : "1", "b" : "2"}', '{"a": "3"}');

OUT:{"a": 3, "b": 2}

IN:SELECT jsonupdate('{"a" : "3", "b" : { "c": "text", "d": 1 }}', '{"b": { "c": "another text" }}');

OUT:{"a": 3, "b": {"c": "another text"}}

IN:SELECT jsonupdate('{"a" : "1", "b" : "2", "c": 3, "d": 4}', '{"a": "5", "d": 6}');

OUT:{"a": 5, "b": 2, "c": 3, "d": 6}

使用這樣一個輸入時發生該問題:SELECT jsonupdate('{"a" : "1", "b" : ""}', '{"a": "5"}')或者這一個:SELECT jsonupdate('{"a" : "1", "b" : "2"}', '{"a": "."}')或這一個:SELECT jsonupdate('{"a" : "1", "b" : "2"}', '{"a": ""}')它給了我一個錯誤

ERROR: invalid input syntax for type json 
DETAIL: The input string ended unexpectedly. 
CONTEXT: JSON data, line 1: 

這裏有什麼問題?

+2

你需要調用'jsonb_each()','不jsonb_each_text()' – pozs

回答

3

您應該使用jsonb_each()函數(而不是jsonb_each_text())。此外,操作者->(而不是->>):

CREATE OR REPLACE FUNCTION jsonupdate(IN "pJson" jsonb, IN "pNewValues" jsonb) 
    RETURNS jsonb 
    LANGUAGE sql 
    IMMUTABLE AS 
$BODY$ 
SELECT json_object_agg(key, CASE 
      WHEN "pNewValues" ? key THEN "pNewValues" -> key 
      ELSE value 
     END) 
FROM jsonb_each("pJson") 
$BODY$; 

jsonb_each_text()->>操作者將任何非字符串JSON值到他們的字符串表示。將它們轉換回JSON將以您不想要的方式修改您的數據。

但我不得不承認,你試圖實現的幾乎是||(連接)運算符。即

SELECT jsonb '{"a" : "1", "b" : "2"}' || jsonb '{"a": "3"}' 

會給你你想要的輸出。 ||和你的功能之間的唯一區別是當pNewValues包含密鑰,它們不在pJson中:||也會追加這些,而你的函數不會附加它們(它只會修改現有的)。

更新:對9.4模擬||操作,您可以使用以下功能:

CREATE OR REPLACE FUNCTION jsonb_merge_objects(jsonb, jsonb) 
    RETURNS jsonb 
    LANGUAGE sql 
    IMMUTABLE AS 
$func$ 
SELECT json_object_agg(key, COALESCE(b.value, a.value)) 
FROM  jsonb_each($1) a 
LEFT JOIN jsonb_each($2) b USING (key) 
$func$; 
+0

我我之前嘗試過'||'運算符,但它不起作用。然後我發現PostgreSQL 9.4不支持它。所以我創建了這個功能。謝謝您的幫助! – Pedro

+1

@PedroCorso是的,它在9.5中引入。我有一個[詳細的答案](https://stackoverflow.com/a/23500670/1499698)爲你想要達到每個Postgres版本回到9.3。 – pozs