为每条记录解析一个带有 FOR 循环的 JSON 列?

Posted

技术标签:

【中文标题】为每条记录解析一个带有 FOR 循环的 JSON 列?【英文标题】:Parse a JSON column with a FOR loop for every record? 【发布时间】:2018-05-27 11:40:44 【问题描述】:

作为 Postgres 和 SQL 的新手,我在 Postgres 9.6 中有以下场景:

table1

"Myjson" JSON
"DateOfAcquisition"  DATE
"Id" INT

"Myjson" 中有一个列表,我用FOR 循环遍历它。

我的目标是将table1中的每个json列表的元素放在另一个表中:

table2

jsonelem1 INT
jsonelem2 INT
"DateOfAcquisition" DATE
"Id" INT

我已经编写了以下代码来解析 json 字段,但我不确定如何为第一个表的每条记录运行 for 循环。

    DO
$BODY$
DECLARE
    omgjson json := myjsonfield; -- this should change for every row of the first table
    i json;
    myJsonelem1 INT;
    myJsonelem2 INT;

begin

FOR i IN SELECT * FROM json_array_elements(omgjson)
  loop
    myJsonelem2 i->>  'jsonsubfield'::INT;

    INSERT INTO destinationTable VALUES (myJsonelem2,DateOfAcquisition);
END LOOP;

END;
$BODY$ language plpgsql

【问题讨论】:

edit您的问题并添加一些示例 JSON 数据和基于该数据的结果。Formatted text 请no screen shots。 Edit您的问题不要在 cmets 中发布代码 FOR 循环周围加上一个在表中循环的外部FOR 循环:FOR var1, var2, ... IN SELECT ... FROM ... LOOP 感谢劳伦斯,这就是我最后所做的。我真的想知道是否有更好的方法来做到这一点。在答案中使用双 for 循环。 我认为您的第一个“TABLE2”应该是“TABLE1”,因此冒昧地解决了这个问题。 一个用于测试的示例 JSON 值会对这个问题有很大帮助。 【参考方案1】:

基于集合的方法通常比循环快得多(而且更短且不易出错)。

基于设置of your answer,这与您的问题有很大不同。

INSERT INTO table2(myfield, data)  -- cleaner: explicit target columns
SELECT k."myField", j.i ->> 'data'
FROM   table1 k, json_array_elements(k."ScrapedJson" -> 'calendar_days') j(i)
WHERE  NOT k."HasBeenProcessed"
-- ORDER BY ???  -- you might want to order rows favorably?

隐式 LATERAL 连接是这里的关键技术。

... FROM   table1 k, json_array_elements(...) ...

是:

... FROM   table1 k
    CROSS  JOIN LATERAL json_array_elements(...) ...

显然,"ScrapedJson" -> 'calendar_days' 是一个 JSON 数组,而不是您在问题中写的“列表”。

相关:

What is the difference between LATERAL and a subquery in PostgreSQL?

旁白

帮自己一个忙,避免在 Postgres 中出现双引号的 CaMeL 案例名称。在您的问题和答案中大量使用引用和 未引用 标识符只会造成混淆。我在您的问题中引用了列名,以在某种程度上与您的答案相匹配。我的长期建议:只使用合法的、小写的、不带引号的名称。

Are PostgreSQL column names case-sensitive?

对于大多数工作负载,请考虑使用数据类型 jsonb 而不是 json

【讨论】:

【参考方案2】:

感谢劳伦斯,这里是任何感兴趣的人的解决方案。

我想知道,有没有更好的方法?

DO
$BODY$
DECLARE
    i json;
    k RECORD;
    mydata INT;
begin

FOR k IN SELECT * from TABLE1 where "HasBeenProcessed" = FALSE
    LOOP  

            FOR i IN SELECT * FROM json_array_elements(k."ScrapedJson" -> 'calendar_days')
              LOOP

                mydata = i->> 'data';

                INSERT INTO "Table2" VALUES (k."myField",mydata);

            END LOOP;


end LOOP;


END;
$BODY$ language plpgsql

【讨论】:

您的答案似乎建立在与您的问题中提出的完全不同的表格上......

以上是关于为每条记录解析一个带有 FOR 循环的 JSON 列?的主要内容,如果未能解决你的问题,请参考以下文章

带有循环和附件的CFMAIL

为每条记录运行子查询?

PLpgSQL:将每条记录存储在 For Loop 中并返回 json

SQL Server - 随机随机播放结果,但为每条记录分配权重

bigquery 为每条记录转置和连接

如何以编程方式填充核心数据存储,为每条记录生成索引