it-swarm-eu.dev

Come trasferire solo i nuovi valori di colonna da una tabella all'altra?

Sto tentando di creare una nuova tabella: _clients che verrà semplicemente popolato con, per ora, con il user_id colonna da #__user_usergroup_map.

Idealmente, il codice seguente dovrebbe estrarre tutti i id da #__user_usergroup_map tabella se corrispondente group_id = 10 e solo ID che non sono già presenti all'interno di _clients tavolo.

Questo sembra funzionare quando aggiungo/rimuovo utenti da group_id = 10 in phpmyadmin. Il $ncl mostra un elenco corretto.

#__clients si aggiorna correttamente all'aggiornamento della pagina, tuttavia viene visualizzato un errore sql per l'inserimento della chiave primaria duplicata in #__clients. Sembra che stia tentando di aggiungere lo stesso utente a #__clients di nuovo (ha aggiunto l'utente alla tabella al primo aggiornamento).

Pensavo che questo codice dovesse selezionare solo $ncl poiché tali ID client non sono già presenti in #__clients tavolo. Qualcuno ha qualche pensiero?

$db = JFactory::getDBO();
$query = $db->getQuery(true);
$query->select('a.user_id', 'a.group_id', 'b.id')
      ->from('#__user_usergroup_map as a', '#__clients as b');
$query->join('RIGHT', '#__clients AS b ON a.user_id != b.id')
      ->where('a.group_id = ' . $db->quote("10"));
$db->setQuery($query);
$ncl = $db->loadColumn();
print_r($ncl);

foreach($ncl as $encl) {
    $db    = JFactory::getDbo();
    $query = $db->getQuery(true);
    $query->insert('#__clients')
          ->set('id = ' . (int) $encl);
    $db->setQuery($query);
    $db->execute();
}
3
Michael Brown

Puoi adattare il tuo codice a:

$db = JFactory::getDBO();
$query = $db->getQuery(true);
$query->select('a.user_id as id') /* changed to load object and insert it */
    ->from('#__user_usergroup_map as a')
    ->leftJoin('#__clients AS b ON a.user_id = b.id') /* you should join with "=" not with "!=" */
    ->where('a.group_id = ' . $db->quote("10"))
    ->where('b.id IS NULL'); /* and filter to "new only" like this */
$ncl = $db->setQuery($query)->loadColumn();
print_r($ncl);

foreach($ncl as $encl) {
    $db->insertObject('#__clients',$encl); /* less code this way */
}

funzionerebbe bene con questo codice, ma puoi andare oltre e farlo

$db = JFactory::getDBO();
$sel_query = $db->getQuery(true);
$ins_query = $db->getQuery(true);
$sel_query->select('a.user_id as id')
    ->from('#__user_usergroup_map as a')
    ->leftJoin('#__clients AS b ON a.user_id = b.id')
    ->where('a.group_id = ' . $db->quote("10"))
    ->where('b.id IS NULL');
$ins_query->insert('#__clients')
    ->columns('id')
    ->values($sel_query);
$db->setQuery(str_replace('VALUES','',$ins_query))->execute();

in questo modo eseguirai il lavoro con una singola richiesta.

1
Alexandr

Ho appena realizzato un metodo più semplice ... Dato che avevo già creato array esistenti, potevo semplicemente usare qualcosa del tipo:

$filteredFoo = array_diff($foo, $bar);

Ciò filtrerà i duplicati dai due array che rappresentano ciascuna tabella e quindi eseguirà un inserimento SQL con $ filteredFoo senza il rischio di duplicati.

1
Michael Brown

Poiché hai solo bisogno di INSERIRE i dati da #__user_usergroup_map A #__clients Dove id è nullo E dove group_id È 10, Devi utilizzare LEFT JOIN Per unirsi ai tavoli. Altri join elimineranno le righe che producono una colonna NULL e ciò non è desiderabile.

