You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Psycopg2存储过程中无法遍历嵌套字典的问题排查

问题描述

我尝试通过psycopg2中的存储过程,将列表内嵌套字典中的值插入Postgres表。以下是从JSON应用获取的数据结构:

[
    {
        "team_id": 236,
        "lineup": [
            {
                "player_id": 3043,
                "country": {
                    "id": 61,
                    "name": "Denmark"
                }
            }
        ]
    },
    {
        "team_id": 237,
        "lineup": [
            {
                "player_id": 3045,
                "country": {
                    "id": 62,
                    "name": "Italy"
                }
            }
        ]
    }
]

我需要将球员的country信息插入Postgres的country表,其中id为integer类型,name为VARCHAR类型。我的存储过程代码如下:

CREATE PROCEDURE insert_country_by_lineups(data JSON)
AS $$
BEGIN
    FOR team IN SELECT * FROM json_array_elements(data) LOOP
        FOR player in SELECT * FROM json_array_elements(team->'lineup') LOOP
            INSERT INTO country(id,name) 
            VALUES (CAST(player->'country'->>'id' AS integer), player->'country'->>'name')
            ON CONFLICT DO NOTHING RETURNING id;
        END LOOP;
    END LOOP; 
END;
$$ LANGUAGE plpgsql;

但执行该存储过程时,我遇到了如下错误:

loop variable of loop over rows must be a record variable or list of scalar variables
LINE 5:         FOR team IN SELECT * FROM json_array_elements(data...
错误原因及解决方案

错误根源是PL/pgSQL的循环变量未声明类型:FOR team IN ...中的team以及内层的player没有被显式声明为record类型,PL/pgSQL无法自动推断变量类型,因此抛出报错。

以下两种方案可以解决问题:

方案一:显式声明循环变量为record类型

在BEGIN块前添加变量声明,指定team和player为record类型,同时可以移除无意义的RETURNING id(循环中未接收返回值):

CREATE PROCEDURE insert_country_by_lineups(data JSON)
AS $$
DECLARE
    team record;
    player record;
BEGIN
    FOR team IN SELECT * FROM json_array_elements(data) LOOP
        FOR player in SELECT * FROM json_array_elements(team->'lineup') LOOP
            INSERT INTO country(id,name) 
            VALUES (CAST(player->'country'->>'id' AS integer), player->'country'->>'name')
            ON CONFLICT DO NOTHING;
        END LOOP;
    END LOOP; 
END;
$$ LANGUAGE plpgsql;

方案二:改用集合查询批量插入(更高效)

嵌套循环的执行效率较低,推荐直接利用Postgres的JSON展开能力,通过集合查询一次性完成批量插入,完全避免循环变量的问题:

CREATE PROCEDURE insert_country_by_lineups(data JSON)
AS $$
BEGIN
    INSERT INTO country(id, name)
    SELECT 
        (player->'country'->>'id')::integer,
        player->'country'->>'name'
    FROM 
        json_array_elements(data) AS teams,
        json_array_elements(teams->'lineup') AS player
    ON CONFLICT DO NOTHING;
END;
$$ LANGUAGE plpgsql;

内容的提问来源于stack exchange,提问作者clattenburg cake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:25:17