A maneira mais eficiente de conseguir isso:
- Execute um único
UPDATE
por tabela. - Atualize apenas colunas anuláveis (não definidas
NOT NULL
) com qualquer string vazia real. - Atualize apenas as linhas com qualquer string vazia real.
- Deixe os outros valores inalterados.
Esta resposta relacionada tem uma função plpgsql que cria e executa o
UPDATE
comando usando o catálogo do sistema pg_attribute
automaticamente e com segurança para qualquer tabela:- Substituir strings vazias por valores nulos
Usando a função
f_empty2null()
a partir desta resposta, você pode percorrer as tabelas selecionadas 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! Isso atualiza todas as strings vazias em todas as colunas de todas as tabelas de usuário no banco de dados. Certifique-se de que é isso que você quer ou pode destruir seu banco de dados.
Você precisa de
UPDATE
privilégios em todas as mesas selecionadas, é claro. Como dispositivo de segurança infantil, comentei a carga útil.
Você deve ter notado que eu uso os catálogos do sistema diretamente, não o esquema de informações (o que também funcionaria). Sobre isso:
- Como verificar se uma tabela existe em um determinado esquema
- Consulta para retornar nomes de colunas de saída e tipos de dados de uma consulta, tabela ou visualização
Para uso repetido
Aqui está uma solução integrada para uso repetido. Sem dispositivos de segurança:
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;
Ligar:
SELECT * FROM pg_temp.f_all_empty2null();
Devoluções:
_tables | _rows
---------+---------
23 | 123456
Observação como eu escapei os nomes de tabelas e colunas corretamente!
c.oid::regclass AS tbl, quote_ident(attname) AS col
Considerar:
- Nome da tabela como parâmetro de função do PostgreSQL
Cuidado! Mesmo aviso acima.
Considere também a explicação básica na resposta que vinculei acima:
- Substituir strings vazias por valores nulos