Menemukan kolom kosong dari sebuah tabel di PostgreSQL

17

Kueri apa yang akan mengembalikan nama kolom pada tabel di mana semua baris NULL?

Seb
sumber
Apakah maksud Anda tabel tertentu, atau semua tabel dalam skema?
Jack Douglas
1
Mengapa Anda perlu melakukan itu? Sepertinya Anda memiliki terlalu banyak kolom / tabel dan harus memikirkan kembali desain Anda.
eevar

Jawaban:

13

testbed:

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;

fungsi:

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;$$;

pertanyaan:

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

hasil:

 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)

Selain itu, Anda dapat memperoleh perkiraan jawaban dengan menanyakan katalog - jika null_fracnol yang menunjukkan tidak ada nol tetapi harus diperiksa ulang terhadap data 'nyata':

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)
Jack Douglas
sumber
1
Ini adalah pertanyaan lama, tetapi orang-orang yang menggunakan ekstensi spasial (postgis) harus mencatat bahwa kolom spasial kosong tidak muncul pg_statsjika mereka kosong saat membuat tabel. Saya menemukan ini hari ini ketika melakukan pembersihan. Saya menemukan bahwa beberapa tabel aspatial historis telah diimpor menggunakan ogr2ogr. jika tidak ada kolom spasial dalam data yang diimpor, ogr2ogrbuatlah kolom geometri penuh <NULL>. Saya pg_statstidak memiliki kolom geometri dari tabel aspatial yang diimpor (memiliki semua kolom lain untuk tabel tersebut). Cukup aneh, pikirku.
GT.
6

Di Postgresql, Anda bisa mendapatkan data langsung dari statistik:

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;

Anda mungkin mendapatkan beberapa kesalahan positif, jadi periksa kembali setelah menemukan kandidat.

Denis de Bernardy
sumber
Apakah Anda memerlukan kondisi lain selain null_frac=1?
Jack Douglas
Saya tidak yakin. null_frac mungkin adalah nyata, jadi mungkin itu membulatkan ke 1 dalam beberapa kasus aneh. Tetapi bahkan dengan 1 dari 10k baris, itu akan menghasilkan sesuatu yang cocok.
Denis de Bernardy
1

Saya akan menunjukkan kepada Anda solusi saya dalam T-SQL, bekerja untuk SQL Server 2008. Saya tidak terbiasa dengan PostgreSQL, tapi saya harap Anda akan menemukan beberapa panduan dalam solusi saya.

-- 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);

Singkatnya, yang saya lakukan adalah membuat tabel uji dengan 5 kolom, ID, dan testTime dihasilkan oleh fungsi identitas dan getdate (), sedangkan 3 kolom varchar menjadi yang menarik. Satu hanya akan memiliki nilai NULL, satu tidak akan memiliki NULL, yang lain akan menjadi kolom gabungan. Hasil akhir skrip adalah bahwa skrip akan melaporkan kolom nullColumn sebagai memiliki semua baris NULL.

Idenya adalah untuk menghitung fungsi DATALENGTH untuk setiap kolom (menghitung jumlah byte untuk ekspresi yang diberikan). Jadi saya menghitung nilai DATALENGTH untuk setiap baris setiap kolom dan membuat SUM per kolom. Jika SUM per kolom adalah NULL, maka kolom lengkap memiliki baris NULL, jika tidak ada beberapa data di dalamnya.

Sekarang Anda harus menemukan terjemahan untuk PostgreSQL dan mudah-mudahan seorang kolega akan dapat membantu Anda dengan itu. Atau mungkin ada tampilan sistem yang bagus yang akan menunjukkan betapa bodohnya saya untuk menciptakan kembali roda :-).

Marian
sumber
1

Anda perlu menanyakan katalog informasi untuk informasi tersebut:

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

memberi Anda tabel yang cocok untuk kolom Anda.

Saya tidak memiliki instalasi postgres saat ini, tetapi sisanya harus sederhana

   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
DrColossos
sumber
Ini bekerja, tetapi ini merupakan pendekatan berulang :-). Saya lebih suka pendekatan berbasis set.
Marian
0

Setelah menggabungkan dari beberapa sumber, saya datang dengan fungsi ini dan permintaan untuk menemukan semua kolom kosong di semua tabel 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))

Nikmati :)

obenda
sumber