写入CSV时如何保持空值

Jon*_*ter 5 python csv postgresql python-3.x

我正在使用Python的csv模块将数据从sql server写入csv文件,然后使用copy命令将csv文件上传到postgres数据库。问题是Python的csv编写器自动将Nulls转换为空字符串“”,并且当列为int或float数据类型时,它使我的工作失败,并且当它应为None或null值时,它将尝试插入此“”。

为了尽可能容易地与实现DB API的模块接口,将值None写为空字符串。

https://docs.python.org/3.4/library/csv.html?highlight=csv#csv.writer

保留空值的最佳方法是什么?有没有更好的方法用Python编写csv?我愿意接受所有建议。

例:

我有纬度和经度值:

42.313270000    -71.116240000
42.377010000    -71.064770000
NULL    NULL
Run Code Online (Sandbox Code Playgroud)

写入csv时,会将null转换为“”:

with file_path.open(mode='w', newline='') as outfile:
    csv_writer = csv.writer(outfile, delimiter=',', quoting=csv.QUOTE_NONNUMERIC)
    if include_headers:
        csv_writer.writerow(col[0] for col in self.cursor.description)
    for row in self.cursor:
        csv_writer.writerow(row)
Run Code Online (Sandbox Code Playgroud)

42.313270000,-71.116240000
42.377010000,-71.064770000
"",""
Run Code Online (Sandbox Code Playgroud)

空值

指定表示空值的字符串。默认值为文本格式\ N(反斜杠-N),以及CSV格式的无引号的空字符串。对于不想将空值与空字符串区分开的情况,甚至可能以文本格式使用空字符串。使用二进制格式时,不允许使用此选项。

https://www.postgresql.org/docs/9.2/sql-copy.html

回答:

对我来说解决问题的是将报价更改为csv.QUOTE_MINIMAL。

csv.QUOTE_MINIMAL指示编写器对象仅引用那些包含特殊字符(例如定界符,quotechar或换行符中的任何字符)的字段。

相关问题:-Postgresql COPY空字符串为NULL不起作用

Mar*_*ers 10

这里有两个选项:更改csv.writingPython中的引号选项,或告诉PostgreSQL接受带引号的字符串作为可能的NULL(需要PostgreSQL 9.4或更高版本)。

Python csv.writer()和报价

在Python方面,您正在告诉csv.writer()对象添加引号,因为您已将其配置为使用csv.QUOTE_NONNUMERIC

指示writer对象引用所有非数字字段。

None值是非数字的,因此导致""被写入。

切换为使用csv.QUOTE_MINIMALcsv.QUOTE_NONE

csv.QUOTE_MINIMAL
指示writer对象仅引用那些包含特殊字符(例如定界符quotecharlineterminator中的任何字符)的字段

csv.QUOTE_NONE
指示writer对象从不引用字段。当前定界符出现在输出数据中时,其前面是当前转义符。

由于您所编写的只是经度和纬度值,因此此处不需要任何引用,因此数据中不存在定界符或引号字符。

无论使用哪个选项,None值的CSV输出都是简单的空字符串:

>>> import csv
>>> from io import StringIO
>>> def test_csv_writing(rows, quoting):
...     outfile = StringIO()
...     csv_writer = csv.writer(outfile, delimiter=',', quoting=quoting)
...     csv_writer.writerows(rows)
...     return outfile.getvalue()
...
>>> rows = [
...     [42.313270000, -71.116240000],
...     [42.377010000, -71.064770000],
...     [None, None],
... ]
>>> print(test_csv_writing(rows, csv.QUOTE_NONNUMERIC))
42.31327,-71.11624
42.37701,-71.06477
"",""

>>> print(test_csv_writing(rows, csv.QUOTE_MINIMAL))
42.31327,-71.11624
42.37701,-71.06477
,

>>> print(test_csv_writing(rows, csv.QUOTE_NONE))
42.31327,-71.11624
42.37701,-71.06477
,
Run Code Online (Sandbox Code Playgroud)

PostgreSQL 9.4 COPY FROMNULL值和FORCE_NULL

从PostgreSQL 9.4开始,NULL使用该FORCE_NULL选项时,还可以强制PostgreSQL接受带引号的空字符串作为s 。从COPY FROM文档中

FORCE_NULL

将指定列的值与空字符串进行匹配(即使已将其引号),并且如果找到匹配项,则将值设置为NULL。在默认情况下,如果空字符串为空,这会将带引号的空字符串转换为NULLCOPY FROM仅当使用CSV格式时,才允许使用此选项。

在命名列FORCE_NULL选项让PostgreSQL的同时接受空列,并""NULL这些列,例如值:

>>> import csv
>>> from io import StringIO
>>> def test_csv_writing(rows, quoting):
...     outfile = StringIO()
...     csv_writer = csv.writer(outfile, delimiter=',', quoting=quoting)
...     csv_writer.writerows(rows)
...     return outfile.getvalue()
...
>>> rows = [
...     [42.313270000, -71.116240000],
...     [42.377010000, -71.064770000],
...     [None, None],
... ]
>>> print(test_csv_writing(rows, csv.QUOTE_NONNUMERIC))
42.31327,-71.11624
42.37701,-71.06477
"",""

>>> print(test_csv_writing(rows, csv.QUOTE_MINIMAL))
42.31327,-71.11624
42.37701,-71.06477
,

>>> print(test_csv_writing(rows, csv.QUOTE_NONE))
42.31327,-71.11624
42.37701,-71.06477
,
Run Code Online (Sandbox Code Playgroud)

在那一点上,您在Python端使用了什么引用选项都不再重要。

要考虑的其他选择

对于来自其他数据库的简单数据转换任务,请不要使用Python

如果您已经在查询数据库以整理数据以输入PostgreSQL,请考虑直接插入Postgres中。如果数据来自其他来源,则可以使用外部数据包装器(fdw)模块切出中间人并直接将数据从其他来源提取到PostgreSQL中。

大量数据?考虑直接从Python使用COPY FROM作为二进制文件

Numpy数据可以通过二进制文件COPY FROM更有效地插入;链接的答案使用所需的额外元数据和字节顺序扩充了一个numpy结构化数组,然后有效地创建数据的二进制副本,并使用COPY FROM STDIN WITH BINARYpsycopg2.copy_expert()方法将其插入到PostgreSQL中。巧妙地避免了数字->文本->数字转换。

持久化数据以处理管道中的大型数据集?

不要重新发明数据流水线。考虑使用诸如Apache Spark之类的现有项目,这些项目已经解决了效率问题。Spark使您可以将数据视为结构化流,并包括并行运行数据分析步骤的基础结构,并且可以将分布式结构化数据视为Pandas数据帧

另一种选择是查看Dask,以帮助在分布式任务之间共享数据集以处理大量数据。

即使将一个已经在运行的项目转换为Spark可能距离太远,至少要考虑使用Apache Arrow,Spark就是基于此构建的数据交换平台。该pyarrow项目将允许您通过Parquet文件交换数据,或通过IPC交换数据

Pandas和Numpy团队投入了大量资金来支持Arrow和Dask的需求(这些项目之间的核心成员有相当多的重叠),并且正在积极努力使Python数据交换尽可能高效,包括扩展Python pickle模块以允许带外数据流,以避免共享数据时不必要的内存复制。