sql >> Database >  >> RDS >> PostgreSQL

Update meerdere kolommen die beginnen met een specifieke tekenreeks

Hiervoor heb je dynamische SQL nodig. U moet dus voorbereid zijn op mogelijke SQL-injectie.

Basisquery

De basisquery om het benodigde DML-commando te genereren kan er als volgt uitzien:

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

Retourneren:

UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
  • Ik gebruik de "kolomlijstsyntaxis " van UPDATE om de code in te korten en de taak te vereenvoudigen.

  • Ik zoek de systeemcatalogi in plaats van informatieschema omdat de laatste, hoewel gestandaardiseerd en gegarandeerd draagbaar in de belangrijkste versies, ook notoir traag en soms onpraktisch is. Er zijn voor- en nadelen, we hebben dit hier op SO al meerdere keren besproken. Zoek naar de trefwoorden voor meer informatie.

  • quote_ident() voor de kolomnamen voorkomt SQL-injectie en is ook nodig voor elke niet-standaard kolomnamen.

  • U heeft verzuimd uw Postgres-versie te vermelden. De verzamelfunctie string_agg() vereist 9.0+.

Volledige automatisering met PL/pgSQL-functie

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

Bel:

SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
  • Om de functie praktischer te maken, retourneert het informatie zoals beschreven in de opmerking. Meer over het verkrijgen van de resultaatstatus in plpgsql in de handleiding.

  • Ik gebruik de variabele _sql om de queryreeks vast te houden, zodat ik het aantal gevonden kolommen kan verzamelen (col_ct ) in dezelfde zoekopdracht.

  • Het object-ID type regclass is de meest efficiënte manier om automatisch SQL-injectie te vermijden (en ook niet-standaardnamen te zuiveren) voor de tabelnaam. U kunt schema-gekwalificeerde tabelnamen . gebruiken onduidelijkheden te voorkomen. Ik zou adviseren om dit te doen als je meerdere schema's in je db hebt! Meer details in deze gerelateerde vraag:
    Tabelnaam als een PostgreSQL-functieparameter

-> SQLfiddle-demo .



  1. Een database maken met Liquibase

  2. Wat is PostgreSQL?

  3. Een nieuwe kolom toevoegen in alle mysql-tabellen

  4. Waarde invoegen en instellen met max()+1 problemen