sql >> Databasteknik >  >> RDS >> PostgreSQL

Sätt tomma strängar ('') till NULL i hela databasen

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


  1. 11 sätt att hämta en primärnyckel i SQL Server (T-SQL-exempel)

  2. Köra ett .sql-skript med MySQL med JDBC

  3. 10 anledningar till att ditt företag behöver Microsoft Access

  4. En första titt på den nya SQL Server Cardinality Estimator