Zum Inhalt springen

Perl - DBI Problem


Empfohlene Beiträge

Moin zusammen.

Folgende Aufgabenstellung:

Nimm eine CSV Datei der Form:

"wert1;wert2;[..];wert10"

und packe diese per DBI und DBD::ODBC in eine bestehende Access Tabelle.

Mein Ansatz ist bis jetzt folgender:


use DBI;


# Declare variables

my $dsn = Access; #DSN im ODBC

my $db = 'c:/repo'; #Ort der CSV datei

my $separator='\\;' ; #Spaltentrenner ";"

my $filename = 'mappe1.csv';



# Makes a Datebase Handler

my $dbh = DBI->connect("DBI:ODBC:$dsn") or die DBI::errstr; #ODBC Access


my $dbh2 = DBI->connect("DBI:CSV:f_dir=$db;csv_sep_char=$separator") or die "öffnen: DBI::errstr"; #CSV Datei c:\repo\mappe1.csv


$dbh2->{csv_tables}->{temps} =

 {'file' => $filename};


my $sth2 = $dbh2->prepare("select * from temps") or die "1: $dbh2->errstr";


$sth2->execute() or die "2: $dbh2->errstr";


while (my @row = $sth2->fetchrow_array()) {

  my $sth = $dbh->do("insert into temps values (@row)") or die "3: $dbh2->errstr";

}


$dbh->disconnect();

$dbh2->disconnect();

Als Fehlermeldung erhalte ich:

DBD::ODBC::db do failed: [Microsoft][ODBC Microsoft Access Driver] Syntaxfehler

(fehlender Operator) in Abfrageausdruck '15.May.2003;10:00;23'. (SQL-42000)(DBD:

Execute immediate failed err=-1) at c:\eigene dateien\perl\progs\odbc2.pl line

23.

3: DBI::db=HASH(0xb04fe54)->errstr at c:\eigene dateien\perl\progs\odbc2.pl line

23.

Und irgendwo hab ich da jetzt nen kräftigen Block im Kopp wo ich net weiterkomm...

Würde mich sehr freuen, wenn mir da wer nen Tip geben könnte.

Alternativ nehme ich auch gerne Lösungsvorschläge, wie es komplett anders gehen könnte ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Lasse dir mal bitte die generierte SQL-Anweisung ausgeben. Denn da liegt der Hase begraben.

Wieso gibts du bei dem Spaltentrenner "\\;" an?

Ok die werte sind durch semikolon getrennt, nicht durch komma ... na gut, dass wird na klar schwer das als getrennte werte auszugeben :D

wie trenne ich denn jetzt mal am besten die werte mit komma?

bin relativer perl newbie, deswegen grad etwas ratlaos...

Spaltentrenner "\\;" da ein einfach ";" sonst als trenner der argumente für dbd:csv gewertet werden würde. deshalb hab ich das mit dem "\\" entwertet, wie das vorgeschlagen wurde in der dbd:csv hilfe ... sollte das nicht richtig sein ?

Link zu diesem Kommentar
Auf anderen Seiten teilen


my @liste;
my @eintrag;
my $file = "dateiname";

open(CVSFILE,$file);
while (<CVSFILE>) {
@eintrag = split(/;/,$_);
# hier den Eintrag in die Datenbank vornehmen
}
close(CVSFILE);
[/PHP]

Ich hoffe mal es klappt. Habe ewig nichts mehr mit Perl zu tun gehabt.

[OT]

Wieso nimmt man eigentlich unter Windows Perl um auf eine Access-DB zuzugreifen? :confused:

[/OT]

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Enrico,

ok die CSV Datei als Datei und nicht als SQL DB zu öffnen ist natürlich auch ein gangbarer weg ;)

Ich habe jetzt folgendes Perl Script und nun das Problem, dass die Datenbank meckert, dass sie mehrere Argumente erwartet aber nur eins bekommt:


use DBI;

use diagnostics;


# Declare variables

my $dsn = Access; #DSN im ODBC

my @liste; 

my @eintrag; 


# Makes a Datebase Handler

