MySQL PDO вставляет неправильные значения (источник данных CSV)

У меня есть такой стол.

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, разбирает строки и вставляет их в таблицу.

После запуска сценария и просмотра базы данных таблица выглядит следующим образом.

Код, который вставляет данные, выглядит так.

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)

1 ответ

Решение

Я просто обернул немного кода вокруг вашего размещенного кода, и он отлично работает. Я даже не изменил код для 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);

Результаты:

Я только что прочитал ваш последний вопрос и должен предположить, что в вашем фиде данных для этого процесса все еще есть какие-то странные символы.

Сделать var_dump() массива, который вы передаете в ->execute() утверждение, которое, скорее всего, покажет больше, чем просто 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);
    }
}
Другие вопросы по тегам