sql >> Base de Datos >  >> RDS >> PostgreSQL

Actualice varias columnas que comienzan con una cadena específica

Necesita SQL dinámico para esto. Por lo tanto, debe estar preparado para lidiar con una posible inyección SQL.

Consulta básica

La consulta básica para generar el comando DML necesario puede verse así:

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

Devoluciones:

UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
  • Uso la "sintaxis de lista de columnas " de UPDATE para acortar el código y simplificar la tarea.

  • Consulto los catálogos del sistema en lugar de esquema de información porque este último, si bien está estandarizado y garantizado para ser portátil en las principales versiones, también es notoriamente lento y, a veces, difícil de manejar. Hay pros y contras, lo hemos discutido varias veces aquí en SO. Busque las palabras clave para obtener más información.

  • quote_ident() para los nombres de columna evita la inyección de SQL y también es necesario para any nombres de columna no estándar.

  • Se olvidó de mencionar su versión de Postgres. La función agregada string_agg() requiere 9.0+.

Automatización completa con función 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.';

Llamar:

SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
  • Para que la función sea más práctica, devuelve información como se describe en el comentario. Más información sobre obtención del estado del resultado en plpgsql en el manual.

  • Yo uso la variable _sql para contener la cadena de consulta, de modo que pueda recopilar la cantidad de columnas encontradas (col_ct ) en la misma consulta.

  • El tipo de identificador de objeto regclass es la forma más eficiente de evitar automáticamente la inyección de SQL (y desinfectar los nombres no estándar) para el nombre de la tabla también. Puede usar nombres de tabla calificados por esquema para evitar ambigüedades. ¡Le aconsejaría hacerlo si tiene múltiples esquemas en su base de datos! Más detalles en esta pregunta relacionada:
    Nombre de tabla como parámetro de función de PostgreSQL

-> demostración de SQLfiddle .