my $dbh = DBI->connect("DBI:ODBC:$dsn") or die DBI::errstr; #ODBC Access


open(CVSFILE,"c:\\repo\\mappe1.csv") or die "Cannot open source file"; 

while (<CVSFILE>) 

{ 

  @eintrag = split(/;/,$_); 

  my $sth = $dbh->prepare("insert into temps values (@eintrag)") or die  $dbh->errstr;

  $sth->execute();

} 


$dbh->disconnect();

close(CVSFILE);

Ich vermute, dass die Auflösung des SQL Statements nicht so funzt wie ich mir das denke.... @eintrag sollte an dieser Stelle zu einem String der form "Wert1,Wert2,Wert3,[..]" interpoliert werden, was so leider nicht geschieht .... Könnte ich nicht theoretisch nach dem Split folgende Zuweisungen treffen:

#Hier nur die while Schleife nach dem Öffnen der Datei

while (<CVSFILE>) 

{ 

  @eintrag = split(/;/,$_); 

  my $wert1 = $eintrag[0];

  my $wert2 = $eintrag[1];

  my $statement = "$wert1 . , . $wert2"


  my $sth = $dbh->prepare("insert into temps values ($statement)") or die  $dbh->errstr;

  $sth->execute();

} 

In dem Codeschnipsel will allerdings auch irgendwas noch nicht so wie ich das will ...

[OT]

[OT]

Wieso nimmt man eigentlich unter Windows Perl um auf eine Access-DB zuzugreifen? :confused:

[/OT]

Ich sag nur gewachsene Strukturen .. die Access DB existiert schon länger und soll nicht ersetzt werden. Dennoch soll das ganze ins Web bzw. vorab mit CSV Dateien gefüttert werden... :rolleyes:

[/OT]

Link zu diesem Kommentar
Auf anderen Seiten teilen

Arghs .. nu hab ich mir da aber nen anderes Problem eingehandelt:

Die zusammengebastelte SQL Anweisung sieht dann so aus:


$sql = "insert into temps values ('String','String2','x,y',[...])

'x,y' geht natürlich nicht, weil das insert into Statement bei Zahlen die in eine DB geschubst werden Dezimalzahlen in der Form "x.y" also mit nem Punkt als dezimalzeichen und ohne Anführungszeichen erwartet. Nu müsste ich entweder die Schleife ändern oder hinterher die fertige SQL Anweisung.... was ist leichter und wie gehts? Mann mann und das am Freitag .. da kann ich doch eh nicht denken ... Der Vollständigkeit halber: CSV Datei beinhaltet folgendes Format:

"Datum;Uhrzeit;Dezimal1;Dezimal2;Dezimal3;Dezimal4;Dezimal5;Dezimal6;Dezimal7;Dezimal8"

Hierbei sind alle " und ; genau wie oben geschrieben in der CSV Datei enthalten. Die Tabelle in die hinein geschubst wird erwartet - Datum als String (also in ' ') - Uhrzeit als Stzring (also in ' ') - Dezimal[1-8] als Double (also mit . und ohne ' ') Und hier das Script wie es derzeit ausschaut:

use DBI;

use diagnostics;


# Declare variables

my $dsn = Access; #DSN im ODBC

my @liste; 

my @eintrag; 

my $value; 

my $sql;

my $sql2;


# Makes a Datebase Handler

my $dbh = DBI->connect("DBI:ODBC:$dsn") or die DBI::errstr; #ODBC Access



open(CVSFILE,"c:\\repo\\mappe1.csv") or die "Cannot open source file"; 


while(<CVSFILE>)

{

	@eintrag = split(/;/,$_); 

	my $value; 

	my $sql = ""; 

	while (($value = shift @eintrag)) { 

		$sql .= "'$value'"; 

		if ($eintrag > 0) { 

		$sql .= ", "; 

             	} 

            } 


            $sql .= "insert into temps values (" .$sql . ")";

            print "\nSQL: $sql \n";

            my $sth = $dbh->do($sql) or die  $dbh->errstr; 

}


$dbh->disconnect();

close(CVSFILE);

