Newsgroup: it.comp.lang.perl
Titolo: mysql ed hash ordinati

Ciao a tutti,
mi chiedo se qualcuno possa darmi un'idea per risolvere il seguente
problemino..
ho la necessità di recuperare dati da una serie di query sql e di
stamparne ( visualizzarne/generarne csv/xls/pdf etc etc) i risultati.
L'idea è quella di leggere tutti i risultati della query con
fetchall_arrayref({}) che mi restituisce un riferimento ad un array
dove gli elementi (corrispondenti alle righe del risultato della query
sql) sono a loro volta dei puntaturi ad un hash dove le coppie chiave/
valore sono i "nomi dei campi" => "valore"
Ora questo risultato lo passo alla funzione che genera l'output dei
risultati, la quale prende le chiavi degli hash per generare la "prima
riga di intestazione" dei valori e di seguito aggiunge tutti i valori
riga per riga.
Il problema è che l'hash, non mi garantisce l'ordine di uscita dei
dati rispetto a quello di assegnamento.. quindi l'output è corretto,
ma con le colonne "mescolate" es:
Query: SELECT nome,cognome,indirizzo .............
Output:
Cognome | Indirizzo | Nome
Dei Tali | Viale della libertà | Tal
Ho visto che esistono dei moduli che mi permettono di dichiarare hash
"ordinati", ma non credo di poterli usare in quanto i risultati sono
già mescolati in fase di uscita della funzione fetchall_arrayref..
Qualcuno sa se è possibile forzare diversamente l'ordinamento? Oppure
darmi una dritta su come posso creare un'alternativa?
Grazie in anticipo
Mario

 darmi una dritta su come posso creare un'alternativa?
La lista dei nomi dei campi richiesti nella select (ovvero tutti i campi 
della tabella, nel caso di SELECT *) esattamente nell'ordine in cui 
compaiono nella clausola select (ovvero nell'ordine in cui sono stati 
definiti nella tabella del db, nel caso di SELECT *), la ottieni con:
my @campi = @{ $sth->{NAME} };
dove $sth è l'oggetto /statement handle/ DBI.
(Meglio ancora usare NAME_lc o NAME_uc).
A questo punto è sufficiente scandire, per ogni $riga restituita da 
fetchall_arrayref(), i nomi campo presenti nell'array @campi e accedere 
al valore corrispondente mediante $riga->{ $campo }.
Esempio:
my $sth = $dbh->prepare( q[SELECT * FROM mia_tabella] );
$sth->execute;
my @campi = @{ $sth->{NAME} }; # Per certi driver *dopo* execute!
my $righe = $sth->fetchall_arrayref( {} );
print join("\t", @campi), "\n"; # Stampa le intestazioni delle colonne.
print '===================================================', "\n";
foreach my $riga ( @{ $righe } ) {
     foreach my $campo ( @campi ) {
         print $riga->{ $campo }, "\t"
     }
     print "\n"
}
# Attento ai campi con valore undef che possono generare un warning.
Questa è la soluzione più generale, ma in pratica le cose sono ancora 
più semplici, dal momento che quasi certamente conosci la lista dei 
campi (compreso l'ordine), visto che l'adoperi nella clausola SELECT e/o 
per le intestazioni delle colonne in output.
Quindi l'array @campi puoi quasi sempre inizializzarlo direttamente da 
una lista nota, senza neanche usare $sth->{NAME}:
my @campi = qw(nome cognome indirizzo); # Li conosci!
L'unico (inusuale) caso che mi viene in mente in cui non conosci a 
priori la lista dei campi, è proprio quello di una SELECT * su una 
tabella di struttura incognita.
Ciao,
Emanuele.

 }
Per completezza: se devi fare solo una stampa tabellare tipo questa, 
allora ti conviene adoperare il più efficiente (sia come tempo che come 
spazio) fetchall_arrayref() in luogo di fetchall_arrayref({}) (la 
sequenza dei valori dei campi in $riga, che in questo caso sarebbe un 
array reference, coincide con la sequenza dei nomi in @campi).
Ciao,
Emanuele.

On 13 Apr, 08:09, Emanuele Zeppieri

Ciao Emanuele,
ok.. mi hai risolto un problema per la seconda volta... e considerando
che ho postato solo 2 volte, vuol dire che hai risolto il 100% dei
miei problemi,
quindi.. GRAZIE !!
Ad ogni modo il mio problema nasce dal fatto che ho voluto scrivere
una funzione di produzione dell'output indipendente dall'input,
quindi le query possono essere ( sono ) sempre diverse. Diciamo quindi
che a priori NON conosco l'elenco e la sequenza dei campi
In compenso mi hai illuminato con questa:
my @campi = @{ $sth->{NAME} };
Non mi piace molto, ma a questo punto posso passare alla funzione di
output DUE riferimenti:
- Il riferimento ai dati da stmpare ( quindi come giustamente dici la
fetchall_arrayref() )
- Il riferimento delle intestazioni
- OPPURE -
( scrivendo mi è venuta in mente anche questa soluzione )
produrre un "hash ordinato" mediante il modulo Tie::IxHash; ( ??? )
riempirlo con l'ordine definito da @{ $sth->{NAME} }
e poi darlo in pasto AS IS alla funzione di output senza toccare
null'altro...
Grazie intanto
Mario

 ok.. mi hai risolto un problema per la seconda volta...
Oddio, me n'ero completamente dimenticato.
Allora scusa per la risposta troppo prolissa e didascalica: mi fossi 
ricordato dell'argomento dell'altra volta, tutt'altro che banale, avrei 
contenuto certi eccessi di pedanteria ;-)
OK, sono quasi le 15.00, andiamo a vedere di che morte ci tocca 
morire... :-(
Ciao!