python - Postgres `WITH ins AS ...` 将所有内容都转换为文本

标签 python sql postgresql psycopg2

我在 postgres 中有这张表

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, data)

当我按原样运行时,出现错误:column "a"is of type json but expression is of type text

我试图通过在 SELECT 语句中添加类型转换来解决这个问题

         'SELECT '
            'ins.a::json '
            'ins.b '
            'ins.c '
            'other_table.id'

但是我得到了错误column "c"is of type text[] but expression is of type text

所以我用同样的方法解决了这个问题:

         'SELECT '
            'ins.a::json '
            'ins.b '
            'ins.c::text[]'
            'other_table.id'

所以现在我收到错误column "b"is of type integer but expression is of type text

这个例子有些简化,因为我在原始查询中有更多的列。

  1. WITH ins ... 语句是否总是将所有内容转换为文本?这对我来说似乎是一种奇怪的行为
  2. 有没有一种无需手动对每一列进行类型转换的编码方式?这似乎不雅且计算效率低下的数据被转换为例如。从 python int 到 postgres 文本再到 postgres 整数。

最佳答案

问题不在于 CTE , 但随着你如何将值传递到 VALUES条款。以某种方式在 CTE 中创建了所有值在VALUES正在作为文本发送(也许查询是用单引号之间的所有值创建的?)。以下示例使用纯 SQL 语句重现您的查询,并且它按预期工作:

WITH ins (a, b, c, id) AS (
  VALUES ('{"answer":42}'::json,42,array['foo','bar'],1)
) 
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.id = other_table.id;

请注意,我将 json 转换为 CTE 中的值, 不在 SELECT条款。因此,如果来源是正确的,那么 postgres 将无法在您不告知的情况下将其转换为文本 ;)

演示: db<>fiddle

关于python - Postgres `WITH ins AS ...` 将所有内容都转换为文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67790537/

相关文章:

python - 如何在单个列上使用 groupby 并在 Pandas 中对多个列进行比较?

python - 在运行 'migrate' 命令之前删除 Django 迁移文件?

node.js - 启动应用程序时使用 pg-promise 验证数据库连接

SQL:当列是唯一且连续的时,向每行的给定列添加 1(或 N)?

sql - 创建一个只能在当前连接中访问的(临时?)表

sql - 如何在 RoR 中包含最后更新的行

sql - 在postgresql中获取一个 child 的所有 parent

python - 使用 dateutil.parser 解析不完整日期时,如何将日期设置为 1?

python - 从 csv 文件创建数据框,其中列表作为其中一列中的条目

sql - 如何删除重复条目?