Weiss noch wer Rat ?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Machen wir das Ganze ebend etwas komplizierter :D



while(<CVSFILE>) {
@eintrag = split(/;/,$_);
my $value;
my $sql = "";
my $pos = 0;
while (($value = shift @eintrag)) {
switch (++$pos) {
case 1 {$sql .= "'$value'";}
case 2 {$sql .= "'$value'";}
else {$value =~ s/,/./;
$sql .= $value}
}

if ($eintrag > 0) {
$sql .= ", ";
}
}

$sql = "insert into temps values (" .$sql . ")";
print "\nSQL: $sql \n";
my $sth = $dbh->do($sql) or die $dbh->errstr;
}
[/PHP]

Link zu diesem Kommentar
Auf anderen Seiten teilen

Will leider nicht .. bin auch der meinung, dass perl "case" nicht kennt, oder?


use DBI;



# Declare variables

my $dsn = Access; #DSN im ODBC

my @liste; 

my @eintrag; 

my $wert; 

my $sql;

my $sql2;


# Makes a Datebase Handler

my $dbh = DBI->connect("DBI:ODBC:$dsn") or die DBI::errstr; #ODBC Access



open(CVSFILE,"c:\\repo\\mappe1.csv") or die "Cannot open source file"; 


while(<CVSFILE>) { 

  @eintrag = split(/;/,$_); 

  my $wert; 

  my $sql = ""; 

  my $pos = 0; 

  while (($wert = shift @eintrag)) { 

    switch (++$pos) { 

      case 1  {$sql .= "'$wert'";} 

      case 2  {$sql .= "'$wert'";} 

      else    {$wert =~ s/,/./;$sql .= $wert;} 

      } 


    if ($eintrag > 0) { 

      $sql .= ", "; 

    } 

  } 


  $sql = "insert into temps values (" .$sql . ")"; 

  print "\nSQL: $sql \n"; 

  sleep(3);

  #my $sth = $dbh->do($sql) or die  $dbh->errstr; 

} 


$dbh->disconnect();

close(CVSFILE);

Fehlermeldung:

C:\Perl\bin>perl "c:\eigene dateien\perl\progs\odbc2.pl"

Number found where operator expected at c:\eigene dateien\perl\progs\odbc2.pl line 25, near "case 1"

(Do you need to predeclare case?)

Number found where operator expected at c:\eigene dateien\perl\progs\odbc2.pl line 26, near "case 2"

(Do you need to predeclare case?)

syntax error at c:\eigene dateien\perl\progs\odbc2.pl line 24, near ") {"

syntax error at c:\eigene dateien\perl\progs\odbc2.pl line 26, near "case 2"

syntax error at c:\eigene dateien\perl\progs\odbc2.pl line 27, near "else"

syntax error at c:\eigene dateien\perl\progs\odbc2.pl line 27, near ";}"

Execution of c:\eigene dateien\perl\progs\odbc2.pl aborted due to compilation errors.

Sorry, aber ich hab echt n Knoten im Kopf im Moment... aber vielen Dank für deine Hilfe!

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hab sjetzt entwas anders gelöst .. ohne switch ...

Alelrdings hab ich nun 1 neues und ein alter -bishe rnicht entdecktes- problem:

1. An der eingelesenen Zeile aus der CSV Datei hängt noch ein Newline (\n)dran, dass noch raus muss

2. Auch zahlen haben nun ihre ' ' ....


use DBI;


# Declare variables

my $dsn = Access; #DSN im ODBC

my @eintrag; 

my $wert; 

my $sql;


# Makes a Datebase Handler

my $dbh = DBI->connect("DBI:ODBC:$dsn") or die DBI::errstr; #ODBC Access


open(CVSFILE,"c:\\repo\\mappe1.csv") or die "Cannot open source file"; 


