Infocurci - programmatore Php Roma
Infocurci - programmatore Php Roma
Questo sito non lascia nessun cookie sul vostro pc, consuma pochissimi kb, non profila nulla e non raccoglie dati personali. Siete i benvenuti.

Mysql : Confrontare database

Questa piccola utility che oggi vi metto a disposizione consente di confrontare la struttura di due o più database mysql. E' particolarmente utile quando ad esempio abbiamo a che fare con due ambienti, uno di sviluppo e uno di produzione.

Mysql

Spesso le modifiche a siti già esistenti vengono testate su uno spazio non visibile al pubblico, che sia un server a parte oppure il localhost del nostro pc. Finchè lavoriamo sul server di sviluppo e pubblichiamo le modifiche tutte assieme, non ci sono problemi. I problemi nascono quando il cliente chiede nel frattempo una modifica "al volo", come al solito "urgente", sul database di produzione.. con il tempo modifiche e contromodifiche possono portare ad avere due copie di database, una di lavoro e una pubblica, quasi uguali. E quel "quasi uguali" è foriero di tanti possibili bug che vogliamo decisamente evitare prima di pubblicare le nuove modifiche!

Ho scritto allora questo piccolo ma prezioso tool che si occupa di confrontare due o più database tra loro. Il file si limita alla struttura ma con poche righe di codice potrete adattarlo andando ad esempio ad inserire una verifica sul numero di record, cosa che a me di solito non serve. Ecco un esempio di risultato:

Chi vuole può scaricare il file dal link che trova alla fine dell'articolo, gli altri possono seguire la mia spiegazione step-step cosi da poter elaborare le proprie modifiche.

Le prime righe sono molto semplici: vado a dichiarare i dati di connessione e quindi ad aprire ciascun database, memorizzando le singole risorse in un array cosi da poterle lavorare in seguito. Se anzichè 3 database ne volete usare altri, basta aggiungere nuovi valori all'array $database[]. La chiave "alias" serve solo per dare un nome di debug, visto che se usassi il nome del db potrei andare incontro a frequenti casi di omonimia (molti di noi usano lo stesso nome per il db online e per quello di test).

    $elenco_database = array();
    $elenco_database[] = array('alias'=>'alias1','host'=>'indirizzo1','user'=>'user1','password'=>'password1','db'=>'datbase1');
    $elenco_database[] = array('alias'=>'alias2','host'=>'indirizzo2','user'=>'user2','password'=>'password2','db'=>'datbase2');
    $elenco_database[] = array('alias'=>'alias3','host'=>'indirizzo3','user'=>'user3','password'=>'password3','db'=>'datbase3');
    
    $elenco_colonne = array('Type','Null','Key','Default','Extra'); //semplice array di appoggio per facilitare il debug a video.
    
    $elenco_connessioni = array();
    foreach($elenco_database as $db){
        $connessione = mysql_connect($db['host'], $db['user'], $db['password']) or die('Impossibile eseguire la connessione per il db '.$db['alias']);
        $elenco_connessioni[] = $connessione;
    }

Grazie alle query SHOW TABLES e SHOW FIELDS vado adesso a memorizzare in array tutte le tabelle e, per ciascuna di queste, tutti i campi che compongono i database.  Volendo è possibile trovare soluzioni più eleganti ma questa mi sembra chiara ed efficace, ho usato anche una variabile chiamata "campi_appoggio" per chiarirne subito la natura temporanea.

    for($i=0;$i<$totale_db;$i++){
        $tabelle = array();
        $campi = array();

        mysql_select_db($elenco_connessioni[$i]['database'],$elenco_connessioni[$i]['connessione']) or die('Impossibile selezionare la basedati per il db '.$elenco_connessioni[$i]['database']);
        $sql = 'SHOW TABLES';
        $result = mysql_query($sql, $elenco_connessioni[$i]) or die(mysql_error());
        while($row = mysql_fetch_array($result)){
            $tabelle[] = $row[0];
            $sql_campi = 'SHOW FIELDS FROM '.$row[0];
            $result_campi = mysql_query($sql_campi, $elenco_connessioni[$i]) or die(mysql_error());
            $campi_appoggio = array();
            while($row_campi= mysql_fetch_array($result_campi,MYSQL_ASSOC)){
                $campi_appoggio[$row_campi['Field']] = $row_campi;
            }
            $campi[$row[0]] = $campi_appoggio;
        }
        $elenco_tabelle[] = $tabelle;
        $elenco_campi[] = $campi;
    }

Qui inizia il ciclo che, per ciascun database, estrae tabelle e campi e li confronta con quelli degli altri database, notate infatti che uso due diverse variabili contatore ($i e $cont):

    for($i=0;$i<$totale_db;$i++){

    for($cont=0;$cont<$totale_db;$cont++){

Se in un array di tabelle non esiste una chiave con il nome della tabella corrente, significa che questa non è presente nel database:

    if(!in_array($tabella,$elenco_tabelle[$cont])){

Se invece è presente, verifico se sono presenti i campi:

    if(!isset($elenco_campi[$cont][$tabella][$campo['Field']])){

e infine, se il campo è presente, verifico che le chiavi ('Type','Null','Key','Default','Extra') restituite da Mysql siano uguali. Queste chiavi le avevo memorizzate ad inizio file in un array per semplice comodità, per evitare di dover dichiararle ogni volta:

    foreach ($elenco_colonne as $colonna){

Bene, credo sia tutto sufficientemente chiaro. Potete fare una prova lanciando il file su un paio di database che potete creare al volo sul vostro localhost. Ovviamente, se volete intervenire sul database remoti, è necessario che il server accetti connessioni dall'esterno. Altrimenti vi conviene fare una copia al volo della struttura in locale, apportando le modifiche man mano da myadmin. Procedura un pò meccanica ma semplice e sempre preferibile a quella di dover rispondere al cliente che si trova davanti un errore di "unknown column".

Il file sorgente potete scaricarlo da qui, l'ho chiamato "parallel".