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);
    }
}