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

使用psycopg2向PostgreSQL jsonb字段写入数据遇格式错误求助

问题:使用psycopg2向PostgreSQL jsonb字段写入数据报错

以下是我的代码:

from psycopg2.extras import Json
from psycopg2.extensions import register_adapter
from psycopg2.extras import execute_values
import psycopg2

register_adapter(dict, Json)

data = [{
    'end_of_epoch_data': ['GasCoin', [{'Input': 5}, {'Input': 6}, {'Input': 7}]],
}]

def get_upsert_sql(schema: str, table: str, columns: str, primary_keys: list | tuple | set):
    return f"""INSERT INTO {schema}.{table}
            ({', '.join(columns)}) VALUES %s
            ON CONFLICT ({','.join(primary_keys)}) DO UPDATE
            SET {', '.join([f"{col}=EXCLUDED.{col}" for col in columns if col not in primary_keys])}"""


def upsert(data: list, uri: str, schema: str, table: str, primary_keys: list | tuple | set):
    connection = psycopg2.connect(uri)
    cursor = connection.cursor()
    try:
        columns = data[0].keys()
        query = get_upsert_sql(schema, table, columns, primary_keys)
        values = [[d[col] for col in columns] for d in data]
        execute_values(cursor, query, values)
        connection.commit()
    except Exception as e:
        connection.rollback()
        raise e
    finally:
        cursor.close()
        connection.close()

执行时出现如下错误:

File "/Users/tests/test_pg_write.py", line 47, in upsert
    execute_values(cursor, query, values)
  File "/Users/venv/lib/python3.9/site-packages/psycopg2/extras.py", line 1299, in execute_values
    cur.execute(b''.join(parts))
psycopg2.errors.InvalidTextRepresentation: malformed array literal: "GasCoin"
LINE 2:             (end_of_epoch_data) VALUES (ARRAY['GasCoin',ARRA...
                                                      ^
DETAIL:  Array value must start with "{" or dimension information.

其中end_of_epoch_data是PostgreSQL表中的jsonb列,请问该如何解决?

更新
我发现错误原因似乎是尝试将Python列表写入jsonb字段,那使用json.dumps(data['end_of_epoch_data'])将列表转为字符串写入是否是正确的解决方案?


解决方案

错误原因分析

你仅注册了dict到Json适配器,但未处理Python列表类型。execute_values会默认把Python列表识别为PostgreSQL的数组类型,而非jsonb,这就导致PostgreSQL解析时出错——因为你的列表首元素是字符串"GasCoin",不符合PostgreSQL数组需用{}包裹的语法要求。

正确解决方式

方式1:为列表注册Json适配器

直接将list类型也注册到Json适配器,让psycopg2自动把Python列表转为jsonb格式:

from psycopg2.extras import Json
from psycopg2.extensions import register_adapter

# 同时注册dict和list类型
register_adapter(dict, Json)
register_adapter(list, Json)

方式2:手动用Json包装目标字段

构造values时,针对jsonb字段的值手动用Json()包裹:

values = [[Json(d[col]) if col == 'end_of_epoch_data' else d[col] for col in columns] for d in data]

关于json.dumps的说明

用json.dumps转字符串写入不是最优方案:虽然能成功写入,但PostgreSQL会将其存储为普通字符串,而非jsonb类型。后续查询时需手动用jsonb()函数转换才能进行jsonb的专属操作(如->路径查询),完全失去了jsonb类型的优势,因此不推荐。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:10:14