Postgres 如何将 json 数组解包到列中,然后重新打包,但保留数据类型?

How can Postgres unpack a json array into a column then re-pack it, but preserve the data type?

这是一些数据:

create table t
(id numeric, ja json, cr timestamp with time zone);

insert into t
values
(1,'[1,2,3]','2019-01-01 00:00:00+0'),
(1,'[3,4,5]','2019-02-01 00:00:00+0'),
(2,'["a","b"]','2019-01-01 00:00:00+0');

这是一个解包 json 数组的查询,只保留给定时间的最新数组元素(一月“3”被删除,二月“3”被删除),然后重新打包数据:

  SELECT r.id, json_agg(r.v), r.cr
  FROM
  (
    SELECT 
      r.id, 
      j.v, 
      t.cr,
      ROW_NUMBER() OVER(PARTITION BY t.id, j.v ORDER BY t.cr DESC) as rn
   FROM 
     t
     CROSS JOIN LATERAL json_array_elements_text(t.ja) j(v)
  ) r
  WHERE r.rn = 1
  GROUP BY r.id, r.cr

部分过程涉及将 json 值转换为文本,以便 postgres 可以将它们分组到 window 函数中,这意味着当重新打包为数组时,数字已变为文本:

id v              cr
1  ["1","2"]      2019-01-01 00:00:00+0
1  ["3","4","5"]  2019-02-01 00:00:00+0
2  ["a","b"]      2019-01-01 00:00:00+0

在将它们打包回 json 数组的过程中,是否有办法将数字字符串转换回数字?

不要将它们转换为文本,您只需要 partition by:

SELECT r.id, json_agg(r.v), r.cr
FROM (
  SELECT t.id, 
      j.v, 
      t.cr,
      ROW_NUMBER() OVER(PARTITION BY t.id, j.v::text ORDER BY t.cr DESC) as rn
  FROM t
     CROSS JOIN LATERAL json_array_elements(t.ja) j(v)
) r
WHERE r.rn = 1
GROUP BY r.id, r.cr

demo:db<>fiddle

您在使用 json_array_elements_text() 时将元素转换为文本。只需使用 json_array_elements() 即可保留数据类型。对于 window 函数,您可以将其单独转换为 text

 SELECT r.id, json_agg(r.v), r.cr
  FROM
  (
    SELECT 
      t.id, 
      j.v, 
      t.cr,
      ROW_NUMBER() OVER(PARTITION BY t.id, j.v::text ORDER BY t.cr DESC) as rn
   FROM 
     t
     CROSS JOIN LATERAL json_array_elements(t.ja) j(v)
  ) r
  WHERE r.rn = 1
  GROUP BY r.id, r.cr