Trovare colonne vuote di una tabella in PostgreSQL


17

Quale query restituirebbe il nome delle colonne di una tabella in cui tutte le righe sono NULL?


Intendi una tabella particolare o tutte le tabelle in uno schema?
Jack Douglas,

1
Perché dovresti farlo? Sembra che tu abbia troppe colonne / tabelle e dovresti ripensare il tuo design.
eevar

Risposte:


13

banco di prova:

create role stack;
create schema authorization stack;
set role stack;

create table my_table as 
select generate_series(0,9) as id, 1 as val1, null::integer as val2;

create table my_table2 as 
select generate_series(0,9) as id, 1 as val1, null::integer as val2, 3 as val3;

funzione:

create function has_nonnulls(p_schema in text, p_table in text, p_column in text)
                returns boolean language plpgsql as $$
declare 
  b boolean;
begin
  execute 'select exists(select * from '||
          p_table||' where '||p_column||' is not null)' into b;
  return b;
end;$$;

query:

select table_schema, table_name, column_name, 
       has_nonnulls(table_schema, table_name, column_name)
from information_schema.columns
where table_schema='stack';

risultato:

 table_schema | table_name | column_name | has_nonnulls
--------------+------------+-------------+--------------
 stack        | my_table   | id          | t
 stack        | my_table   | val1        | t
 stack        | my_table   | val2        | f
 stack        | my_table2  | id          | t
 stack        | my_table2  | val1        | t
 stack        | my_table2  | val2        | f
 stack        | my_table2  | val3        | t
(7 rows)

Inoltre, puoi ottenere una risposta approssimativa eseguendo una query sul catalogo - se null_fracè zero che non indica valori nulli ma deve essere verificato due volte rispetto ai dati "reali":

select tablename, attname, null_frac from pg_stats where schemaname='stack';

 tablename | attname | null_frac
-----------+---------+-----------
 my_table  | id      |         0
 my_table  | val1    |         0
 my_table  | val2    |         1
 my_table2 | id      |         0
 my_table2 | val1    |         0
 my_table2 | val2    |         1
 my_table2 | val3    |         0
(7 rows)

1
Questa è una vecchia domanda, ma le persone che usano estensioni spaziali (postgis) dovrebbero notare che le colonne spaziali vuote non compaiono pg_statsse sono vuote durante la creazione della tabella. L'ho scoperto oggi mentre facevo le pulizie. Ho scoperto che alcune tabelle aspatiali storiche erano state importate usando ogr2ogr. se non ci sono colonne spaziali nei dati importati, ogr2ogrcrea una colonna geometrica piena di <NULL>. My pg_statsnon ha colonne geometriche dalle tabelle aspatiali importate (ha tutte le altre colonne per quelle tabelle). Abbastanza strano, ho pensato.
GT.

6

In Postgresql, puoi ottenere i dati direttamente dalle statistiche:

vacuum analyze; -- if needed

select schemaname, tablename, attname
from pg_stats
where most_common_vals is null
and most_common_freqs is null
and histogram_bounds is null
and correlation is null
and null_frac = 1;

Potresti ottenere alcuni falsi positivi, quindi un nuovo controllo è in ordine dopo aver trovato i candidati.


Hai bisogno di altre condizioni oltre null_frac=1?
Jack Douglas,

Non ne sono sicuro. null_frac è presumibilmente un valore reale, quindi potrebbe essere arrotondato a 1 in alcuni casi dispari. Ma anche con 1 su 10k righe, si tradurrebbe in qualcosa che si adatta.
Denis de Bernardy,

1

Ti mostrerò la mia soluzione in T-SQL, funzionante per SQL Server 2008. Non ho familiarità con PostgreSQL, ma spero che troverai qualche consiglio nella mia soluzione.

-- create test table
IF object_id ('dbo.TestTable') is not null
    DROP table testTable
go
create table testTable (
    id int identity primary key clustered,
    nullColumn varchar(100) NULL,
    notNullColumn varchar(100) not null,
    combinedColumn varchar(100) NULL,
    testTime datetime default getdate()
);
go

-- insert test data:
INSERT INTO testTable(nullColumn, notNullColumn, combinedColumn)
SELECT NULL, 'Test', 'Combination'
from sys.objects
union all
SELECT NULL, 'Test2', NULL
from sys.objects

select *
from testTable

-- FIXED SCRIPT FOR KNOWN TABLE (known structure) - find all completely NULL columns
select sum(datalength(id)) as SumColLength,
    'id' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(nullColumn)) as SumColLength,
    'nullColumn' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(notNullColumn)) as SumColLength,
    'notNullColumn' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(combinedColumn)) as SumColLength,
    'combinedColumn' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(testTime)) as SumColLength,
    'testTime' as ColumnName
from dbo.testTable

-- DYNAMIC SCRIPT (unknown structure) - find all completely NULL columns
declare @sql varchar(max) = '', @tableName sysname = 'testTable';

SELECT @sql +=
        'select sum(datalength(' + c.COLUMN_NAME + ')) as SumColLength,
    ''' + c.COLUMN_NAME + ''' as ColumnName
from ' + c.TABLE_SCHEMA + '.' + c.TABLE_NAME --as StatementToExecute
+ '
UNION ALL
'
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME = @tableName;

SET @sql = left(@sql, len(@sql)-11)
print @sql;
exec (@sql);

In breve, quello che ho fatto è stato creare una tabella di test con 5 colonne, ID e testTime generati dalla funzione identity e getdate (), mentre le 3 colonne varchar sono quelle di interesse. Uno avrà solo valori NULL, uno non avrà alcun NULL, l'altro sarà una colonna combinata. Il risultato finale dello script sarà che lo script riporterà la colonna nullColumn come avere tutte le righe NULL.

L'idea era di calcolare la funzione DATALENGTH per ogni colonna (calcola il numero di byte per una determinata espressione). Quindi ho calcolato il valore DATALENGTH per ogni riga di ogni colonna e ho fatto una SOMMA per colonna. Se la SOMMA per colonna è NULL, la colonna completa ha righe NULL, altrimenti all'interno sono presenti alcuni dati.

Ora devi trovare la traduzione per PostgreSQL e spero che un collega possa aiutarti. O forse c'è una bella vista del sistema che mostrerà quanto sono stupido per reinventare la ruota :-).


1

È necessario interrogare il catalogo delle informazioni per tali informazioni:

SELECT column_name FROM information_schema.columns WHERE table_name='your_table'

ti dà le tabelle corrispondenti per le tue colonne.

Al momento non ho un'installazione di Postgres, ma il resto dovrebbe essere semplice

   loop over the results of the above query and foreach result
        send a COUNT(*) to the table
        if the count is null, give back the column,
                 else ignore it
   end foreach

Funziona, ma è un approccio iterativo :-). Preferisco l'approccio basato sul set.
Marian,

0

Dopo aver combinato da diverse risorse, ho trovato questa funzione e una query per trovare tutte le colonne vuote in tutte le tabelle del database

CREATE OR REPLACE FUNCTION public.isEmptyColumn(IN table_name varchar, IN column_name varchar)
RETURNS boolean AS $$
declare 
    count integer;
BEGIN
    execute FORMAT('SELECT COUNT(*) from %s WHERE %s IS NOT NULL', table_name, quote_ident(column_name)) into count;
    RETURN (count = 0);
END; $$
LANGUAGE PLPGSQL; 


SELECT s.table_name, s.column_name
FROM information_schema.columns s
WHERE (s.table_schema LIKE 'public') AND
      (s.table_name NOT LIKE 'pg_%') AND
      (public.isEmptyColumn(s.table_name, s.column_name))

Godere :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.