PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Atualizar várias colunas que começam com uma string específica


Você precisa de SQL dinâmico para isso. Portanto, você deve estar preparado para lidar com uma possível injeção de SQL.

Consulta básica


A consulta básica para gerar o comando DML necessário pode ser assim:
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_%';

Devoluções:
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);

  • Eu uso a "sintaxe de lista de colunas " de UPDATE para encurtar o código e simplificar a tarefa.

  • Eu consulto os catálogos do sistema em vez de esquema de informações porque o último, embora seja padronizado e garantido para ser portátil nas principais versões, também é notoriamente lento e às vezes difícil de manejar. Existem prós e contras, já discutimos isso várias vezes aqui no SO. Pesquise as palavras-chave para obter mais informações.

  • quote_ident() para os nomes das colunas impede a injeção de SQL e também é necessário para qualquer nomes de colunas não padrão.

  • Você esqueceu de mencionar sua versão do Postgres. A função agregada string_agg() requer 9.0+.

Automação total com função 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.';

Ligar:
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');

  • Para tornar a função mais prática, ela retorna as informações conforme descrito no comentário. Mais sobre como obter o status do resultado em plpgsql no manual.

  • Eu uso a variável _sql para manter a string de consulta, para que eu possa coletar o número de colunas encontradas (col_ct ) na mesma consulta.

  • O tipo de identificador de objeto regclass é a maneira mais eficiente de evitar automaticamente a injeção de SQL (e limpar nomes não padrão) para o nome da tabela também. Você pode usar nomes de tabela qualificados por esquema para evitar ambiguidades. Eu aconselharia fazer isso se você tiver vários esquemas em seu banco de dados! Mais detalhes nesta pergunta relacionada:
    Nome da tabela como parâmetro de função do PostgreSQL

-> Demonstração do SQLfiddle .