Postgresql 9.4 - 转换为JSONB时输入语法无效

时间:2017-06-14 12:02:30

标签: json postgresql postgresql-9.4 jsonb

我已经创建了一个简单的函数来使用新值更新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:

这里有什么问题?

1 个答案:

答案 0 :(得分: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$;