使用 COPY FROM 从 CSV 导入数据时转换列

Posted

技术标签:

【中文标题】使用 COPY FROM 从 CSV 导入数据时转换列【英文标题】:Casting column when using COPY FROM to import data from CSV 【发布时间】:2020-04-24 00:32:44 【问题描述】:

使用 PostgreSQL 12,我尝试从 CSV 导入数据,格式如下:

country,state,county,lat,lng,type,measure,beds,population,year,source,source_url
US,AK,ketchikan gateway,63.588753,-154.493062,ICU,1000HAB,3.928701,13745,2018,arcgis,https://services1.arcgis.com/Hp6G80Pky0om7QvQ/arcgis/rest/services/Hospitals_1/FeatureServer/0
US,AK,kodiak island,63.588753,-154.493062,ACUTE,1000HAB,,n,2018,arcgis,https://services1.arcgis.com/Hp6G80Pky0om7QvQ/arcgis/rest/services/Hospitals_1/FeatureServer/0

请注意,第二行的“人口”字段有一个 n 而不是空的。我的目标是导入 CSV,以便“人口”列是 BIGINT,并且“n”被替换为 NULL。我目前的解决方案是:

CREATE TABLE temp_table
(
    country CHAR(2),
    state CHAR(2),
    county VARCHAR(255),
    lat DOUBLE PRECISION,
    lng DOUBLE PRECISION,
    type VARCHAR(11),
    measure VARCHAR(255),
    beds DOUBLE PRECISION,
    pop VARCHAR(255),
    year SMALLINT,
    source VARCHAR(255),
    source_url VARCHAR(255)
);

COPY temp_table 
FROM 'C:\\Users\\mconr\\Downloads\\global-hospital-beds-capacity-for-covid19\\hospital_beds_USA_v1.CSV' 
WITH (DELIMITER ',', FORMAT CSV, HEADER TRUE);

SELECT country, state, county, lat, lng, type, measure, beds, CAST (NULLIF (pop, 'n') AS BIGINT) AS population, year, source, source_url 
INTO USA
FROM temp_table;

DROP TABLE temp_table;

我目前的解决方案是创建一个临时表,其中“population”为 VARCHAR(255),导入数据,从 SELECT 语句创建一个新表,将“n”替换为 NULL,并将列转换为 BIGINT,然后删除临时表。但是,这似乎有点低效,因为我正在创建和删除一个中间表。有谁知道这样做的更好方法吗?

【问题讨论】:

【参考方案1】:

您可以将 NULL 参数设置为“n”,但这会破坏其他情况,其中空字段以通常的方式(由未引用的空字符串)表示,而不是由“n”表示。 COPY 不允许您为每列设置 NULL。

您当前的方法对我来说似乎很好,这将是我的首选(除了修复可能超出您控制范围的此文件的生成器)。您还可以使用 Perl 或 awk 或 sed 编写一些内容,将文件作为流编辑以将“,n”转换为“,”,并使用 PROGRAM 功能将其连接到 COPY,但这似乎很繁琐且错误很容易,我怀疑效率提升会那么大。

这是一种过早的优化,是最邪恶的根源。这真的是一个有意义的问题吗?

【讨论】:

我同意你的所有观点。我将保持我的解决方案原样。正如你所说,我可以更改生成器,但数据来自 Kaggle,所以这是不可能的。我可以编写一个脚本(如在 Python 中),在导入数据库之前对文件进行预处理,但这会引发您在我看来提出的问题。我是 SQL 新手,只想写出最好的代码,所以我只是想看看是否有更好的解决方案。非常感谢您的意见!

以上是关于使用 COPY FROM 从 CSV 导入数据时转换列的主要内容,如果未能解决你的问题,请参考以下文章

COPY FROM .csv 文件到远程 PostgreSQL 数据库(在 Linux 服务器上运行)

错误:加载到表中 - COPY 命令中的数据无效

COPY FROM CSV 上的 Cassandra CQLSH TEXT 字段限制(字段大于字段限制 (131072))

将 csv 导入到 postgresql:缺少列的数据

使用 COPY 导入时 Redshift 添加列

将压缩的 CSV 文件导入 PostgreSQL