PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Aggiorna più colonne che iniziano con una stringa specifica

Hai bisogno di SQL dinamico per questo. Quindi devi essere preparato ad affrontare una possibile SQL injection.

Richiesta di base

La query di base per generare il comando DML necessario può essere simile a questa:

SELECT format('UPDATE tbl SET (%s) = (%s)'
               ,string_agg (quote_ident(attname), ', ')
               ,string_agg ('NULL', ', ')
             )
FROM   pg_attribute
WHERE  attrelid = 'tbl'::regclass
AND    NOT attisdropped 
AND    attnum > 0
AND    attname ~~ 'foo_%';

Resi:

UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
  • Uso la "sintassi dell'elenco di colonne " di UPDATE per abbreviare il codice e semplificare il compito.

  • Interrogo i cataloghi di sistema invece di schema informativo perché quest'ultimo, pur essendo standardizzato e garantito per essere portabile su tutte le versioni principali, è anche notoriamente lento e talvolta ingombrante. Ci sono pro e contro, ne abbiamo discusso diverse volte qui su SO. Cerca le parole chiave per ulteriori informazioni.

  • quote_ident() per i nomi delle colonne impedisce l'iniezione SQL ed è necessario anche per qualsiasi nomi di colonne non standard.

  • Hai dimenticato di menzionare la tua versione di Postgres. La funzione aggregata string_agg() richiede 9.0+.

Automazione completa con funzione PL/pgSQL

CREATE OR REPLACE FUNCTION f_update_cols(_tbl regclass, _col_pattern text
                                        , OUT row_ct int, OUT col_ct int)
  RETURNS record AS
$func$
DECLARE
   _sql text;
BEGIN
   SELECT format('UPDATE tbl SET (%s) = (%s)'
                 ,string_agg (quote_ident(attname), ', ')
                 ,string_agg ('NULL', ', ')
                )
         ,count(*)::int
   INTO   _sql, col_ct
   FROM   pg_attribute
   WHERE  attrelid = _tbl
   AND    NOT attisdropped         -- no dropped columns
   AND    attnum > 0               -- no system columns
   AND    attname ~~ _col_pattern; -- only columns matching pattern

   -- RAISE NOTICE '%', _sql;      -- output generated SQL for debugging
   EXECUTE _sql;

   GET DIAGNOSTICS row_ct = ROW_COUNT;
END
$func$  LANGUAGE plpgsql;

COMMENT ON FUNCTION f_update_cols(regclass, text)
 IS 'Updates all columns of table _tbl ($1)
that match _col_pattern ($2) in a LIKE expression.
Returns the count of columns (col_ct) and rows (row_ct) affected.';

Chiama:

SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
  • Per rendere la funzione più pratica, restituisce informazioni come descritto nel commento. Ulteriori informazioni su ottenimento dello stato del risultato in plpgsql nel manuale.

  • Uso la variabile _sql per contenere la stringa di query, così posso raccogliere il numero di colonne trovate (col_ct ) nella stessa query.

  • Il tipo di identificatore dell'oggetto regclass è il modo più efficiente per evitare automaticamente l'iniezione SQL (e disinfettare i nomi non standard) anche per il nome della tabella. Puoi utilizzare nomi di tabelle qualificati per lo schema per evitare ambiguità. Ti consiglierei di farlo se hai più schemi nel tuo db! Maggiori dettagli in questa domanda correlata:
    Nome tabella come parametro di funzione PostgreSQL

-> Demo di SQLfiddle .