PHP/SQL - 将 CSV 上传到数据库 - 不同的工作表 daily/Multiple 表
PHP/SQL - Uploading CSV to database - Different sheets daily/Multiple Tables
我昨天问了一个不清楚的问题,现在我稍微扩展了一下。简而言之,这个当前项目需要一个简单的 Web 界面,用户可以在其中上传一个 csv 文件(这个网页已经创建)。我已经为测试文件修改了我的 PHP,但我的情况需要一些不同的东西。每天,用户会上传 1 到 5 个不同的 CSV 报告。这些报告大约有 110 fields/columns,但并不是每份报告都会填写所有字段。我创建了一个包含 5 table 的数据库,每个 table 涵盖 110 个不同的字段。例如,一个 table 包含水表(25 个字段)的信息,另一个table 包含在仪表上完成的测试的信息(45 个字段)。我很难找到一种方法来获取 CSV,一旦上传,并将数据分成不同的 tables。我听说过将整个 CSV 放入一个 table 并使用 INSERT 语句从那里拆分,但我对此有疑问:
有没有一种方法可以在不创建字段的情况下将具有 110 个字段的 CSV 合并为一个 table?或者我必须在 MYSQL workbench 中创建 110 个字段,然后在 PHP?
中为每个字段创建一个变量
如果没有,我能否从 table 转储中声明变量,以便正确的数据进入正确的 table?
就像这样上传而言,我对 CSV 不太熟悉,通常只是从文件名已知的文件夹中提取一个 csv,所以这就是我的困惑所在。这是我用作简单测试的 PHP,只有 10 列。这样做是为了确保 CSV 上传工作正常。
<?php
$server = "localhost";
$user = "root";
$pw = "root";
$db = "uwstest";
$connect = mysqli_connect($server, $user, $pw, $db);
if ($connect->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
if(isset($_POST['submit']))
{
$file = $_FILES['file']['tmp_name'];
$handle = fopen($file, "r");
$c = 0;
while(($filesop = fgetcsv($handle, 1000, ",")) !== false)
{
$one = $filesop[0];
$two = $filesop[1];
$three = $filesop[2];
$four = $filesop[3];
$five = $filesop[4];
$six = $filesop[5];
$seven = $filesop[6];
$eight = $filesop[7];
$nine = $filesop[8];
$ten = $filesop[9];
$sql = "INSERT INTO staging (One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten) VALUES ('$one','$two', '$three','$four','$five','$six','$seven','$eight','$nine','$ten')";
}
if ($connect->query($sql) === TRUE) {
echo "You database has imported successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
}
}?>
假设 tables 和 CSV 之间的关系是任意但统一的,现在您只需要建立对应数组索引 -> table 列一次。
根据 CSV 大小,您可能需要考虑使用 MySQL 的原生 CSV 导入功能,因为它的运行速度快 10 倍到 100 倍。
如果你坚持逐行导入,那么你可以用PDO做这样的事情(或者适应mysqli)。
如果你想匹配列,那么要么将你的 csv 存储为关联数组,要么解析第一行并将其存储在 $cols 之类的数组中。
在这种情况下,$results 是一个关联数组,它存储了一行 column_name=>column_value
的 csv
$cols=implode(',',array_keys($result));
$vals=':'.str_replace(",",",:",$cols);
$inserter = $pdo->prepare("INSERT INTO `mydb`.`mytable`($cols) VALUES($vals);");
foreach ($result as $k => $v) {
$result[':' . $k] = utf8_encode($v);
if(is_null($v))
$result[':' . $k] = null;
unset($result[$k]);
}
$inserter->execute($result);
希望这对您有所帮助。
我建议使用 PDO 只是为了避免您在 CSV 数据中可能遇到的各种怪异现象。
这就是我创建 columns/vals 的方式。
$is_first=true;
$cols='';
$vals='';
$cols_array=array();
while (($csv = fgetcsv($handle)) !== false) {
if($is_first)
{
$cols_array=$csv;
$cols=implode(',',$csv);
$is_first=false;
$vals=':'.str_replace(",",",:",$cols);
continue;
}
foreach ($result as $k => $v) {
$result[':' . $cols_array[$k]] = utf8_encode($v);
if(is_null($v))
$result[':' . $cols_array[$k]] = null;
unset($result[$k]);
}
$inserter->execute($result);
}
这是我用于 CSV 导入的代码。
$file='data/data.csv';
$handle = fopen($file, "r");
$path=realpath(dirname(__FILE__));
$full_path=$path."/../../$file";
$cnt = 0;
$is_first = true;
$headers=array();
$bind=array();
$csv = fgetcsv($handle, 10000, ",");
$headers=$csv;
$alt_query='LOAD DATA LOCAL INFILE \''.$full_path.'\' INTO TABLE mytable
FIELDS TERMINATED BY \',\'
ENCLOSED BY \'\"\'
LINES TERMINATED BY \'\r\n\'
IGNORE 1 LINES
(' . implode(',',$headers).')';
echo exec("mysql -e \"USE mydb;$alt_query;\"",$output,$code);
我昨天问了一个不清楚的问题,现在我稍微扩展了一下。简而言之,这个当前项目需要一个简单的 Web 界面,用户可以在其中上传一个 csv 文件(这个网页已经创建)。我已经为测试文件修改了我的 PHP,但我的情况需要一些不同的东西。每天,用户会上传 1 到 5 个不同的 CSV 报告。这些报告大约有 110 fields/columns,但并不是每份报告都会填写所有字段。我创建了一个包含 5 table 的数据库,每个 table 涵盖 110 个不同的字段。例如,一个 table 包含水表(25 个字段)的信息,另一个table 包含在仪表上完成的测试的信息(45 个字段)。我很难找到一种方法来获取 CSV,一旦上传,并将数据分成不同的 tables。我听说过将整个 CSV 放入一个 table 并使用 INSERT 语句从那里拆分,但我对此有疑问:
有没有一种方法可以在不创建字段的情况下将具有 110 个字段的 CSV 合并为一个 table?或者我必须在 MYSQL workbench 中创建 110 个字段,然后在 PHP?
中为每个字段创建一个变量
如果没有,我能否从 table 转储中声明变量,以便正确的数据进入正确的 table?
就像这样上传而言,我对 CSV 不太熟悉,通常只是从文件名已知的文件夹中提取一个 csv,所以这就是我的困惑所在。这是我用作简单测试的 PHP,只有 10 列。这样做是为了确保 CSV 上传工作正常。
<?php
$server = "localhost";
$user = "root";
$pw = "root";
$db = "uwstest";
$connect = mysqli_connect($server, $user, $pw, $db);
if ($connect->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
if(isset($_POST['submit']))
{
$file = $_FILES['file']['tmp_name'];
$handle = fopen($file, "r");
$c = 0;
while(($filesop = fgetcsv($handle, 1000, ",")) !== false)
{
$one = $filesop[0];
$two = $filesop[1];
$three = $filesop[2];
$four = $filesop[3];
$five = $filesop[4];
$six = $filesop[5];
$seven = $filesop[6];
$eight = $filesop[7];
$nine = $filesop[8];
$ten = $filesop[9];
$sql = "INSERT INTO staging (One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten) VALUES ('$one','$two', '$three','$four','$five','$six','$seven','$eight','$nine','$ten')";
}
if ($connect->query($sql) === TRUE) {
echo "You database has imported successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
}
}?>
假设 tables 和 CSV 之间的关系是任意但统一的,现在您只需要建立对应数组索引 -> table 列一次。
根据 CSV 大小,您可能需要考虑使用 MySQL 的原生 CSV 导入功能,因为它的运行速度快 10 倍到 100 倍。
如果你坚持逐行导入,那么你可以用PDO做这样的事情(或者适应mysqli)。
如果你想匹配列,那么要么将你的 csv 存储为关联数组,要么解析第一行并将其存储在 $cols 之类的数组中。
在这种情况下,$results 是一个关联数组,它存储了一行 column_name=>column_value
的 csv$cols=implode(',',array_keys($result));
$vals=':'.str_replace(",",",:",$cols);
$inserter = $pdo->prepare("INSERT INTO `mydb`.`mytable`($cols) VALUES($vals);");
foreach ($result as $k => $v) {
$result[':' . $k] = utf8_encode($v);
if(is_null($v))
$result[':' . $k] = null;
unset($result[$k]);
}
$inserter->execute($result);
希望这对您有所帮助。 我建议使用 PDO 只是为了避免您在 CSV 数据中可能遇到的各种怪异现象。
这就是我创建 columns/vals 的方式。
$is_first=true;
$cols='';
$vals='';
$cols_array=array();
while (($csv = fgetcsv($handle)) !== false) {
if($is_first)
{
$cols_array=$csv;
$cols=implode(',',$csv);
$is_first=false;
$vals=':'.str_replace(",",",:",$cols);
continue;
}
foreach ($result as $k => $v) {
$result[':' . $cols_array[$k]] = utf8_encode($v);
if(is_null($v))
$result[':' . $cols_array[$k]] = null;
unset($result[$k]);
}
$inserter->execute($result);
}
这是我用于 CSV 导入的代码。
$file='data/data.csv';
$handle = fopen($file, "r");
$path=realpath(dirname(__FILE__));
$full_path=$path."/../../$file";
$cnt = 0;
$is_first = true;
$headers=array();
$bind=array();
$csv = fgetcsv($handle, 10000, ",");
$headers=$csv;
$alt_query='LOAD DATA LOCAL INFILE \''.$full_path.'\' INTO TABLE mytable
FIELDS TERMINATED BY \',\'
ENCLOSED BY \'\"\'
LINES TERMINATED BY \'\r\n\'
IGNORE 1 LINES
(' . implode(',',$headers).')';
echo exec("mysql -e \"USE mydb;$alt_query;\"",$output,$code);