while(<CVSFILE>) { 

  @eintrag = split(/;/,$_); 

  #hier müsste vom letzten element des arrays (letzter wert) das newline \n entfernt werden mit chop...

  #wie kriege ich raus welches das letzte element ist?


  $sql = ""; 

  while (($wert = shift @eintrag)) { 

     $wert =~ s/,/./; 

     $sql .= "'". $wert . "',";  #hiernach haben leider auch zahlen ein '' ..... wie vermeiden?

     } 


  chop($sql);  #Entfernen des letzten ,

  $sql = "insert into temps werts (" .$sql . ")"; 

  print "\nSQL: $sql \n"; 

  my $sth = $dbh->do($sql) or die  $dbh->errstr; 

} 


$dbh->disconnect();

close(CVSFILE);

Link zu diesem Kommentar
Auf anderen Seiten teilen

Verdammt noch mal! Scheint es erst seit Perl 5.8 zu geben. Hatte das Beispiel genutzt: http://www.perldoc.com/perl5.8.0/lib/Switch.html.

Muss man eben etwas umschreiben:


while (($wert = shift @eintrag)) {
$pos++;
if ($pos == 1) { # case 1
$sql .= "'$wert'";
}
else if ($pos == 2) { # case 2
$sql .= "'$wert'";
}
else {
$wert =~ s/,/./;
$sql .= $wert;
}
# ... weiter wie gehabt
[/PHP]

Link zu diesem Kommentar
Auf anderen Seiten teilen

So mit ein paar Änderungen wegen Syntaxfehlern habe ich folgenden (funktionierenden) code:


use DBI;

use diagnostics;


# Declare variables

my $dsn = Access; #DSN im ODBC

my @liste; 

my @eintrag; 

my $wert; 

my $sql;

my $sql2;


# Makes a Datebase Handler

my $dbh = DBI->connect("DBI:ODBC:$dsn") or die DBI::errstr; #ODBC Access



open(CVSFILE,"c:\\repo\\mappe1.csv") or die "Cannot open source file"; 


while(<CVSFILE>) { 

  @eintrag = split(/;/,$_); 

  chop($eintrag[$#eintrag]);  #Abschliessende Newline am letzten Array element entfernen


  $sql = ""; 

  my $pos = 0; 




   while (($wert = shift @eintrag)) { 

     $pos++; 


     #Je nach pos (=index des arrays +1) entscheiden ob als string oder zahl geschrieben werden soll    

     $sql .= "'$wert'," if ($pos==1); #Pos 1 als String

     $sql .= "'$wert'," if ($pos==2); #Pos 2 als String

     $wert =~ s/,/./   if ($pos != 1 && $pos != 2); #Wenn nicht Pos 1 oder 2 komma durch punkt ersetzen

     $sql .= "$wert,"   if ($pos != 1 && $pos != 2); #Alle anderen Positionen als Zahl ohne '' 



     print "\n Werte: $sql";



  } 


  chop($sql);

  $sql = "insert into temps values (" .$sql . ")"; 

  print "\nSQL: $sql \n"; 

  my $sth = $dbh->do($sql) or die  $dbh->errstr; 

} 


$dbh->disconnect();

close(CVSFILE);

Es folgen dann jetzt die Erweiterungen ...

Beispielsweise muss ich noch dafür sorgen, dass die erste Zeile der CSV Datei, die die Spaltennamen erhält nicht genutzt wird, da es sonst zu ODBC Fehlern kommt (Datentypen passen nicht...) aber das soltle das kleinere Prob werden.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es folgen dann jetzt die Erweiterungen ...

Beispielsweise muss ich noch dafür sorgen, dass die erste Zeile der CSV Datei, die die Spaltennamen erhält nicht genutzt wird, da es sonst zu ODBC Fehlern kommt (Datentypen passen nicht...) aber das soltle das kleinere Prob werden.

Das möchte ich aber auch meinen. Wenn es trotzdem nicht klappen will:

Hier werden Sie geholfen!

:bimei

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das möchte ich aber auch meinen. Wenn es trotzdem nicht klappen will:

Hier werden Sie geholfen!

:bimei

Joah hat alles geklappt. Nun hab ich eine Vorlage für die anderen knapp 50 csv Dateien die importiert werden sollen (und na klar alle ein etwas anderes Format haben :rolleyes:) naja wird scho schief gehen.

Danke nochmal

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...