sql >> Databasteknik >  >> RDS >> PostgreSQL

Uppdatera flera kolumner som börjar med en specifik sträng

Du behöver dynamisk SQL för detta. Så du måste vara beredd att hantera eventuell SQL-injektion.

Grundläggande fråga

Den grundläggande frågan för att generera DML-kommandot som behövs kan se ut så här:

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

Returnerar:

UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
  • Jag använder mig av "kolumnlistsyntax stark> " av UPDATE för att förkorta koden och förenkla uppgiften.

  • Jag frågar systemkatalogerna istället för informationsschema eftersom den senare, samtidigt som den är standardiserad och garanterad att vara bärbar över större versioner, också är notoriskt långsam och ibland svårhanterlig. Det finns för- och nackdelar, vi har diskuterat detta flera gånger här på SO. Sök efter nyckelorden för mer information.

  • quote_ident() för kolumnnamnen förhindrar SQL-injektion och är också nödvändig för alla icke-standardiserade kolumnnamn.

  • Du försummade att nämna din Postgres-version. Den aggregerade funktionen string_agg() kräver 9.0+.

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

Ring:

SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
  • För att göra funktionen mer praktisk returnerar den information som beskrivs i kommentaren. Mer om att få resultatstatus i plpgsql i manualen.

  • Jag använder variabeln _sql för att hålla frågesträngen, så att jag kan samla antalet kolumner som hittats (col_ct ) i samma fråga.

  • Objektidentifieraren typ regclass är det mest effektiva sättet att automatiskt undvika SQL-injektion (och sanera icke-standardiserade namn) för tabellnamnet också. Du kan använda schemakvalificerade tabellnamn för att undvika oklarheter. Jag skulle råda dig att göra det om du har flera scheman i din db! Mer information i den här relaterade frågan:
    Tabellnamn som en PostgreSQL-funktionsparameter

-> SQLfiddle-demo .



  1. django.db.utils.OperationalError Kunde inte ansluta till servern

  2. Ställ in timeout för Oracle 10g databasanslutning i Java

  3. Hur BIN() fungerar i MariaDB

  4. MYSQL undvik att infoga samma rad två gånger