MySQL PDO插入错误值(CSV数据源)
MySQL PDO inserting wrong values (CSV data source)
我有一个table这样的。
CREATE TABLE `GBPAUD` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`currency_pair` varchar(11) NOT NULL DEFAULT '',
`date` datetime NOT NULL,
`sell` float NOT NULL,
`buy` float NOT NULL,
`spread` float NOT NULL,
PRIMARY KEY (`id`)
)
我编写了一个脚本来打开 CSV 文件,重复行并将它们插入 table。
在脚本具有 运行 之后,我在数据库中查看 table 显示如下。
插入数据的代码看起来像这样。
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
我打印出准确语句之前的值,这些值是正确的。
Array
(
[:currency_pair] => GBP/AUD
[:date] => 2007-11-01 14:06:04.000
[:buy] => 2.273400
[:sell] => 2.272500
[spread] => 0
)
有人知道为什么它不插入我的数据吗?
编辑:
数据库连接代码
define("DSN", "mysql:dbname=rates_test;host=localhost;port=3306");
define("USER", "blah");
define("PASS", "blah");
$pdo = new PDO(DSN, USER, PASS);
编辑 2
我已将插入从函数中取出并添加到我正在执行的 while 循环中,这样您就可以看到发生了什么。
while( false !== ( $data = fgetcsv($file) ) ) {
if(array(null) !== $data){ //skip blank lines
$currencyPair = $data[$column['columns']['instrument']];
$date = $data[$column['columns']['date']];
$sell = $data[$column['columns']['sell']];
$buy = $data[$column['columns']['buy']];
$spread = (float)$buy - (float)$sell;
echo "value => " . $currencyPair . "\r\n";
echo "value => " . $date . "\r\n";
echo "value => " . $sell . "\r\n";
echo "value => " . $buy . "\r\n";
echo "value => " . $spread . "\r\n";
echo var_dump(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, ':spread' => (float)$spread));
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, ':spread' => (float)$spread));
}
}
这是结果
value => GBP/AUD
value => 2007-10-28 21:21:48.000
value => 2.229000
value => 2.229900
value => 0
array(5) {
[":currency_pair"]=> string(15) "GBP/AUD"
[":date"]=> string(47) "2007-10-28 21:21:48.000"
[":buy"]=> float(0)
[":sell"]=> float(0)
[":spread"]=> float(0)
}
编辑 3:
我解决了它,但它有点老套。此外,我无法控制这些 CSV,因此其中可能包含任何不可见的字符。谁能确认这是否足以处理可能存在的任何不可见字符? (我还没有把它放到一个函数中,但我正在为我插入的所有变量做同样的事情)
$buy = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $buy);
$buy = (strpos($buy, ':') && strpos($buy, '-')) ? array_shift(explode('.', $buy)) : $buy;
我不喜欢我对日期所做的事情,但我想不出任何其他方法(由于不可见字符,我无法直接从 CSV 解析合法日期)即使不删除不可见字符我也不能解析日期,因为有些字段超过 6 微秒(PHP 只能处理 6)
我只是在您发布的代码周围封装了一些代码,它运行良好。我什至没有更改 spread
到 :spread
建议的代码。
但是我确实添加了一个 try/catch 块,因为我看到您将模式设置为抛出异常,但是 catch 块从未被激活。
<?php
class tst
{
private $pdo;
private $instrument = 'gbp_aud';
public function __construct()
{
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'test';
/*** mysql password ***/
$password = 'test';
/*** database name ***/
$dbname = 'test';
try {
$this->pdo = new PDO("mysql:host=$hostname;dbname=$dbname;charset=UTF8", $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
}
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
catch(PDOException $e) {
print_r($this->pdo->errorInfo());
exit;
}
}
public function doit($currencyPair, $date, $buy, $sell, $spread){
$this->insert($currencyPair, $date, $buy, $sell, $spread);
}
}
$test = new tst();
$currencyPair = 'GBP/AUD';
$date = '2007-11-01 14:06:04.000';
$buy = 2.273400;
$sell = 2.272500;
$spread = 0;
$test->doit($currencyPair, $date, $buy, $sell, $spread);
$currencyPair = 'GBP/AUD';
$date = '2007-11-02 13:06:04.000';
$buy = 2.276600;
$sell = 2.278800;
$spread = 0.4;
$test->doit($currencyPair, $date, $buy, $sell, $spread);
结果:
我刚读了你的最后一个问题,我不得不假设你在这个过程的数据馈送中仍然有一些奇怪的字符。
对您提供给 ->execute()
语句的数组执行 var_dump()
,这可能会显示比简单的 print_r()
更新
问题是旧文件是用 UNICODE 编码的,而新文件是简单的 ASCII 单字节编码。
我将旧文件脱机转换为 ASCII,这段代码非常愉快地加载了旧文件和新文件
如果旧文件在第 1 行没有列名并且字段顺序略有不同,那么剩下的唯一复杂问题就是 FLOC。请参阅下面的代码。
<?php
class tst
{
private $pdo;
private $instrument = 'gbp_aud';
public function __construct()
{
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'test';
/*** mysql password ***/
$password = 'test';
/*** database name ***/
$dbname = 'test';
try {
$this->pdo = new PDO("mysql:host=$hostname;dbname=$dbname;charset=UTF8", $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
}
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
catch(PDOException $e) {
print_r($this->pdo->errorInfo());
exit;
}
}
public function doit($currencyPair, $date, $buy, $sell, $spread){
$this->insert($currencyPair, $date, $buy, $sell, $spread);
}
}
$test = new tst();
// One old and one new format file
$files = array('GBP_AUD_Week1.csv', 'GBP_AUD_Week5.csv');
foreach ($files as $file) {
$old_format = true;
if (($handle = fopen($file, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
// test old or new file layout
if ( $data[0] == 'lTid' ) {
// New file layout
$old_format = false;
// Skip the title row
continue;
}
if ( $old_format ) {
$test->doit($data[1], $data[2], $data[3], $data[4], $data[4]-$data[3]);
} else {
$test->doit($data[2], $data[3], $data[4], $data[5], $data[5]-$data[4]);
}
}
fclose($handle);
}
}
我有一个table这样的。
CREATE TABLE `GBPAUD` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`currency_pair` varchar(11) NOT NULL DEFAULT '',
`date` datetime NOT NULL,
`sell` float NOT NULL,
`buy` float NOT NULL,
`spread` float NOT NULL,
PRIMARY KEY (`id`)
)
我编写了一个脚本来打开 CSV 文件,重复行并将它们插入 table。
在脚本具有 运行 之后,我在数据库中查看 table 显示如下。
插入数据的代码看起来像这样。
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
我打印出准确语句之前的值,这些值是正确的。
Array
(
[:currency_pair] => GBP/AUD
[:date] => 2007-11-01 14:06:04.000
[:buy] => 2.273400
[:sell] => 2.272500
[spread] => 0
)
有人知道为什么它不插入我的数据吗?
编辑: 数据库连接代码
define("DSN", "mysql:dbname=rates_test;host=localhost;port=3306");
define("USER", "blah");
define("PASS", "blah");
$pdo = new PDO(DSN, USER, PASS);
编辑 2
我已将插入从函数中取出并添加到我正在执行的 while 循环中,这样您就可以看到发生了什么。
while( false !== ( $data = fgetcsv($file) ) ) {
if(array(null) !== $data){ //skip blank lines
$currencyPair = $data[$column['columns']['instrument']];
$date = $data[$column['columns']['date']];
$sell = $data[$column['columns']['sell']];
$buy = $data[$column['columns']['buy']];
$spread = (float)$buy - (float)$sell;
echo "value => " . $currencyPair . "\r\n";
echo "value => " . $date . "\r\n";
echo "value => " . $sell . "\r\n";
echo "value => " . $buy . "\r\n";
echo "value => " . $spread . "\r\n";
echo var_dump(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, ':spread' => (float)$spread));
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, ':spread' => (float)$spread));
}
}
这是结果
value => GBP/AUD
value => 2007-10-28 21:21:48.000
value => 2.229000
value => 2.229900
value => 0
array(5) {
[":currency_pair"]=> string(15) "GBP/AUD"
[":date"]=> string(47) "2007-10-28 21:21:48.000"
[":buy"]=> float(0)
[":sell"]=> float(0)
[":spread"]=> float(0)
}
编辑 3:
我解决了它,但它有点老套。此外,我无法控制这些 CSV,因此其中可能包含任何不可见的字符。谁能确认这是否足以处理可能存在的任何不可见字符? (我还没有把它放到一个函数中,但我正在为我插入的所有变量做同样的事情)
$buy = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $buy);
$buy = (strpos($buy, ':') && strpos($buy, '-')) ? array_shift(explode('.', $buy)) : $buy;
我不喜欢我对日期所做的事情,但我想不出任何其他方法(由于不可见字符,我无法直接从 CSV 解析合法日期)即使不删除不可见字符我也不能解析日期,因为有些字段超过 6 微秒(PHP 只能处理 6)
我只是在您发布的代码周围封装了一些代码,它运行良好。我什至没有更改 spread
到 :spread
建议的代码。
但是我确实添加了一个 try/catch 块,因为我看到您将模式设置为抛出异常,但是 catch 块从未被激活。
<?php
class tst
{
private $pdo;
private $instrument = 'gbp_aud';
public function __construct()
{
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'test';
/*** mysql password ***/
$password = 'test';
/*** database name ***/
$dbname = 'test';
try {
$this->pdo = new PDO("mysql:host=$hostname;dbname=$dbname;charset=UTF8", $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
}
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
catch(PDOException $e) {
print_r($this->pdo->errorInfo());
exit;
}
}
public function doit($currencyPair, $date, $buy, $sell, $spread){
$this->insert($currencyPair, $date, $buy, $sell, $spread);
}
}
$test = new tst();
$currencyPair = 'GBP/AUD';
$date = '2007-11-01 14:06:04.000';
$buy = 2.273400;
$sell = 2.272500;
$spread = 0;
$test->doit($currencyPair, $date, $buy, $sell, $spread);
$currencyPair = 'GBP/AUD';
$date = '2007-11-02 13:06:04.000';
$buy = 2.276600;
$sell = 2.278800;
$spread = 0.4;
$test->doit($currencyPair, $date, $buy, $sell, $spread);
结果:
我刚读了你的最后一个问题,我不得不假设你在这个过程的数据馈送中仍然有一些奇怪的字符。
对您提供给 ->execute()
语句的数组执行 var_dump()
,这可能会显示比简单的 print_r()
更新
问题是旧文件是用 UNICODE 编码的,而新文件是简单的 ASCII 单字节编码。
我将旧文件脱机转换为 ASCII,这段代码非常愉快地加载了旧文件和新文件
如果旧文件在第 1 行没有列名并且字段顺序略有不同,那么剩下的唯一复杂问题就是 FLOC。请参阅下面的代码。
<?php
class tst
{
private $pdo;
private $instrument = 'gbp_aud';
public function __construct()
{
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'test';
/*** mysql password ***/
$password = 'test';
/*** database name ***/
$dbname = 'test';
try {
$this->pdo = new PDO("mysql:host=$hostname;dbname=$dbname;charset=UTF8", $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
}
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
catch(PDOException $e) {
print_r($this->pdo->errorInfo());
exit;
}
}
public function doit($currencyPair, $date, $buy, $sell, $spread){
$this->insert($currencyPair, $date, $buy, $sell, $spread);
}
}
$test = new tst();
// One old and one new format file
$files = array('GBP_AUD_Week1.csv', 'GBP_AUD_Week5.csv');
foreach ($files as $file) {
$old_format = true;
if (($handle = fopen($file, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
// test old or new file layout
if ( $data[0] == 'lTid' ) {
// New file layout
$old_format = false;
// Skip the title row
continue;
}
if ( $old_format ) {
$test->doit($data[1], $data[2], $data[3], $data[4], $data[4]-$data[3]);
} else {
$test->doit($data[2], $data[3], $data[4], $data[5], $data[5]-$data[4]);
}
}
fclose($handle);
}
}