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

Establecer cadenas vacías ('') en NULL en toda la base de datos

La forma más eficiente de lograr esto:

  • Ejecute una única UPDATE por mesa.
  • Solo actualizar columnas anulables (no definidas NOT NULL ) con cualquier cadena vacía real.
  • Solo actualice las filas con cualquier cadena vacía real.
  • Deje los demás valores sin cambios.

Esta respuesta relacionada tiene una función plpgsql que compila y ejecuta UPDATE comando usando el catálogo del sistema pg_attribute de forma automática y segura para cualquier tabla dada:

  • Reemplazar cadenas vacías con valores nulos

Usando la función f_empty2null() a partir de esta respuesta, puede recorrer tablas seleccionadas como esta:

DO
$do$
DECLARE
   _tbl regclass;
BEGIN
   FOR _tbl IN
      SELECT c.oid::regclass
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relkind = 'r'            -- only regular tables
      AND    n.nspname NOT LIKE 'pg_%'  -- exclude system schemas
   LOOP
      RAISE NOTICE $$PERFORM f_empty2null('%');$$, _tbl;
      -- PERFORM f_empty2null(_tbl);  -- uncomment to prime the bomb
   END LOOP;
END
$do$;

¡Cuidado! Esto actualiza todas las cadenas vacías en todas las columnas de todas las tablas de usuarios en la base de datos. Asegúrese de que eso es lo que quiere o podría destruir su base de datos.

Necesitas UPDATE privilegios en todas las mesas seleccionadas, por supuesto.

Como dispositivo de seguridad para niños, comenté la carga útil.

Es posible que haya notado que uso los catálogos del sistema directamente, no el esquema de información (que también funcionaría). Sobre esto:

  • Cómo verificar si una tabla existe en un esquema dado
  • Consulta para devolver nombres de columnas de salida y tipos de datos de una consulta, tabla o vista

Para uso repetido

Aquí hay una solución integrada para uso repetido. Sin dispositivos de seguridad:

CREATE OR REPLACE FUNCTION f_all_empty2null(OUT _tables int, OUT _rows int) AS
$func$
DECLARE
   _typ CONSTANT regtype[] := '{text, bpchar, varchar, \"char\"}';
   _sql text;
   _row_ct int;
BEGIN
   _tables := 0;  _rows := 0;
   FOR _sql IN
      SELECT format('UPDATE %s SET %s WHERE %s'
                  , t.tbl
                  , string_agg(format($$%1$s = NULLIF(%1$s, '')$$, t.col), ', ')
                  , string_agg(t.col || $$ = ''$$, ' OR '))
      FROM  (
         SELECT c.oid::regclass AS tbl, quote_ident(attname) AS col
         FROM   pg_namespace n
         JOIN   pg_class     c ON c.relnamespace = n.oid
         JOIN   pg_attribute a ON a.attrelid = c.oid
         WHERE  n.nspname NOT LIKE 'pg_%'   -- exclude system schemas
         AND    c.relkind = 'r'             -- only regular tables
         AND    a.attnum >= 1               -- exclude tableoid & friends
         AND    NOT a.attisdropped          -- exclude dropped columns
         AND    NOT a.attnotnull            -- exclude columns defined NOT NULL!
         AND    a.atttypid = ANY(_typ)      -- only character types
         ORDER  BY a.attnum
         ) t
      GROUP  BY t.tbl
   LOOP
      EXECUTE _sql;
      GET DIAGNOSTICS _row_ct = ROW_COUNT;  -- report nr. of affected rows
      _tables := _tables + 1;
      _rows := _rows + _row_ct;
   END LOOP;
END
$func$  LANGUAGE plpgsql;

Llamar:

SELECT * FROM pg_temp.f_all_empty2null();

Devoluciones:

 _tables | _rows
---------+---------
 23      | 123456

Nota ¡cómo escapé correctamente de los nombres de las tablas y las columnas!

c.oid::regclass AS tbl, quote_ident(attname)  AS col

Considere:

  • Nombre de tabla como parámetro de función de PostgreSQL

¡Cuidado! La misma advertencia que la anterior.
También considere la explicación básica en la respuesta que vinculé anteriormente:

  • Reemplazar cadenas vacías con valores nulos