db_affected_rows in Drupal 7 per db_query


8

Ho appena notato che @Berdir è stato così bello da rimuovere db_affected_rowsda Drupal 7 . Ora mi chiedo quale sia la procedura migliore ora per rilevare se la query eseguita ha cambiato qualcosa nel database.

Un tipico caso d'uso sarebbe.

db_query(...);
if (!db_affected_rows()) {
  db_query(...);
}

Ho dato un'occhiata all'oggetto query restituito da db_query, ma non mi è sembrato di grande aiuto.

Aggiornamento:
vedo che non ero chiaro su quali circostanze avessi bisogno delle informazioni.

Il mio caso d'uso attuale è piuttosto semplice. Ho una tabella per un tipo di nodo con una colonna nid e alcune colonne di dati. Ho un modulo e dopo aver inviato il modulo, voglio inserire o aggiornare la riga nel db.

Il problema con db_update/ db_insertè che, se uso prima l'aggiornamento e inserisco se l'aggiornamento restituisce 0, non rileverò la condizione, in cui il modulo è stato inviato con il valore nel db. Se uso prima db_insert, ciò genererà un errore se esiste già una riga nel db.

Suppongo che in questa specifica condizione potrei inserire un valore vuoto quando il nodo viene creato e quindi utilizzare solo l'aggiornamento, ma per alcuni casi ciò potrebbe non essere possibile, se avessi bisogno di archiviare informazioni che erano state codificate in un database esterno. Vorrei anche evitare di dover dipendere dai valori del database affinché il mio codice funzioni.

La mia solita strategia per questi casi è stata quella di fare un

db_query("INSERT IGNORE INTO ...")
if (!db_affected_rows()) {
  db_query("UPDATE ...");
}

Fare questo è sia semplice che privo di errori, indipendentemente dalle condizioni in cui si trova il db. L'opzione migliore che posso vedere in questo momento, sarebbe gestirla con SQL e fare questo:

db_query("INSERT ... ON DUPLICATE KEY UPDATE");

Ma speravo che l'API db fosse in grado di gestirlo.

Risposte:


9

Tali informazioni vengono restituite direttamente dal metodo execute () di Delete / UpdateQuery, vedere ad esempio UpdateQuery :: execute () .

<?php
$affected = db_update('some_table')
  ->fields(array(
    'some_field' => $value,
  ))
  ->condition('another_field', $id)
  ->execute();
?>

E InsertQuery :: execute () restituisce l'ultimo ID di inserimento.


8

Dopo aver scavato, ho scoperto che Drupal fornisce uno strumento pronto per il mio esatto caso d'uso:

Inserisci una riga nel db o aggiorna l'esistente se è già presente.

Questo si chiama merge query , che può essere fatto atomicamente per alcuni motori db.

Il testo sintetico è piuttosto semplice:

db_merge('example')
  ->key(array('name' => $name))
  ->fields(array(
    'field1' => $value1,
    'field2' => $value2,
))
->execute();

Ah sì, questa è la risposta corretta alla tua domanda aggiornata :) Nota che le query di unione sono state riprogettate alla fine del ciclo di sviluppo D7 per funzionare effettivamente come le query sql MERGE, che fanno parte dello standard SQL 2003 ma nessun dbms lo implementa ancora , quindi tutti i dbms richiedono due query (sono rese atomiche usando le transazioni). Il problema con l'approccio a query singola utilizzato per MySQL era che ignorava completamente la definizione key () e funzionava semplicemente con le chiavi uniche / primarie di una determinata tabella.
Berdir,

@Berdir: grazie per avermi indicato nella giusta direzione. Sono uno di quegli sviluppatori a cui piace scrivere SQL e non
riesco ad

Grazie per questo puntatore. Tuttavia, ho dovuto ricorrere comunque a db_query in quanto il db api di Drupal non consente l'uso di costanti come CURRENT_TIMESTAMP (vedi drupal.org/node/215821 )
Whisky
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.