Det mest effektiva sättet att uppnå detta:
- Kör en enda
UPDATE
per bord. - Uppdatera endast nollbara kolumner (ej definierad
NOT NULL
) med någon faktisk tom sträng. - Uppdatera endast rader med en faktisk tom sträng.
- Lämna andra värden oförändrade.
Det här relaterade svaret har en plpgsql-funktion som bygger och kör UPDATE
kommando med systemkatalogen pg_attribute
automatiskt och säkert för ett givet bord:
- Ersätt tomma strängar med nollvärden
Använder funktionen f_empty2null()
från det här svaret kan du gå igenom valda tabeller så här:
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$;
Försiktigt! Detta uppdaterar alla tomma strängar i alla kolumner i alla användartabeller i DB. Se till att det är vad du vill, annars kan det skada din databas.
Du behöver UPDATE
privilegier på alla valda tabeller, naturligtvis.
Som en barnsäkerhetsanordning kommenterade jag nyttolasten.
Du kanske har noterat att jag använder systemkatalogerna direkt, inte informationsschemat (vilket också skulle fungera). Om detta:
- Hur man kontrollerar om en tabell finns i ett givet schema
- Fråga för att returnera utdatakolumnnamn och datatyper för en fråga, tabell eller vy
För upprepad användning
Här är en integrerad lösning för upprepad användning. Utan säkerhetsanordningar:
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;
Ring:
SELECT * FROM pg_temp.f_all_empty2null();
Returnerar:
_tables | _rows
---------+---------
23 | 123456
Obs hur jag slapp både tabell- och kolumnnamn ordentligt!
c.oid::regclass AS tbl, quote_ident(attname) AS col
Tänk på:
- Tabellnamn som en PostgreSQL-funktionsparameter
Försiktigt! Samma varning som ovan.
Tänk även på den grundläggande förklaringen i svaret jag länkade ovan:
- Ersätt tomma strängar med nollvärden