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

时间:2018-02-28 10:15:08

标签: python postgresql psycopg2

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

对于插入速度,我在INSERT INTO A( {col_list} ) SELECT * FROM ( VALUES (row_1), (row_2),...) B( {col_list} )

之前以下列形式将记录批量序列化为字符串
NULL

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

目前,我正在检查每个列的数据库API ::timestamp属性并比较列type_code,并根据需要添加类型转换,如None

但这会让人感觉很麻烦,额外的工作是:驱动程序已经将数据从文本转换为适当的python数据类型,现在我必须重做那些包含那么多onSelect s的列。

有没有更好的方法来解决这个问题与优雅&简单?

3 个答案:

答案 0 :(得分: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 :(得分: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"}]')

答案 2 :(得分:1)

您可以直接将SELECT子句附加到VALUES,而不是从INSERT插入,即:

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

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

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