2009-06-04 18 views
46

Uguale a oracle diff: how to compare two tables? tranne in mysql.confrontare le differenze tra due tabelle in mysql

Supponiamo di avere due tabelle, t1 e t2 che sono identiche nel layout ma che possono contenere dati diversi.

Qual è il modo migliore per diffare queste due tabelle?

Per essere più precisi, sto cercando di capire una semplice query SQL che mi dice che se i dati da una riga in T1 è diverso dai dati della riga corrispondente a t2

Risulta I non è possibile utilizzare l'intersezione o meno. Quando provo

SELECT * FROM robot intersect SELECT * FROM tbd_robot 

ricevo un codice di errore:

[Codice errore: 1064, SQL Stato: 42000] Hai un errore nella sintassi SQL ; controllare il manuale che corrisponde al server versione di MySQL per la sintassi diritto di utilizzare vicino a 'SELECT * FROM tbd_robot' at line 1

Sto facendo qualcosa di sbagliato sintatticamente? In caso contrario, c'è un'altra domanda che posso usare?

Modifica: Inoltre, sto interrogando tramite una versione gratuita DbVisualizer. Non sono sicuro che questo potrebbe essere un fattore.

risposta

65

INTERSECT ha bisogno di essere emulato in MySQL:

SELECT 'robot' AS `set`, r.* 
FROM robot r 
WHERE ROW(r.col1, r.col2, …) NOT IN 
     (
     SELECT * 
     FROM tbd_robot 
     ) 
UNION ALL 
SELECT 'tbd_robot' AS `set`, t.* 
FROM tbd_robot t 
WHERE ROW(t.col1, t.col2, …) NOT IN 
     (
     SELECT * 
     FROM robot 
     ) 

