从 CSV NULL 值导入的 PostgreSQL 是文本 - 需要 null

Posted

技术标签:

【中文标题】从 CSV NULL 值导入的 PostgreSQL 是文本 - 需要 null【英文标题】:PostgreSQL import from CSV NULL values are text - Need null 【发布时间】:2021-01-12 22:00:48 【问题描述】:

我使用 phpMyAdmin 从 mysql 数据库中将一堆表 (>30) 导出为 CSV 文件。这些 CSV 文件包含 NULL 值,例如:

"id","sourceType","name","website","location"
"1","non-commercial","John Doe",NULL,"California"

我使用 TablePlus 将许多此类 csv 导入到 PostgreSQL 数据库。但是,列中的 NULL 值实际上显示为文本而不是 null。

当我的应用程序从这些列中获取数据时,它实际上检索的是文本 'NULL' 而不是空值。

另外,带有IS NULL 的 SQL 命令也不会检索这些行,可能是因为它们被标识为文本而不是空值。

是否有一个 SQL 命令可以将所有表中的所有文本 NULL 值转换为实际的 NULL 值?这是避免重新导入所有表的最简单方法。

【问题讨论】:

也许写一个简单的脚本来读取 CSV 并插入到表格中? 我的问题更多的是导入完成后要做什么。 问题是为什么NULL在这个字段中而不是一个空(null)字段。除非您需要经常这样做,否则最简单的解决方案是将该列定义为 TEXT 导入到临时表中,然后通过适当的转换选择到最终表中。 @BjarniRagnarsson 你能提供一个例子作为解决方案吗? 一种方法是在选择入决赛表时使用NULLIF函数将NULL字符串转换为null。实际上 - 在这种情况下,您可以直接读入决赛表并运行 update table set website=null where website='NULL';,因为它是一个文本列,NULL 不会导致错误。 【参考方案1】:

PostgreSQL 的COPY 命令具有NULL 'some_string' 选项,允许将任何字符串指定为NULL 值:https://www.postgresql.org/docs/current/sql-copy.html 这当然需要重新导入所有表格。

您的数据示例:

CSV:

"id","sourceType","name","website","location"
"1","non-commercial","John Doe",NULL,"California"
"2","non-commercial","John Doe",NULL,"California"

桌子:

CREATE TABLE import_with_null (id integer, source_type varchar(50), name varchar(50), website varchar(50), location varchar(50));

COPY 声明:

COPY import_with_null (id, source_type, name, website, location) from '/tmp/import_with_NULL.csv' WITH (FORMAT CSV, NULL 'NULL', HEADER);

测试将 NULL 字符串正确导入为 SQL NULL:

SELECT * FROM import_with_null WHERE website IS NULL;
 id |  source_type   |   name   | website |  location  
----+----------------+----------+---------+------------
  1 | non-commercial | John Doe |         | California
  2 | non-commercial | John Doe |         | California
(2 rows)

将 NULL 字符串转换为 SQL NULL 值的重要部分是 NULL 'NULL' 并且可以是任何其他值 NULL 'whatever string'

【讨论】:

您能否举例说明一下。如果您可以展示完整示例以帮助可能再次遇到此问题的任何人,我想我会将其标记为答案,因为我上面的答案是非常特定于应用程序的(需要 laravel 和 php)。 用你的数据添加了一个完整的例子。【参考方案2】:

更新对于来这里寻找解决方案的人 查看两种潜在解决方案的答案

其中一个解决方案提供了一种 SQL COPY 方法,该方法必须在导入之前执行。该解决方案由 Michal T 提供,并标记为已接受的答案是从一开始就防止这种情况发生的更好方法。 下面的解决方案在我的应用程序中使用了一个脚本(内置于 Laravel/PHP),该脚本可以在导入完成后完成。

注意 - 查看代码中的 cmets,您可能会在其他语言/框架中找到类似的解决方案。

感谢上面 cmets 中的@BjarniRagnarsson 建议,我想出了一个简短的 PHP Laravel 脚本来对所有列(“字符串”或“文本”类型)执行更新查询,以将“NULL”文本替换为NULL 值。

    public function convertNULLStringToNULL()
    
        $tables = DB::connection()->getDoctrineSchemaManager()->listTableNames(); //Get list of all tables
        $results = []; // an array to store the output results
        foreach ($tables as $table)  // Loop through each table
            $columnNames =  DB::getSchemaBuilder()->getColumnListing($table); //Get list of all columns

            $columnResults = []; // array to store the results per column
            foreach ($columnNames as $column)  Loop through each column
                $columnType = DB::getSchemaBuilder()->getColumnType($table, $column); // Get the column type
                if (
                    $columnType == 'string' || //check if column type is string or text
                    $columnType == 'text'
                ) 
                    $query = "update " . $table . " set \"" . $column . "\"=NULL where \"" . $column . "\"='NULL'"; //Build the update query as mentioned in comments above

                    $r = DB::update($query); //perform the update query
                    array_push($columnResults, [
                        $column => $r
                    ]); //Push the column Results
                
            

            array_push($results, [
                $table => $columnResults
            ]); // push the table results
        

        dd($results); //Output the results
    

请注意,我为此使用了 Laravel 8。

【讨论】:

以上是关于从 CSV NULL 值导入的 PostgreSQL 是文本 - 需要 null的主要内容,如果未能解决你的问题,请参考以下文章

在将数据从文件插入表时,如何用 NULL 替换 NA 值?

MySQL 从 CSV 数据加载 NULL 值

PHP/MySQL:导入 CSV,所有日期和十进制值都为空,零

MySQL 不会 CSV 导入 \N 作为 NULL

NULL值不会插入到sql表中。

使用 phpMyAdmin 导入大型 csv 文件