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

Opdater flere kolonner, der starter med en bestemt streng

Du skal bruge dynamisk SQL til dette. Så du skal være forberedt på at håndtere eventuel SQL-injektion.

Grundlæggende forespørgsel

Den grundlæggende forespørgsel til at generere den nødvendige DML-kommando kan se sådan ud:

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

Returnerer:

UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
  • Jeg gør brug af "kolonnelistesyntaks stærk> " af UPDATE for at forkorte koden og forenkle opgaven.

  • Jeg forespørger på systemkatalogerne i stedet for informationsskema fordi sidstnævnte, selv om det er standardiseret og garanteret at være bærbart på tværs af større versioner, også er notorisk langsom og nogle gange uhåndterligt. Der er fordele og ulemper, det har vi diskuteret flere gange her på SO. Søg efter nøgleordene for at få flere oplysninger.

  • quote_ident() for kolonnenavnene forhindrer SQL-injektion og er også nødvendig for enhver ikke-standard kolonnenavne.

  • Du forsømte at nævne din Postgres-version. Den samlede funktion string_agg() kræver 9.0+.

Fuld automatisering 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 til:

SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
  • For at gøre funktionen mere praktisk returnerer den information som beskrevet i kommentaren. Mere om opnåelse af resultatstatus i plpgsql i manualen.

  • Jeg bruger variablen _sql at holde forespørgselsstrengen, så jeg kan indsamle antallet af fundne kolonner (col_ct ) i samme forespørgsel.

  • Objektidentifikatortypen regclass er den mest effektive måde til automatisk at undgå SQL-injektion (og rense ikke-standardnavne) for tabelnavnet. Du kan bruge skema-kvalificerede tabelnavne for at undgå uklarheder. Jeg vil råde dig til at gøre det, hvis du har flere skemaer i din db! Flere detaljer i dette relaterede spørgsmål:
    Tabelnavn som en PostgreSQL-funktionsparameter

-> SQLfiddle-demo .



  1. SSL-forbindelsesproblemer mellem go Scratch-beholder og PG-beholder. Hvordan løses?

  2. LibreOffice:'com.mysql.jdbc.driver' kan ikke indlæses

  3. Eksempler på mange-til-mange forhold

  4. Sidste x blogindlæg - men kun én gang pr. bruger