PHP csv 导入需要帮助 - 插入 table 时十进制值变成四舍五入值
PHP csv import need help - Decimal values becomes rounded values when inserting into table
我正在尝试使用 PHP、
从 csv 文件将数据插入 MySql table
请查看这张图片 - 我的 CSV 文件。
我面临的问题是,在加载 CSV 文件时,net_sales 列变圆并插入 table。
插入后请查看下面 MySql Table 的示例图像。
仅供参考,这里我只显示 net_sales 列来解释我的问题,实际上我在 table 和 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。请帮助在 table 中插入带小数的值,因为它在 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);
我会这样做:
<?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
输出中最重要的部分是最后两个数组,您可以看到我们如何将数据映射到文件头,然后使用 $default_map
填充任何缺失的列。您可以在其中放置所需的任何默认值,例如 null 或您拥有的任何默认值,但您必须手动执行而不是使用 $default_map = array_fill_keys($placeholders, '');
这应该是不言自明的,如果不明白请随时询问。
希望我能将它们之间的所有内容以及数据库和文件内容都匹配起来,否则应该非常接近。但这是相当复杂的代码,所以我可能错过了一些东西并不是不可思议的。
重要的是这会让您以一种优雅的方式映射出 CSV 数据,并避免任何 SQL 恶意注入。
我正在尝试使用 PHP、
从 csv 文件将数据插入 MySql table请查看这张图片 - 我的 CSV 文件。
我面临的问题是,在加载 CSV 文件时,net_sales 列变圆并插入 table。
插入后请查看下面 MySql Table 的示例图像。
仅供参考,这里我只显示 net_sales 列来解释我的问题,实际上我在 table 和 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。请帮助在 table 中插入带小数的值,因为它在 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);
我会这样做:
<?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
输出中最重要的部分是最后两个数组,您可以看到我们如何将数据映射到文件头,然后使用 $default_map
填充任何缺失的列。您可以在其中放置所需的任何默认值,例如 null 或您拥有的任何默认值,但您必须手动执行而不是使用 $default_map = array_fill_keys($placeholders, '');
这应该是不言自明的,如果不明白请随时询问。
希望我能将它们之间的所有内容以及数据库和文件内容都匹配起来,否则应该非常接近。但这是相当复杂的代码,所以我可能错过了一些东西并不是不可思议的。
重要的是这会让您以一种优雅的方式映射出 CSV 数据,并避免任何 SQL 恶意注入。