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