|  #__user_usergroup_map |  LEFT JOIN ON user_id=id  |  #__clients  |
|------------------------|              <            |--------------|
|  user_id  |  group_id  |              <            |      id      |
|-----------|------------|              <            |--------------|
|     1     |     10     |              <            |     NULL     |
|     2     |      9     |              <            |     NULL     |
|     3     |     10     |              <            |     NULL     |
|     4     |      6     |              <            |     NULL     |
|     5     |     10     |              <            |       5      | //previously INSERTED for demonstration's sake
|     6     |     10     |              <            |     NULL     |
|     7     |     10     |              <            |     NULL     |
|     8     |     10     |              <            |     NULL     |
|     9     |      4     |              <            |     NULL     |
|    10     |     10     |              <            |     NULL     |
--------------------------                           ----------------

Prima di arrivare alle soluzioni, voglio richiamare l'attenzione sul fatto che la tua sintassi php/Joomla non sta generando la query desiderata.

$query = $db->getQuery(true)
            ->select('a.user_id', 'a.group_id', 'b.id')
            ->from('#__user_usergroup_map as a', '#__clients as b')
            ->join('RIGHT', '#__clients AS b ON a.user_id != b.id')
            ->where('a.group_id = ' . $db->quote("10"));
echo $query->dump();

Genera:

SELECT a.user_id                                    // 2nd & 3rd columns are lost (should have been written as an array, but they were unimportant anyhow)
FROM prefx_user_usergroup_map as a                  // comma joined table is lost (not that it was good for anything)
RIGHT JOIN prefx_clients AS b ON a.user_id != b.id  // this is not the correct join, nor ON logic
WHERE a.group_id = '10'                             // this is half of what is required

Questo restituirà zero righe.


Mentre sono fiducioso che lo snippet di Alexandr fornirà il risultato atteso perché la logica/sintassi è valida, offrirò la mia versione che presenta alcune differenze.

$db = JFactory::getDBO();
try {
    $select_query = $db->getQuery(true)
                       ->select("A.user_id")
                       ->from("#__user_usergroup_map A")
                       ->leftJoin("#__clients B ON A.user_id = B.id")
                       ->where("A.group_id = 10 AND B.id IS NULL");
    //echo $select_query->dump();

    $insert_query = $db->getQuery(true)
                       ->insert('#__clients')
                       ->columns('id')
                       ->values($select_query);
    // echo $insert_query->dump();

    $db->setQuery($insert_query);
    $db->execute();
    // echo $db->getAffectedRows() , " row(s) inserted into clients table";
} catch (Exception $e) {
    echo "Syntax Error"; // . " & Error: " . $e->getMessage();
}

Ho testato il mio frammento per avere successo sul mio host locale. Ho anche creato una SQLFiddle Demo se qualcuno vuole giocare.

  • Sto concatenando ogni query dal metodo getQuery() per eliminare menzioni duplicate di ${Word}_query.
  • Non sto usando alcuna chiamata qn() o q() perché non sono necessarie per motivi di analisi/sicurezza.
  • Uso gli alias di tabella in maiuscolo per aiutarli a distinguersi dai nomi e dalle colonne della tabella.
  • Non sto aliasando la colonna in SELECT perché non è richiesta.
  • setQuery(str_replace('VALUES','',$ins_query)) non è necessario.

Nel caso in cui qualcuno sia preoccupato di rubare senza vergogna la soluzione di Alexandr, pubblicherò una diversa query-build con forza bruta che avrà lo stesso effetto supponendo che la tua colonna #__clients.id Sia un PRIMARY/UNIQUE KEY. Non penso che userei questa soluzione meno elegante (anche se, per qualche ragione, fosse leggermente più performante).

$select_query = $db->getQuery(true)
                   ->select("A.user_id")
                   ->from("#__user_usergroup_map A")
                   ->where("A.group_id = 10");
// echo $select_query->dump();

$insert_query = $db->getQuery(true)
                   ->insert('#__clients')
                   ->columns('id')
                   ->values($select_query);

$db->setQuery(str_replace("INSERT", "INSERT IGNORE", $insert_query));
0
mickmackusa