通过 CSV 导出/导入 mysql json 对象

Posted

技术标签:

【中文标题】通过 CSV 导出/导入 mysql json 对象【英文标题】:Export/import mysql json object via CSV 【发布时间】:2020-09-09 07:29:46 【问题描述】:

我正在使用一对 P​​HP 脚本。一个脚本从 mysql 数据库读取数据并将其导出到 csv 文件,然后第二个脚本使用 csv 将导出的 csv 文件上传到另一个 MySQL 数据库实例。数据库表 A(导出)和 B(导入)的结构是相同的。

这些脚本适用于“普通”MySQL 表和列类型。但是,当我们将它们应用于在其中一列中存储 JSON 对象的 MySQL 表时导入失败(MySQL 列类型为“json”)。

导出数据的脚本按预期工作,生成一个 CSV 文件,其中 JSON 对象用双引号括起来……就像行中的其他值一样。 导出的 CSV 文件中的行是这样的(最后一项是复杂的 json 对象,为简单起见缩写):

"894","Somebody","Related","2020-02-20",""name1":"value1","name2":"value2","name3":"value3"","expired"

在导出数据的 php 脚本中,基本上是这样的:

$rowStr =   "894","Somebody","Related","2020-02-20",""name1":"value1","name2":"value2","name3":"value3"","expired";
file_put_contents($filepath, trim($rowStr), FILE_APPEND);

导出没有问题。行按预期出现在 CSV 文件中(格式与上述相同)。

我将 csv 读入其他数据库的代码如下所示:

    $allRows = array_map('str_getcsv',file($fp)); // read the exported csv file where $fp is the path to the file

    foreach($allRows as $i => $row) 
        //get the col_names from the 2nd database table (identical to the first) where $ac-> is the class that handles data queries
        $col_names = $ac->get_table_column_names('databasename',$tablename);

        $update_arr = array();
        foreach($col_names as $i => $cname) 

            $update_arr[$cname['COLUMN_NAME']] = $val;              
        

        //and write the row to the 2nd db's table
        $ac->create_update_table($update_arr,$tablename,FALSE);
   

如果重要的话,这里是“get_table_column_names”和“create_update_table”函数中使用的查询:

get_table_column_names //使用 PDO

SELECT COLUMN_NAME,COLUMN_DEFAULT,DATA_TYPE FROM information_schema.columns WHERE table_schema = :db AND table_name = :table

创建更新表

INSERT INTO 'tablename' (field1, field2, field3, field4,json_object_column) VALUES ("894","Somebody","Related","2020-02-20",""name1":"value1","name2":"value2","name3":"value3"")

问题是,在导入时,行被转换成这样的数组:

array (
[0] = "894",
[1] = "Somebody",
[2] = "Related",
[3] = "2020-02-20",
[4] = "name1":"value1",
[5] = "name2:"value2",  //should be part of node 4
[6] = "name3:"value3"", //should be part of node 4
[7] = "expired"
);

发生的情况是 JSON 对象中的“,”被视为字段分隔符,并且 JSON 被分解为数组节点。除了编写脚本来检测以“ 并以 ”结尾的字段之外,我如何将整个 json 字符串作为一个字段读取(就像它在数据库中一样)?或者,也许有更好的方法来输出字符串以便可以将其作为一个项目读取?

【问题讨论】:

【参考方案1】:

如果您不只是使用file_put_contents() 之类的东西写出数据,而是使用为 CSV 文件设计的一些方法,那么这将为您完成大部分工作...

要写入数据,请使用fputcsv(),它会转义分隔符(在这种情况下“变成”)...

$row = ["894","Somebody","Related","2020-02-20",'"name1":"value1","name2":"value2","name3":"value3"',"expired"];

$fh = fopen($filepath, "a");
fputcsv($fh, $row);
fclose($fh);

将写入文件

894,Somebody,Related,2020-02-20,"""name1"":""value1"",""name2"":""value2"",""name3"":""value3""",expired

然后要从文件中读取,只需一次读取一行并使用fgetcsv()...

$fh = fopen($filepath, "r");
print_r(fgetcsv($fh));   // This in a loop to read all lines
fclose($fh);

显示

Array
(
    [0] => 894
    [1] => Somebody
    [2] => Related
    [3] => 2020-02-20
    [4] => "name1":"value1","name2":"value2","name3":"value3"
    [5] => expired
)

【讨论】:

我尝试了这两种工具(fputcsvfgetcsv)的组合,但没有让它们工作。使用您明确的解决方案,它可以按预期工作!谢谢!我发现的一件小事是导出时fopen 的“a”设置至关重要。我曾尝试使用 'w' 进行 fopen 并且只在文件中写入一行。 这是 fopen 中的模式,使用 w 将文件清空并允许您写入,a 打开用于写入并附加数据。看看php.net/manual/en/function.fopen.php的模式部分,还有更多选择。【参考方案2】:

解决此问题的一种方法是创建数组的新副本并操作新数组 并将 json 添加为原始数组的切片部分。

$allRows = array_map('str_getcsv',file($fp)); 

$new_arr = [];
foreach($allRows[0] as $key=>$item) 

    $json = false;

    if (substr($item,0,1) == '') 
        $json_start = $key;
        $json = true;
    

    if (substr($item,-2,2) == '"') 
        $json_stop = $key;
        $json = true;

        //Slice json-part from original array (in your case 4,5,6)
        $sl = array_slice($allRows[0], $json_start, ($json_stop-$json_start)+1);

        //Add the sliced part into key where json started
        $new_arr[$json_start] = implode('',$sl);         
    

    if ($json === false) $new_arr[] = $item;

然后你在$new_arr 中得到了你期望的数组。

【讨论】:

以上是关于通过 CSV 导出/导入 mysql json 对象的主要内容,如果未能解决你的问题,请参考以下文章

mongodb 导入导出

如何将csv导入mysql和mysql导出csv

Access数据表怎么导出.csv格式的文件并附加到oracle数据库?

MySQL-导入导出csv

mysql 导出导入数据 -csv

mysql导入导出CSV