如何避免在Postgresql中INSERT期间显式转换NULL

问题描述 投票:1回答:3

我正在编写python脚本来将表从MSSQL数据库同步到Postgresql数据库。原作者倾向于使用超宽表,其中有许多区域连续的NULL洞。

对于插入速度,我在execute()之前以下列形式将记录批量序列化为字符串

INSERT INTO A( {col_list} ) 
SELECT * FROM ( VALUES (row_1), (row_2),...) B( {col_list} )

在行序列化期间,它不可能在python中确定NULLNone的数据类型。这使得工作变得复杂。 NULL列,timestamp列等中的所有integer值都需要显式类型转换为适当的类型,或者Pg抱怨它。

目前,我正在检查DB API connection.description属性并比较列type_code,对于每个列,并根据需要添加类型转换,如::timestamp

但是这需要额外的工作感觉很麻烦:驱动程序已经将数据从文本转换为正确的python数据类型,现在我必须使用那些许多Nones重做它。

有没有更好的方法来解决这个问题,优雅和简洁?

python postgresql psycopg2
3个回答
1
投票

你可以将SELECT条款直接附加到VALUES,而不是从INSERT插入,即:

INSERT INTO A ({col_list}) 
VALUES (row_1), (row_2), ...

当您从查询中插入时,Postgres在尝试推断列类型时会单独检查查询,然后尝试强制它们匹配目标表(仅发现它不能)。

当您直接从VALUES列表插入时,它在执行类型推断时知道目标表,然后可以假设任何无类型的NULL与相应的列匹配。


2
投票

如果您不需要SELECT,请使用@Nick's answer。 如果需要它(比如使用CTE多次使用输入行),根据用例的详细信息,有一些变通方法。

例如,使用完整行时:

INSERT INTO A -- complete rows
SELECT * FROM (
   VALUES ((NULL::A).*), (row_1), (row_2), ...
   ) B
OFFSET 1;

在这种特殊情况下,{col_list}是可选噪声,因为我们无论如何都需要提供完整的行。

详细说明:


1
投票

您可以尝试使用json_populate_record(..)从数据创建json,然后从json创建rowset。

postgres=# create table js_test (id int4, dat timestamp, val text);
CREATE TABLE

postgres=# insert into js_test
postgres-# select (json_populate_record(null::js_test,
postgres(# json_object(array['id', 'dat', 'val'], array['5', null, 'test']))).*;
INSERT 0 1

postgres=# select * from js_test;
 id | dat | val
----+-----+------
  5 |     | test

你可以使用json_populate_recordset(..)一次完成多行。你只需传递json数组,即json数组。确保它不是json数组。

所以这没关系:'[{"id":1,"dat":null,"val":6},{"id":3,"val":"tst"}]'::json

这不是:array['{"id":1,"dat":null,"val":6}'::json,'{"id":3,"val":"tst"}'::json]

select *
from json_populate_recordset(null::js_test,
                             '[{"id":1,"dat":null,"val":6},{"id":3,"val":"tst"}]')
© www.soinside.com 2019 - 2024. All rights reserved.