我正在尝试使用PHP将数据从csv文件插入到MySql表中,
我遇到的问题是,在加载CSV文件时,net_sales列会变为圆角并插入表格中。
仅供参考,我在这里只显示了net_sales列来解释我的问题,实际上我在表格和CSV中有更多列。
由于某些原因,我不能使用像"insert into tran_detail (tran_id,tran_datetime,net_sales) values (...)";
所以我更喜欢这句话"INSERT INTO tran_detail (".implode(',', array_keys($data)).") VALUES('".implode('\',\'', array_map("convert",array_values($data)))."')";
这是我用于插入的PHP。请帮助在表中插入带小数的值,就像在CSV中一样。
function convert($string)
{
return htmlspecialchars($string,ENT_QUOTES);
}
$columnArray = array();
$dataArray = array();
$firstRule = true;
while ($data = fgetcsv ($source, 1000, ","))
{
if($firstRule)
{
foreach($data as $columnName)
{
$columnArray[] = $columnName;
}
$firstRule = false;
}
else
{
$rule = array();
for($i = 0; $i < count($data) ; $i++)
{
$rule[$columnArray[$i]] = $data[$i];
}
$dataArray[] = $rule;
}
}
foreach($dataArray as $data)
{
$query = "INSERT INTO `tran_detail` (".implode('`,`', array_keys($data))."`) VALUES('".implode('\',\'', array_map("convert",array_values($data)))."')";
mysql_query($query) or mysql_error();
}
fclose($source);
答案 0 :(得分:3)
这是我这样做的方式:
<?php
/*
PDO named placeholders require that the array keys are matched
so we have to prefix them with a colon : as in 'field' becomes ':field'
the benefit here is the array key order is irrelevant,
so your csv could have the headers in any order.
*/
function prefixPdoArray(array $array){
return array_map(function($item){
return ':'.$item;
}, $array);
}
//PDO database driver
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
$db = new PDO($dsn, $user, $password);
//header array should match DB fields
$header_map = [
'field1',
'field2',
'field3',
'field4',
];
$placeholders = prefixPdoArray($header_map);
//prepare the query outside of the loop
$stmt = $db->prepare('INSERT INTO `tran_detail` (`'.implode('`,`', $header_map).'`)VALUES('.implode(',', $placeholders).')');
/*
we can dynamically build the query because $header_map and $placeholders
are "canned" data, but you could just type it out as well.
if you do the SQL manually you can dump $header_map and $placeholders
and manually create $default_map. You could also dump this function
prefixPdoArray() and just move the array map to $headers.
so it would be a bit more efficient, but I thought I would show you
a proper way to build the query dynamically.
*/
$default_map = array_fill_keys($placeholders, '');
//read the first line
$headers = fgetcsv($source, 1000, ",");
//$header_count = count($csv_headers); //for error chcking if needed
//prefix csv headers
$headers = prefixPdoArray($headers);
while ($data = fgetcsv($source, 1000, ",")){
/*
array combine will throw an error if the header length
is different then the data length.
this indicates a missing or extra delimiter in the csv file.
you may or may not have to check for this condition
-------------------------------------
if( $header_count != count($data) ){ //do something on error }
*/
//map file data to file headers
$csv_mapped = array_combine( $headers, $data);
//map file row to database query
$csv_mapped = array_replace($default_map, $csv_mapped );
//execute the query
$stmt->execute($csv_mapped);
}
fclose($source);
注意我只能对此进行有限的测试(没有数据库或文件),因此,为了测试和解释,这里是用于测试基本功能的代码。
<?php
function prefixPdoArray(array $array){
return array_map(function($item){
return ':'.$item;
}, $array);
}
//header array should match DB fields
$header_map = [
'field1',
'field2',
'field3',
'field4',
];
$placeholders = prefixPdoArray($header_map);
echo str_pad(' Placeholders ', 45, '-', STR_PAD_BOTH)."\n";
var_dump($placeholders);
//prepare the query
echo "\n".str_pad(' Raw SQL ', 45, '-', STR_PAD_BOTH)."\n";
echo 'INSERT INTO `tran_detail` (`'.implode('`,`', $header_map).'`)VALUES('.implode(',', $placeholders).')';
$default_map = array_fill_keys($placeholders, '');
echo "\n\n".str_pad(' Default Map ', 45, '-', STR_PAD_BOTH)."\n";
var_dump($default_map);
//(CANNED TEST DATA) read the first line
//example data for testing ( missing field1 ), and field3 out of order
$headers = [
'field3',
'field2',
'field4',
];
//prefix headers with placeholders
$headers = prefixPdoArray($headers);
echo "\n".str_pad(' CSV headers ', 45, '-', STR_PAD_BOTH)."\n";
var_dump($headers);
//while ($data = fgetcsv($source, 1000, ",")){
//(CANNED TEST DATA) read the data line(s)
//example data for testing ( missing field1 ), and field3 out of order
$data = [
'value3',
'value2',
'value4',
];
echo "\n".str_pad(' CSV data ', 45, '-', STR_PAD_BOTH)."\n";
var_dump($data);
$csv_mapped = array_combine( $headers, $data);
echo "\n".str_pad(' CSV mapped data ', 45, '-', STR_PAD_BOTH)."\n";
var_dump($csv_mapped);
$csv_mapped = array_replace($default_map, $csv_mapped );
echo "\n".str_pad(' CSV filled data ', 45, '-', STR_PAD_BOTH)."\n";
var_dump($csv_mapped);
//}
输出
--------------- Placeholders ----------------
array(4) {
[0]=> string(7) ":field1"
[1]=> string(7) ":field2"
[2]=> string(7) ":field3"
[3]=> string(7) ":field4"
}
------------------ Raw SQL ------------------
INSERT INTO `tran_detail` (`field1`,`field2`,`field3`,`field4`)VALUES(:field1,:field2,:field3,:field4)
---------------- Default Map ----------------
array(4) {
[":field1"]=> string(0) ""
[":field2"]=> string(0) ""
[":field3"]=> string(0) ""
[":field4"]=> string(0) ""
}
---------------- CSV headers ----------------
array(3) {
[0]=> string(7) ":field3"
[1]=> string(7) ":field2"
[2]=> string(7) ":field4"
}
----------------- CSV data ------------------
array(3) {
[0]=> string(6) "value3"
[1]=> string(6) "value2"
[2]=> string(6) "value4"
}
-------------- CSV mapped data --------------
array(3) {
[":field3"]=> string(6) "value3"
[":field2"]=> string(6) "value2"
[":field4"]=> string(6) "value4"
}
-------------- CSV filled data --------------
array(4) {
[":field1"]=> string(0) ""
[":field2"]=> string(6) "value2"
[":field3"]=> string(6) "value3"
[":field4"]=> string(6) "value4"
}
你可以在这里查看。
http://sandbox.onlinephpfunctions.com/code/ab868ac6c6fbf43d74cf62ef2907b0c72e1f59bf
输出中最重要的部分是最后2个数组,因为您可以看到我们如何将数据映射到文件头,然后使用$default_map
填写任何缺少的列。你可以在你需要的地方放置任何默认值,例如null或你有什么,但是你必须手动而不是使用$default_map = array_fill_keys($placeholders, '');
如果不随意问的话,这应该是非常自我解释的。
希望我得到它们之间的所有内容以及数据库和文件的内容,如果不是它应该非常接近。但这是相当复杂的代码,所以我可能错过了一些不可思议的事情。
重要的是,它可以让您以优雅的方式映射CSV数据,并避免任何SQL注入错误。