Spaltennamen einer SQL-Abfrage auslesen
bert
- perl
Ich habe eine MySQL-Datenbank, in der verschiedene Auswertungen gebraucht werden. Die SQL-Statements können dabei konfiguriert werden und völlig verschiedene Spalten und Daten liefern. Ich generiere jeweils XLS-Dateien daraus. Hier ein Codeschnipsel:
$QueryObject = $db->prepare($sql);
$QueryObject->execute();
while ( $zref = $QueryObject->fetchrow_hashref()) {
if ($Counter == 0) {
#Überschriften auslesen
@KeyList = keys % {$zref};
foreach (@KeyList) {
#Spaltennamen in XLS-Datei schreiben
$Worksheet->write($RowNum, $ColNum, $_ , $FormatHeadline);
$ColNum++;
}
$ColNum = 0;
$RowNum++;
}
#Daten
@KeyList = keys % {$zref};
foreach (@KeyList) {
#Spaltenwerte exportieren
$Worksheet->write($RowNum, $ColNum, $$zref{"$_"} ,$FormatContent);
$ColNum++;
}
$Counter++;
$ColNum = 0;
$RowNum++;
}
Dem Script soll es egal sein, welche Spalten über $sql abgefragt werden. Die Spaltennamen brauche ich aber als Überschrift in der XLS-Datei.
Ich verwende fetchrow_hashref, damit ich die Spaltennnamen der Anfrage kriege und diese über keys %{zref} auslesen kann.
Das funzt eigentlich ganz gut, jedoch kommen die Spalten in zufälliger Reihenfolge an, und nicht in der, die im SQL festgelegt wurde. Vermutlich liegt das an der internen Verwaltung des Hashes.
Wie kriege ich die Spaltennamen einer Abfrage in die richtige Reihenfolge?
Bert
hi,
Wie kriege ich die Spaltennamen einer Abfrage in die richtige Reihenfolge?
$ary_ref = $dbh->selectrow_arrayref("describe table");
Im array dann auf [0] gucken.
Viele Grüße,
Hotte
hi,
Wie kriege ich die Spaltennamen einer Abfrage in die richtige Reihenfolge?
$ary_ref = $dbh->selectrow_arrayref("describe table");
Tschuldige, das war Käse. Hier stehts richtig:
my $ref = $dbh->selectall_arrayref("describe table");
my @cols = map{$_->[0]}@$ref; # array mit Spaltennamen
print join("\n", @cols), "\n"; # zur Kontrolle
-- Hotte
Hallo Hotte,
danke für die schnelle Antwort. Leider ist das noch nicht ganz das, was ich suche. Ich frage nicht einfach eine Tabelle ab, sondern ich habe ein SELECT-Statement, das dynamisch konfiguriert wird. Ich kenne es also nicht vorher, es kann aber recht lang sein, hier mal ein "kurzes" als Beispiel:
select Date_Format(FROM_UNIXTIME(v.Zeitstempel) , "%d.%m.%Y") Datum, l.Name Filiale,
sum(if(a.name='Jacke', p.Anzahl , 0)) 'Anzahl Jacken',
sum(if(a.name='Hose', p.Anzahl , 0)) 'Anzahl Hosen',
sum(if(a.name='Schuh', p.Anzahl , 0)) 'Anzahl Schuhe'
from verkauf v LEFT JOIN verkauf_positionen p using (VerkaufsID)
left join map_locations l on (l.LocationID=v.locationID)
left join artikel a on (p.ArtikelID=a.ArtikelID)
where v.ENTRYTYPE = 'ACTIVE' and p.EntryType = 'ACTIVE' and l.EntryType = 'ACTIVE'
and (v.Status = 200 or v.Status = 300)
and (FROM_UNIXTIME(v.Zeitstempel) >= STR_TO_DATE('01.12.2007',"%d.%m.%Y")) and (FROM_UNIXTIME(v.Zeitstempel) < STR_TO_DATE('04.03.2008',"%d.%m.%Y"))
group by v.VerkaufsID
Meistens sind die Statements noch lustig verschachtelt usw. Jedenfalls ergibt dieses SELECT was in der Form (Datum, Filiale, Jacken, Hosen, Schuhe).
Mit meinem Script krieg ich in meiner Datei sowas angezeigt (Jacken, Datum, Schuhe, Filiale, Hosen), also ziemlich durcheinander.
my $ref = $dbh->selectall_arrayref("describe table");
my @cols = map{$_->[0]}@$ref; # array mit Spaltennamen
Im Prinzip kann ich ein DESCRIBE auch auf ein SELECT anwenden, das ergibt aber etwas anderes.
Noch andere Ideen?
Ich frage nicht einfach eine Tabelle ab, sondern ich habe ein SELECT-Statement, das dynamisch konfiguriert wird.
Was bitteschön ist "dynamisch konfiguriert"?
Ich kenne es also nicht vorher, es kann aber recht lang sein
Aber an irgendeiner Stelle der "dynamischen Konfiguration" wirst Du doch die Feldliste haben, oder? Daraus kannst Du dann die Spaltenüberschriften bilden und brauchst dann später nur noch das Ergebnis von fetchrow_arrayref nacheinander abzuarbeiten.
Siechfred
Eigentlich sollte das eine ganz einfache Frage sein. In meiner Anwendung gibt es ein gutes Dutzend Auswertungen und vermutlich werden es bald noch mehr sein. Um den Programmcode nicht ändern zu müssen, habe ich für jede benötigte Auswertung eine sql-Datei in ein Verzeichnis gelegt. Der Nutzer kann dann eine aus dieser Liste auswählen und kriegt das Ergebnis als XLS-Datei.
Im einfachsten Fall steht in einer solchen Datei: "SELECT * FROM TableXY" oder "SELECT a,b FROM viewXY"
Für eine weitere Auswertung brauche ich (oder ein cleverer Nutzer) nur ein SQL-Statement zu formulieren und das als Datei abzulegen.
Aber an irgendeiner Stelle der "dynamischen Konfiguration" wirst Du doch die Feldliste haben, oder? Daraus kannst Du dann die Spaltenüberschriften bilden und brauchst dann später nur noch das Ergebnis von fetchrow_arrayref nacheinander abzuarbeiten.
Eigentlich ist über die Formulierung des SELECT ja alles über die Reihenfolge der Felder gesagt. Klar, ich kann in die Dateien zusätzlich noch eine Feldreihenfolge hinterlegen, z.B.:
REIHENFOLGE:Feld1,Feld2,...
SELECT * FROM TableXY
Das ist doch aber doppelt gemoppelt! In anderen Programmiersprachen kenne ich das Problem nicht. Dort setze ich per ODBC oder sonstwie eine Abfrage ab und kriege die Werte und deren Bezeichnungen und deren Reihenfolge ganz einfach zurück.
Ich bin recht neu in der PERL-Programmierung und dachte, hier müsste sich doch jemand mit sowas auskennen.
Hat denn wirklich noch keiner eine allgemeingültige Routine zum Export aus MySQL mit Perl geschrieben?
Im einfachsten Fall steht in einer solchen Datei: "SELECT * FROM TableXY" oder "SELECT a,b FROM viewXY"
Also wird da nix dynamisch zusammengesetzt, sondern das Statement wird aus einer Textdatei ausgelesen. Damit kannst Du aus dem Statement doch ganz einfach die Feldliste extrahieren, entweder mit Regulären Ausdrücken oder indem Du das NAME-Attribut Deines Statement-Handles abfragst (siehe Beispiel in der verlinkten Doku).
Hat denn wirklich noch keiner eine allgemeingültige Routine zum Export aus MySQL mit Perl geschrieben?
Das DBI-Modul bietet eigentlich alles, was man braucht. Btw, zum dynamischen Generieren von SQL-Abfragen schau Dir mal SQL::Abstract an. Stell' Dir mal vor, einer Deiner Nutzer verhaspelt sich beim Statement - und schon fliegt Dir Dein Programm um die Ohren.
Siechfred
Danke Alexander und Siechfred,
mit NAME geht es super. Hab mir doch gedacht, dass es was in der Art geben muss.
Bert
#################################################################
while (@row = $sth->fetchrow_array) {
if ($Counter == 0) {
#Überschrift
foreach (@{$sth->{NAME}}) {
$Worksheet->write($RowNum, $ColNum, $_ , $FormatHeadline);
$ColNum++;
}
$ColNum = 0;$RowNum++;
}
#Daten
foreach (@row) {
$Worksheet->write($RowNum, $ColNum, $_ , $FormatContent);
$ColNum++;
}
$Counter++;
$ColNum = 0;$RowNum++;
}
Moin Moin!
http://search.cpan.org/~timb/DBI-1.602/DBI.pm#NAME_(array-ref,_read-only)
Alexander