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 .