我在 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
这个例子有些简化,因为我在原始查询中有更多的列。
WITH ins ...
语句是否总是将所有内容转换为文本?这对我来说似乎是一种奇怪的行为- 有没有一种无需手动对每一列进行类型转换的编码方式?这似乎不雅且计算效率低下的数据被转换为例如。从 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/