2013-03-06 9 views
5

Sto cercando un'istruzione SQL standard "UPSERT". Una chiamata per inserimento e aggiornamento se esiste.Chiamata UPSERT standard SQL

Sto cercando una chiamata funzionante, efficiente e multipiattaforma.

ho visto MERGE, UPSERT, REPLACE, INSERT .. ON DUPLICATE UPDATE ma nessuna dichiarazione soddisfa le esigenze.

BTW Io uso MYSQL e HSQLDB per unità. Capisco che HSQLDB è limitato e potrebbe non coprire ciò di cui ho bisogno, ma non sono riuscito a trovare un modo standard anche senza di esso. Una dichiarazione che per ora solo MYSQL e HSQLDB saranno sufficienti.

Sono in giro da un po 'e non ho potuto ottenere una risposta.

Il mio tavolo:

CREATE TABLE MY_TABLE (
    MY_KEY varchar(50) NOT NULL , 
    MY_VALUE varchar(50) DEFAULT NULL, 
    TIME_STAMP bigint NOT NULL, 
    PRIMARY KEY (MY_KEY) 
); 

Qualche idea?

Grazie;)

+0

'INSERT .. ON DUPLICATE UPDATE' è la chiave in' mYSQL'. puoi mostrare alcuni record o forse la struttura del tavolo? –

+0

Sì, ma è supportato solo in MYSQL. HSQLDB e tutti gli altri non lo usano ... – BobTheBuilder

+0

c'è una fusione ANSI (http://en.wikipedia.org/wiki/Merge_%28SQL%29), ma non è implementata in tutti i DBMS. Quindi nessuna speranza per un comando universale. –

risposta

4

L'unica soluzione supportata da MySQL e HSQLDB consiste nell'interrogare le righe che si intende sostituire e condizionatamente INSERT o UPDATE. Ciò significa che è necessario scrivere più codice dell'applicazione per compensare le differenze tra le implementazioni RDBMS.

  1. START TRANSACTION.
  2. SELEZIONA ... PER AGGIORNAMENTO.
  3. Se SELECT trova le righe, quindi UPDATE.
  4. Altrimenti, INSER.
  5. COMMIT.

MySQL non supporta l'istruzione MERGE ANSI SQL. Supporta REPLACE e INSERT ... ON DUPLICATE KEY UPDATE. Vedere la mia risposta a "INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE" per ulteriori informazioni.


commenti Re: Sì, un altro approccio è quello di provare solo l'inserto e vedere se si riesce. Altrimenti, fai un UPDATE. Se si tenta di INSERT e colpisce una chiave duplicata, verrà generato un errore, che si trasforma in un'eccezione in alcune interfacce client. Lo svantaggio di farlo in MySQL è che genera un nuovo ID di auto-incremento anche se l'INSERT fallisce. Quindi finisci con le lacune. So che le lacune nella sequenza di auto-incremento non sono di solito qualcosa di cui preoccuparsi, ma ho aiutato un cliente l'anno scorso che aveva intervalli di 1000-1500 tra gli inserti riusciti a causa di questo effetto, e il risultato è stato che hanno esaurito la gamma di un INT nella loro chiave primaria.

Come dice @baraky, si potrebbe invece tentare prima l'UPDATE, e se ciò interessa zero righe, allora fare invece l'INSERT. Il mio commento su questa strategia è che UPDATEing zero rows non è un'eccezione: dovrai verificare "il numero di righe interessate" dopo l'UPDATE per sapere se è "riuscito" o meno.

Ma interrogare il numero di righe interessate riporta al problema originale: è necessario utilizzare query diverse in MySQL rispetto a HSQLDB.

HSQLDB:

CALL DIAGNOSTICS(ROW_COUNT); 

MySQL:

SELECT ROW_COUNT(); 
+0

Oppure esegui INSERT, cattura SQLException e se è una violazione del vincolo di integrità, esegui un UPDATE – fredt

+0

In realtà quello è (quasi) quello che sto per fare - aggiornerò, rileverò l'eccezione (come gli aggiornamenti sono il caso comune per me) e inserire se fallisce. Grazie! – BobTheBuilder

3

La sintassi per fare un upsert in un unico comando varia a seconda del RDBMS.

In MySQL E 'INSERT...ON DUPLICATE KEY UPDATE

In HSQLDB è MERGE

Se si desidera una soluzione multipiattaforma, allora avrete bisogno di utilizzare più comandi. Prima controlla la riga esistente, quindi inserisci o aggiorna in modo condizionato come appropriato.

+0

Non voglio usare più comandi, altre idee su come test e dev eseguiranno lo stesso codice? – BobTheBuilder

+0

Continuo a consigliarlo usando il codice condizionale. Se non lo farai, considera la standardizzazione del test e ambienti dev per utilizzare lo stesso RD BMS. –

+0

@baraky: se si desidera supportare più DBMS, non sarà mai in grado di risolvere ogni problema con un'istruzione eseguita su tutti i DBMS. Preparati ad avere una dichiarazione specifica sul DBMS. Tutto il resto fallirà. –