Psycopg2 execute_values 将所有值作为文本发送

Psycopg2 execute_values sending all values as text

我在 postgres

中有这个 table
CREATE TABLE target (
    a json
    b integer
    c text []
    id integer
    CONSTRAINT id_fkey FOREIGN KEY (id)
        REFERENCES public.other_table(id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
)

我想使用

从 psycopg2 插入数据
import psycopg2
import psycopg2.extras as extras

# data is of the form dict, integer, list(string), string <- used to get fkey id
data = [[extras.Json([{'a':1,'b':2}, {'d':3,'e':2}]), 1, ['hello', 'world'], 'ident1'],
        [extras.Json([{'a':4,'b':3}, {'d':1,'e':9}]), 5, ['hello2', 'world2'], 'ident2']]


# convert data to list of tuples containing objects
x = [tuple(u) for u in data]

# insert data to the database
query = ('WITH ins (a, b, c, ident) AS '
         '(VALUES %s) '
         'INSERT INTO target (a, b, c, id) '
         'SELECT '
            'ins.a '
            'ins.b '
            'ins.c '
            'other_table.id'
        'FROM '
            'ins '
            'LEFT JOIN other_table ON ins.ident = other_table.ident;')

cursor = conn.cursor()

extras.execute_values(cursor, query, x)

当我 运行 这个时,我得到了 error: column "a" is of type json but expression is of type text。我试图通过在 SELECT 语句中添加类型转换来解决这个问题,但后来我对 c 和 b.

都遇到了同样的错误

最初我认为问题在于 WITH 语句,但根据我之前问题的答案,情况似乎并非如此

似乎 execute_values 将所有值作为带有 ' ' 的文本发送。

主要问题: 我怎样才能让 execute_values 发送基于 python 数据类型的值,而不是仅仅文字?

子问题:
我如何确认 execute_values 实际上是以带引号的文本形式发送值?
execute_values https://www.psycopg.org/docs/extras.html 的模板参数的目的是什么,这有什么帮助吗?

Adrian Klaver points out in their , and also seen in this answer 一样,问题是 CTE 中的输入丢失了。

我们可以在 psql shell:

中用一个例子来说明这一点
CREATE TABLE test (col1 json);

WITH cte (c) AS (VALUES ('{"a": 1}'))
INSERT INTO test (col) SELECT c FROM cte; 

导致

ERROR:  column "col" is of type json but expression is of type text

而具有指定类型的此版本成功:

WITH cte(c)  AS  (VALUES ('{"a": 1}'::json))
INSERT INTO test (col) SELECT c FROM cte;

我们可以在 execute_values 中通过在模板参数中提供类型信息来模仿这一点:

extras.execute_values(cursor, query, data, template='(%s::json, %s, %s, %s)')