Json

如何消除嵌套聚合問題中的 for 循環

  • April 24, 2019

我有一個解析問題,我正在使用 plpgsql 中的 FOR LOOP 解決,主要是因為我無法弄清楚如何使用子查詢和嵌套聚合來解決它。我的問題是可以消除 for 循環,如果可以,如何消除?我正在使用 PostgreSQL 版本 11.1。

輸入(JSON):[{"a":"1","b":"2"},{"c":"3","d":"4","e":""}]

預期輸出:{{a="1",b="2"},{c="3",d="4",e=""}}

我的plpgsql程式碼:

CREATE OR REPLACE FUNCTION parse(_in JSONB)
RETURNS TEXT LANGUAGE plpgsql STABLE AS $BODY$
DECLARE
   _out TEXT;
   _parts TEXT[];
   _row RECORD;
BEGIN
   FOR _row IN (
       SELECT q1.value, ROW_NUMBER() OVER () AS index
           FROM JSONB_ARRAY_ELEMENTS(_in) q1
   ) LOOP
       _parts[_row.index] := STRING_AGG(CONCAT(q2.key, '=', q2.value::TEXT), ',')
           FROM JSONB_EACH(_row.value) q2;
   END LOOP;

   SELECT CONCAT(
           '{{',
           COALESCE(STRING_AGG(q, '},{'), ''),
           '}}'
       )
       INTO _out
       FROM UNNEST(_parts) q;

   RETURN _out;
END
$BODY$;

跑:

my_db=*# select parse('[{"a":"1","b":"2"},{"c":"3","d":"4","e":""}]');
              parse
------------------------------------
{{a="1",b="2"},{c="3",d="4",e=""}}
(1 row)

更新:響應額外要求的請求:

  • 輸入是一個實際的 json(b) 對象,而不是字元串表示。
  • 任何鍵或值都不會有雙引號字元(甚至不是轉義字元。)
  • 這些值始終為字元串類型,儘管它們可能為空。
  • JSON 中可能有很多元素。

對於所示的範例,純字元串操作可以完成這項工作:

WITH tbl(j) AS (SELECT json '[{"a":"1","b":"2"},{"c":"3","d":"4","e":""}]')
SELECT '{' || regexp_replace( left(right(j::text, -1), -1)
                           , '"([^"]+)" *:', '\1=', 'g')
   || '}'
FROM  tbl;

如果你有更複雜的鍵和值,這裡是你的函式的重寫。改用簡單的 SQL 函式:

CREATE OR REPLACE FUNCTION f_parse(_in jsonb)
 RETURNS text LANGUAGE sql STABLE AS
$func$
SELECT '{{' || string_agg(part, '},{') || '}}'
FROM   jsonb_array_elements(_in) q1
CROSS  JOIN LATERAL (
  SELECT string_agg(q2.key || '=' || q2.value::text, ',') AS part
  FROM   jsonb_each(q1.value) q2
  ) q2
$func$;

如果您不相信元素的原始順序得到保證,請使用以下安全變體:

CREATE OR REPLACE FUNCTION f_parse_safe(_in jsonb)
 RETURNS text LANGUAGE sql STABLE AS
$func$
SELECT '{{' || string_agg(part, '},{' ORDER BY q1.ordinality) || '}}'
FROM   jsonb_array_elements(_in) WITH ORDINALITY q1
CROSS  JOIN LATERAL (
  SELECT string_agg(q2.key || '=' || q2.value::text, ',' ORDER BY q2.ordinality) AS part
  FROM   jsonb_each(q1.value) WITH ORDINALITY q2
  ) q2
$func$;

看:

db<>在這裡擺弄

引用自:https://dba.stackexchange.com/questions/233055