2016-06-19 1 views
0

Я пытаюсь вставить значения в таблицу MySQL по строке, которая считывается из файла в Perl. Если какое-либо поле пусто в CSV-файле, будут две последовательные запятые. Например.Вставка Mysql с значениями, содержащими двойные запятые

Firstname,Lastname,Code,Phone,Email 
fname1,lname1,123,34543,[email protected] 
fname2,lname2,344,45645,[email protected] 
fname3,lname3,454,,[email protected] 

В третьей строке нет номера телефона. Итак, есть две последовательные запятые. Когда мы пытаемся вставить в mysql следующую команду, она терпит неудачу.

insert into table1 (Firstname,Lastname,Code,Phone,Email) values (fname3,lname3,454,,[email protected]) 

Как это сделать?

Я использовал следующий код, чтобы сделать это.

open CSV, $file or die $!; 
my @csv_content = <CSV>; 
close CSV; 
my $fields = "Firstname,Lastname,Code,Phone,Email"; 
my $table = "table1"; 

my $csv = Text::CSV->new(); 
foreach(@csv_content){ 
    if($csv->parse($_)){ 
     my @values = $csv->fields(); 
     my $status = $csv->combine(@values); 
     my $line = $csv->string(); 

     $statement = "INSERT INTO $table($fields) VALUES($line);"; 
     $sth = $dbh->prepare($statement); 
     $sth->execute() or die "$! $DBI::errstr"; 
    } 
} 
+0

MySQL может загружать CSV непосредственно с синтаксисом LOAD DATA INFILE. Я бы рекомендовал использовать это, если вам не нужно предварительно обработать ваш CSV. – ThisSuitIsBlackNot

+0

Мне нужно предварительно обработать csv, так что это не вариант. – Prabhu

+0

1/Использовать точки привязки в вашем SQL. 2/'prepare()' SQL за пределами цикла (второй пункт не решает вашу проблему - это повышает эффективность вашего кода). –

ответ

0

Лучший способ загрузить такие данные могли бы использовать команду MySQL LOAD DATA INFILE:

LOAD DATA INFILE "yourfilename" INTO TABLE "yourtablename" COLUMNS TERMINATED BY ","; 

Таким образом Избегая ,, вопрос полностью

+0

Мне нужно сделать это с perl, делать это напрямую не вариант. – Prabhu

+1

Затем вам нужно предварительно обработать строку в perl в разные столбцы: Разделить на массив, а затем присвоить значения массива значениям в инструкции insert. Таким образом, вы избегаете проблемы с пустым столбцом, поскольку вместо этого вы просто назначаете пустое значение столбцу. –

1

Я мог бы написать это следующим образом. Я включил пустые поля в ваш файл csv. Я использовал 5 заполнителей, «?» И не подготовился внутри цикла. Просто выполните в цикле.

my $csv = Text::CSV->new ({ binary => 1, eol => "\n" }); 

my $file = 'blahblah'; 
open my $fh, $file or die "$file open failed: $!"; 

my $dbh = DBI->connect("dbi:SQLite:dbname=pedro.lite","","", 
    {PrintError => 1, AutoCommit => 0}) or die "Can't connect"; 


my $sth = $dbh->prepare(q{INSERT INTO table1 VALUES(?,?,?,?,?)}) 
    or die $dbh->errstr; 

<$fh>; # throw away header - first line 
while (my $row = $csv->getline ($fh)) { 
    $sth->execute(@$row) or die $sth->errstr; 
} 

$dbh->commit or die $dbh->errstr; 
close $fh or die "$file close failed: $!"; 
$sth->finish; 

Если в начале файла нет заголовка, не используйте эту строку кода.

Обновление: Вот фактическая программа, которую я использовал для создания базы данных (с использованием SQLite), и она отлично работала даже с двойными запятыми (пустое поле).

#!/usr/bin/perl 
use strict; 
use warnings; 
use Text::CSV_XS; 
use DBI; 

my $csv = Text::CSV_XS->new ({ binary => 1, eol => "\n" }); 

my $file = 'j1.csv'; 
open my $fh, $file or die "$file open failed: $!"; 

my $dbh = DBI->connect("dbi:SQLite:dbname=pedro.lite","","", 
    {RaiseError => 1, PrintError => 0, AutoCommit => 0}) or die "Can't connect"; 

$dbh->do('DROP TABLE IF EXISTS table1'); 

$dbh->do(<<EOF); 
CREATE TABLE table1 (
    Firstname TEXT, 
    Lastname TEXT, 
    Code INTEGER, 
    Phone INTEGER, 
    Email TEXT) 
EOF 

my $sth = $dbh->prepare(q{INSERT INTO table1 VALUES(?,?,?,?,?)}); 

<$fh>; # throw away header - first line 
while (my $row = $csv->getline ($fh)) { 
    $sth->execute(@$row); 
} 
$sth->finish; 
$dbh->commit; 
$dbh->disconnect; 

close $fh or die "$file close failed: $!"; 

И вот результат запроса таблицы1.

sqlite> .mode column 
sqlite> .width 10 10 10 10 14 
sqlite> .headers on 
sqlite> select * from table1; 
Firstname Lastname Code  Phone  Email 
---------- ---------- ---------- ---------- -------------- 
fname1  lname1  123   34543  [email protected] 
fname2  lname2  344   45645  [email protected] 
fname3  lname3  454      [email protected] 
sqlite> 

Как вы можете видеть, это правильно показывает, что для fname3 нет номера телефона. Я использовал ваши данные так, как они появляются в вашем сообщении, чтобы ввести INSERT в таблицу1.

0

Я решил это с помощью другого подхода: сначала вложил каждое поле в перевернутые кавычки, даже пустые. Данные выглядели следующим образом после включения в котировки:

'fname1','lname1','123','34543','[email protected]' 
'fname2','lname2','344','45645','[email protected]' 
'fname3','lname3','454','','[email protected]' 

Это было сделано с использованием языка программирования. После этого не возникло проблем с вставкой данных.

1

Компьютер не понимает, что вы пытаетесь вставить, потому что он не может понять, что между двумя запятыми существует пустое значение. Если вы делаете это с perl, попробуйте приложить каждое значение в пределах quotes, даже пустые. Для примера в вашей линии передачи данных 3 изменения

fname3,lname3,454,,[email protected] 

к

'fname3','lname3','454','','[email protected]' 

Это легко достичь в любом языке программирования. Теперь попробуйте вставить. Он не будет генерировать исключение, поскольку часть между ними будет пустой строкой.

1

Прилагайте каждое значение с помощью инвертированной запятой, например, «fname3», «lname3», «454», «», «[email protected]». Обратите внимание на пустые перевернутые запятые между запятыми. Это сделает трюк