Utilizzare CASE per selezionare le colonne nella query UPDATE?


13

Posso usare CASEper scegliere quali colonne visualizzare in una SELECTquery (Postgres), in questo modo:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

È possibile fare qualcosa di simile quando si esegue una UPDATEquery in Postgres (ovvero scegliere quali colonne devono essere aggiornate)? Presumo non dal momento che non sono riuscito a trovare nulla al riguardo, ma forse qualcuno ha un'alternativa intelligente (oltre a utilizzare una procedura o aggiornare ogni colonna utilizzando a CASEper determinare se al valore della colonna debba essere assegnato un nuovo valore o semplicemente riassegnato quello esistente valore). Se non ci sono alternative facili, ovviamente accetterò anche quella come risposta.

Informazioni extra : Nel mio caso ho 14 potenziali colonne che possono essere aggiornate, con una sola che viene aggiornata per riga corrispondente (la tabella da aggiornare è unita a un'altra nella query). La quantità di righe da aggiornare probabilmente varierà, potrebbe essere dozzine o centinaia. Credo che siano in atto indici per le condizioni di unione.

Risposte:


26

Se si specifica che una colonna deve essere aggiornata, verrà sempre aggiornata, ma è possibile modificare il valore inserito in modo condizionale e ripristinare i valori originali in base alle proprie condizioni. Qualcosa di simile a:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Quindi, se le condizioni non sono giuste per un aggiornamento di una determinata colonna, devi solo restituire il valore corrente.

Fare nota che ogni riga abbinato sarà vedere un aggiornamento (anche se tutte le colonne finiscono per ottenere insieme ai valori che già hanno) a meno che non si esplicitamente cancello di questa circostanza in voi e filtri e le clausole WHERE, che potrebbe essere un problema di prestazioni (non ci sarà essere una scrittura, gli indici verranno aggiornati, i trigger appropriati verranno attivati, ...) se non mitigati.


Grazie per il suggerimento su tutto ciò che viene aggiornato, se questo è lento, potrei prendere il suggerimento di @Colin 't Hart di avere più dichiarazioni di aggiornamento.
newenglander

È possibile mitigare il problema completo assicurandosi che le clausole ON e WHERE filtrino tutte le righe in cui non sono necessarie modifiche, ma ciò può significare ripetere tutte le condizioni sia nella clausola SET che nella clausola WHERE (a meno che non sia presente un controllo generale più semplice che è equivalente al 100% a tutte queste condizioni combinate). A quel punto questo metodo potrebbe essere ancora più efficiente, ma il metodo degli aggiornamenti multipli potrebbe essere più semplice da mantenere.
David Spillett,

Ricorda inoltre che l'aggiornamento di una colonna con lo stesso valore comporterà la creazione di una ripetizione, vedi orainternals.wordpress.com/2010/11/04/…
Colin 't Hart

@Colin: Sì, qualsiasi aggiornamento passerà attraverso il registro delle transazioni del DB, compresi gli aggiornamenti che sono essenzialmente NoOps a causa dell'aggiornamento dei campi per avere gli stessi valori che avevano prima. Oltre al potenziale per un immediato problema di prestazioni, questo potrebbe essere un fattore importante se si utilizzano la replica, i backup differenziali, il log shipping e così via, poiché le operazioni di aggiornamento delle righe extra aumenteranno lo spazio / larghezza di banda necessari per quelli.
David Spillett,

Grazie a entrambi per i suggerimenti, nel mio caso la singola istruzione di aggiornamento ha funzionato bene.
newenglander

5

Quante diverse combinazioni di colonne da aggiornare hai? Quante righe dell'intera tabella verranno aggiornate? Sono presenti indici per un rapido accesso alle righe da aggiornare?

A seconda delle risposte a queste domande, potresti essere in grado di eseguire più istruzioni di aggiornamento, una per ogni colonna che desideri aggiornare e posizionare la condizione sul valore di quella colonna nella clausola where dell'aggiornamento in modo che zero righe vengano aggiornate se quella colonna ha un valore sbagliato.

Prova a pensare basato su set, non dare per scontato che l'aggiornamento debba aggiornare una singola riga trovata dalla chiave primaria.


Grazie per la risposta. Ho aggiunto alcune informazioni alla mia domanda, spero sia comprensibile. Questa è una buona alternativa con più istruzioni di aggiornamento (preferirei una dichiarazione di aggiornamento, ma vedo che c'è un vantaggio lì).
newenglander

Questa potrebbe essere la risposta che sto cercando ma intendi mettere update column_x = new_value_for_x dove @val = 0. Potrei sperimentare qualcosa del genere. Sembra divertente Non è più semplice se val = 0 inizia l'aggiornamento column_x = new_value_for_x ecc.
CashCow

-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then 'Ace@Assasin.com'
       when FName = 'Riddick' then 'fallguy@Drunk.com'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end

Questo aggiornamento è una sola colonna, mentre chi desidera sapere come aggiornare colonne diverse a seconda delle condizioni.
Colin 't Hart,
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.