通过 CSV 导出/导入 mysql json 对象
Posted
技术标签:
【中文标题】通过 CSV 导出/导入 mysql json 对象【英文标题】:Export/import mysql json object via CSV 【发布时间】:2020-09-09 07:29:46 【问题描述】:我正在使用一对 PHP 脚本。一个脚本从 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
)
【讨论】:
我尝试了这两种工具(fputcsv
和fgetcsv
)的组合,但没有让它们工作。使用您明确的解决方案,它可以按预期工作!谢谢!我发现的一件小事是导出时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 对象的主要内容,如果未能解决你的问题,请参考以下文章