Edit: aggiunto `intorno alle parole: impostato

+1

Fantastico, grazie! Apparentemente, non avevo bisogno della parte "come set" ma ora funziona – echoblaze

+0

Superbo !. Questo è quello che stavo cercando. E so anche ROW (...) IN (...) cosa ora – Imdad

+2

Qualche idea su come farlo senza dover scrivere tutti i campi? – Veve

53

È possibile costruire manualmente l'intersezione utilizzando UNION. È facile se hai un campo univoco in entrambe le tabelle, ad es. ID:

SELECT * FROM T1 
WHERE ID NOT IN (SELECT ID FROM T2) 

UNION 

SELECT * FROM T2 
WHERE ID NOT IN (SELECT ID FROM T1) 

Se non si dispone di un valore unico, è ancora possibile ampliare il codice qui sopra per verificare la presenza di tutti i campi invece che solo l'ID, e utilizzare e per collegarli (ad esempio ID NOT IN (. ..) E OTHER_FIELD NOT iN (...) ecc)

+2

risposta impressionante. –

+1

soluzione elegante, @Roee Adler! – Chubaka

+0

Grazie. Questo è funzionante. –

8

ho trovato un'altra soluzione in questo link

SELECT MIN (tbl_name) AS tbl_name, PK, column_list 
FROM 
(
    SELECT ' source_table ' as tbl_name, S.PK, S.column_list 
    FROM source_table AS S 
    UNION ALL 
    SELECT 'destination_table' as tbl_name, D.PK, D.column_list 
    FROM destination_table AS D 
) AS alias_table 
GROUP BY PK, column_list 
HAVING COUNT(*) = 1 
ORDER BY PK 
+1

ciao, +1. Stavo cercando la stessa identica cosa. – Hussain

+0

@ haim-evgi ignora i duplicati ... Supponiamo che una tabella abbia una riga e un'altra tabella abbia tali due righe, quindi ignorerà questa. ovviamente, considerando che non ci sono campi PK in entrambe le tabelle. Come dovremmo gestire in questo caso? –

+0

Ho dovuto usare '' COUNT (*) '' invece di '' COUNT (*) ''. – Rolf

2

Sulla base di risposta di Haim ho creato un codice PHP per testare e visualizzare tutte le differenze tra due database. Questo verrà visualizzato anche se una tabella è presente nei database di origine o di test. È necessario modificare con i dettagli il contenuto delle variabili <>.

<?php 

    $User = "<DatabaseUser>"; 
    $Pass = "<DatabasePassword>"; 
    $SourceDB = "<SourceDatabase>"; 
    $TestDB = "<DatabaseToTest>"; 

    $link = new mysqli("p:". "localhost", $User, $Pass, ""); 

    if (mysqli_connect_error()) { 

     die('Connect Error ('. mysqli_connect_errno() .') '. mysqli_connect_error()); 

    } 

    mysqli_set_charset($link, "utf8"); 
    mb_language("uni"); 
    mb_internal_encoding("UTF-8"); 

    $sQuery = 'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="'. $SourceDB .'";'; 

    $SourceDB_Content = query($link, $sQuery); 

    if (!is_array($SourceDB_Content)) { 

     echo "Table $SourceDB cannot be accessed"; 
     exit(0); 

    } 

    $sQuery = 'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="'. $TestDB .'";'; 

    $TestDB_Content = query($link, $sQuery); 

    if (!is_array($TestDB_Content)) { 

     echo "Table $TestDB cannot be accessed"; 
     exit(0); 

    } 

    $SourceDB_Tables = array(); 
    foreach($SourceDB_Content as $item) { 
     $SourceDB_Tables[] = $item["TABLE_NAME"]; 
    } 

    $TestDB_Tables = array(); 
    foreach($TestDB_Content as $item) { 
     $TestDB_Tables[] = $item["TABLE_NAME"]; 
    } 
    //var_dump($SourceDB_Tables, $TestDB_Tables); 
    $LookupTables = array_merge($SourceDB_Tables, $TestDB_Tables); 
    $NoOfDiscrepancies = 0; 
    echo " 

    <table border='1' width='100%'> 
    <tr> 
     <td>Table</td> 
     <td>Found in $SourceDB (". count($SourceDB_Tables) .")</td> 
     <td>Found in $TestDB (". count($TestDB_Tables) .")</td> 
     <td>Test result</td> 
    <tr> 

    "; 

    foreach($LookupTables as $table) { 

     $FoundInSourceDB = in_array($table, $SourceDB_Tables) ? 1 : 0; 
     $FoundInTestDB = in_array($table, $TestDB_Tables) ? 1 : 0; 
     echo " 

    <tr> 
     <td>$table</td> 
     <td><input type='checkbox' ". ($FoundInSourceDB == 1 ? "checked" : "") ."></td> 
     <td><input type='checkbox' ". ($FoundInTestDB == 1 ? "checked" : "") ."></td> 
     <td>". compareTables($SourceDB, $TestDB, $table) ."</td> 
    </tr> 
     "; 

    } 

    echo " 

    </table> 
    <br><br> 
    No of discrepancies found: $NoOfDiscrepancies 
    "; 


    function query($link, $q) { 

     $result = mysqli_query($link, $q); 

     $errors = mysqli_error($link); 
     if ($errors > "") { 

      echo $errors; 
      exit(0); 

     } 

     if($result == false) return false; 
     else if ($result === true) return true; 
     else { 

      $rset = array(); 

      while ($row = mysqli_fetch_assoc($result)) { 

       $rset[] = $row; 

      } 

      return $rset; 

     } 

    } 

    function compareTables($source, $test, $table) { 

     global $link; 
     global $NoOfDiscrepancies; 

     $sQuery = " 

    SELECT column_name,ordinal_position,data_type,column_type FROM 
    (
     SELECT 
      column_name,ordinal_position, 
      data_type,column_type,COUNT(1) rowcount 
     FROM information_schema.columns 
     WHERE 
     (
      (table_schema='$source' AND table_name='$table') OR 
      (table_schema='$test' AND table_name='$table') 
     ) 
     AND table_name IN ('$table') 
     GROUP BY 
      column_name,ordinal_position, 
      data_type,column_type 
     HAVING COUNT(1)=1 
    ) A;  

     "; 

     $result = query($link, $sQuery); 

     $data = ""; 
     if(is_array($result) && count($result) > 0) { 

      $NoOfDiscrepancies++; 
      $data = "<table><tr><td>column_name</td><td>ordinal_position</td><td>data_type</td><td>column_type</td></tr>"; 

      foreach($result as $item) { 

       $data .= "<tr><td>". $item["column_name"] ."</td><td>". $item["ordinal_position"] ."</td><td>". $item["data_type"] ."</td><td>". $item["column_type"] ."</td></tr>"; 

      } 

      $data .= "</table>"; 

      return $data; 

     } 
     else { 

      return "Checked but no discrepancies found!"; 

     } 

    } 

?> 
+0

Chiedere +1 riduce le possibilità di ottenerlo. Stack Overflow ha una coda di revisione, le persone sono incoraggiate a votare per le domande e risposte a loro piace. una risposta decente può ottenere un upvote o due. C'è un badge in bronzo per le risposte che 10 upvotes ("bella risposta"), 25 upvotes: "buona risposta" (distintivo d'argento) e 100 uptotes "ottima risposta" (distintivo d'oro). le inversioni di solito si articolano lentamente, di solito, a seconda della domanda, della risposta e dell'argomento. Possono essere necessarie settimane, mesi o anni per ottenere un numero elevato di fattori di aumento, dal momento che non molte persone potrebbero vedere la domanda o la tua risposta, o potrebbero essere risposte competitive che rubano lo spettacolo. – clearlight

+0

Raccomando il [Tour in 2 minuti] (http://stackoverflow.com/tour). Questo ti darà più informazioni su ciò che accade qui. Sembra che tu sia pronto per la sfida, imparare in fretta e fare un buon lavoro. Dovresti essere in grado di far crescere rapidamente la tua reputazione e i privilegi del tuo sito e lavorare su alcuni badge per mostrare anche i tuoi contributi. In bocca al lupo! E benvenuto – clearlight

4
select t1.user_id,t2.user_id 
from t1 left join t2 ON t1.user_id = t2.user_id 
and t1.username=t2.username 
and t1.first_name=t2.first_name 
and t1.last_name=t2.last_name 

provare questo. Questo confronterà la tua tabella e troverà tutte le coppie corrispondenti, se qualche discrepanza restituirà NULL a sinistra.

+0

Questa è la risposta migliore e più performante per la domanda! Grazie! –

+0

assicurati di usare ifnull (t1.field_name, 1) = ifnull (t2.field_name, 1) per assicurarti di eliminare i falsi positivi. –

Problemi correlati