PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Aktualisieren Sie mehrere Spalten, die mit einer bestimmten Zeichenfolge beginnen

Dazu benötigen Sie dynamisches SQL. Sie müssen also darauf vorbereitet sein, mit einer möglichen SQL-Injektion umzugehen.

Grundlegende Abfrage

Die grundlegende Abfrage zum Generieren des benötigten DML-Befehls kann wie folgt aussehen:

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_%';

Rückgabe:

UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
  • Ich verwende die "Spaltenlistensyntax " von UPDATE um den Code zu verkürzen und die Aufgabe zu vereinfachen.

  • Ich frage die Systemkataloge ab anstelle von Informationsschema denn letzteres ist, obwohl es standardisiert und garantiert über Hauptversionen portierbar ist, auch notorisch langsam und manchmal unhandlich. Es gibt Vor- und Nachteile, wir haben das hier auf SO mehrfach diskutiert. Suchen Sie nach den Schlüsselwörtern, um weitere Informationen zu erhalten.

  • quote_ident() für die Spaltennamen verhindert SQL-Injection und ist auch für any notwendig nicht standardmäßige Spaltennamen.

  • Sie haben es versäumt, Ihre Postgres-Version zu erwähnen. Die Aggregatfunktion string_agg() erfordert 9.0+.

Vollständige Automatisierung mit PL/pgSQL-Funktion

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.';

Aufruf:

SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
  • Um die Funktion praktischer zu gestalten, gibt sie Informationen wie im Kommentar beschrieben zurück. Mehr über Erhalten des Ergebnisstatus in plpgsql im Handbuch.

  • Ich verwende die Variable _sql um die Abfragezeichenfolge zu speichern, damit ich die Anzahl der gefundenen Spalten sammeln kann (col_ct ) in derselben Abfrage.

  • Der Objektbezeichnertyp regclass ist der effizienteste Weg, um auch für den Tabellennamen automatisch eine SQL-Einschleusung zu vermeiden (und nicht standardmäßige Namen zu bereinigen). Sie können schemaqualifizierte Tabellennamen verwenden Unklarheiten zu vermeiden. Ich würde dazu raten, wenn Sie mehrere Schemas in Ihrer Datenbank haben! Weitere Details in dieser verwandten Frage:
    Tabellenname als PostgreSQL-Funktionsparameter

-> SQLfiddle-Demo .