IO E I COLLEGHI DI UFFICIO
Writing by corra on Wednesday, 31 of May , 2006 at 6:17 pm
… bella gente!

Corra

Jamo

Ema

GV
… bella gente!

Corra

Jamo

Ema

GV
Comments (2)
Category: Cazzeggio
Nel DB delle partite dell’Inter c’erano ben 3 date in cui ci risultavano giocate 2 partite lo stesso giorno. In ogni caso si trattava della concomitanza di una partita di Coppa Europa Centrale (aka Mitropa Cup) con una di campionato. Consultanto ogni archivio e almanacco in nostro possesso, ma anche girando su internet, non siamo riusciti a districare il mistero. Io e Jamo siamo quindi andati in Sormani (la più grande biblioteca milanese) a spulciare i microfilm della Gazzetta degli anni in questione: stagioni 1930/31 e 1932/33.
In un’ora circa abbiamo risolto l’arcano. Erano errate le date di campionato. Infatti all’epoca la Coppa Europa si giocava di domenica, ergo venivano posticipati gli incontri del torneo nazionale. Cosa che nessun archivio in nostro possesso riportava correttamente.
Un lavoro di investigazione che ci ha consentito di rendere più attendibili i nostri dati, anche nei dettagli apparentemente più insignificanti.
Comments (2)
Category: LavoroMi sono divertito un po’ con INFORMATION_SCHEMA, il database di metadata di MySQL 5.
Nell’admin ho inserito un summary delle principali statistiche che si aggiorna in tempo reale.
Eccolo
| Numero database | 22 |
| Numero Tabelle | 226 |
| Dimensione totale dati | 2336.8617181778 MB |
| Spazio allocato libero | 0.0345573425292969 MB (0.0015%) |
| Dimensione totale indici | 97.650390625 MB |
| Numero totale righe | 3373741 |
| Stored Procedures | 2 |
| Stored Functions | 1 |
| Views | 0 |
| Triggers | 0 |
| Formato tabelle | 117 Dynamic 109 Fixed |
| Tipo tabelle | 225 MyISAM 1 MRG_MyISAM |
| Formato righe | 446 varchar 350 char 191 enum 158 smallint 129 mediumint 125 tinyint 79 int 58 text 57 date 41 datetime 24 timestamp 12 mediumblob 7 blob 7 time 5 set 4 decimal 4 bigint 2 float 1 longtext 1 longblob |
Sto razionalizzando un paio di tabelle del DB, o meglio, “normalizzando”.
Sto togliendo delle inutili ridondanze da giocatori, tipo ad esempio il numero totale delle presenze e dei gol segnati per competizione, che necessità c’è di avere questi dati se possiamo calcolarli dalle stagioni di carriera già presenti in una tabella a parte?
La tabella delle partite subirà invece le variazioni maggiori: non ci saranno più i nomi per esteso delle squadre, ma ci sarà solo un ID dell’avversaria dell’Inter. Anzitutto è inutile avere “Inter” replicato su tutti i record, ben sappiamo che una delle squadre siamo sempre noi! In questo modo sfruttiamo maggiormente il modello relazionale dei dati.
Ovviamente c’è il rovescio della medaglia: la modifica di tutti gli script che lavorano su queste due tabelle! Non sono pochi, ma un piccolo stratagemma mi ha consentito di non perdere un sacco di tempo a riscrivere query su query e stravolgere pezzi di codice.
Ho creato una STORED FUNCTION che mi ritorna il nome di una squadra in base all’ID della partita, al fatto che si tratti della squadra ospite o di quella di casa e alla lingua (così risolviamo anche le annose questioni sui nomi delle squadre con Stewart). In questo modo non ho dovuto modificare niente nel codice degli script, se non soltanto cambiare le parti SELECT dei nomi con la chiamata a tale function. Molto veloce.
Ecco la STORED FUNCTION in questione
CREATE FUNCTION `nome_squadra`(idp int, casatrasf char(1), lingua char(2))
RETURNS varchar(25)
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE ns varchar(25) default '';
SELECT IF(ct=casatrasf,
CASE
WHEN stagione between '1928/29' and '1942/43' THEN 'Ambrosiana Inter'
ELSE 'Inter'
END,
CASE lingua
WHEN 'it' THEN nome_it
WHEN 'en' THEN nome_en
WHEN 'es' THEN nome_es
END) INTO ns
FROM match join team using(idteam)
WHERE idmatch=idp;
RETURN ns;
END
una query di selezione di un partita diviene quindi
SELECT nome_squadra(idmatch,'c','it') as squadra_casa, nome_squadra(idmatch,'t','it') as squadra_ospitata
FROM match
WHERE idmatch=1234;
A corollario di questo lavoro ho scovato qualche inesattezza sul DB: una ventina di date di partite errate e dei dati statistici di giocatori non congruenti. Con un po’ di deduzioni logiche e di ricerche d’archivio (siti internet e manuali del calcio) ho corretto la maggior parte di questi errori storici.
In effetti il problema di intercettare l’output di query all’interno di una stored procedure non è di banale soluzione. E’ stata proposta una pacth per il DBD::MySQL, ma sinceramente non l’ho analizzata in dettaglio per capire quanto è percorribile e perchè non sia stata ancora inclusa ufficialmente.
In attesa di vedere cosa capita l’unico modo al momento per avvantaggiarsi delle stored procedures accedendovi tramite DBI è di passare parametri in OUT.
Ho creato la seguente SP:
CREATE PROCEDURE conta_notizie(OUT newscount INT)
SELECT COUNT(*) INTO newscount FROM notizie WHERE published='Y';
il semplice script PERL (con l’uso del modulo AAS) ritorna il valore che ci interessa:
#!/usr/bin/perl
use AAS;
use strict;
my $p = new AAS;
$p->ConnettiDB;
my $query = "call conta_notizie(\@n)";
$p->RunQuery($query);
$query = "select \@n";
my ($t,$c) = $p->RunQuery($query);
print "Le notizie sono $t->[0][0]\n\n”;
$p->DisconnettiDB;
Ovviamente tanti sono i valori da leggere tante dovranno essere le user variables da usare.
Il sistema funziona ma è poco scalabile, soprattutto se vogliamo che la SP possa ad esempio ritornare “più righe” di risultato. Bisogna pensare quindi la SP in modo che ritorni “una riga di risultato” e che al contempo sia utile per i nostri scopi.
NB
L’esempio usato non è molto calzante, infatti per ritornare un solo valore si poteva scrivere una FUNCTION.
CREATE FUNCTION conta_news() RETURNS INT
NOT DETERMINISTIC
BEGIN
DECLARE numnotizie INT DEFAULT 0;
SELECT COUNT(*) INTO numnotizie FROM notizie WHERE published='Y';
RETURN numnotizie;
END
e chiamarla poi dallo script come.
SELECT conta_news()
lo script PERL sarebbe risultato più semplice