Jakie zapytanie zwróciłoby nazwę kolumn tabeli, w której wszystkie wiersze mają wartość NULL?
Jakie zapytanie zwróciłoby nazwę kolumn tabeli, w której wszystkie wiersze mają wartość NULL?
Odpowiedzi:
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;
funkcjonować:
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;$$;
pytanie:
select table_schema, table_name, column_name,
has_nonnulls(table_schema, table_name, column_name)
from information_schema.columns
where table_schema='stack';
wynik:
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)
Ponadto można uzyskać przybliżoną odpowiedź, przeszukując katalog - jeśli null_frac
zero oznacza brak wartości zerowych, ale należy je dwukrotnie sprawdzić w stosunku do „rzeczywistych” danych:
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)
pg_stats
jeśli są puste przy tworzeniu tabeli. Dowiedziałem się tego dzisiaj, kiedy robiłem porządki. Odkryłem, że niektóre historyczne aspatial stoły zostały przywiezione użyciu ogr2ogr
. jeśli w importowanych danych nie ma kolumny przestrzennej, ogr2ogr
tworzona jest kolumna geometrii pełna <NULL>
. Mój pg_stats
nie ma żadnych kolumn geometrii z zaimportowanych tabel przestrzennych (ma wszystkie pozostałe kolumny dla tych tabel). Całkiem dziwne, pomyślałem.
W Postgresql możesz uzyskać dane bezpośrednio ze statystyk:
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;
Możesz otrzymać kilka fałszywych wyników pozytywnych, więc po znalezieniu kandydatów należy ponownie sprawdzić.
null_frac=1
?
Pokażę ci moje rozwiązanie w T-SQL, pracujące dla SQL Server 2008. Nie znam PostgreSQL, ale mam nadzieję, że znajdziesz wskazówki w moim rozwiązaniu.
-- 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);
Krótko mówiąc, stworzyłem tabelę testową z 5 kolumnami, ID i testTime generowanymi przez funkcje identyczności i getdate (), podczas gdy interesujące są 3 kolumny varchar. Jeden będzie miał tylko wartości NULL, jeden nie będzie miał żadnych NULL, drugi będzie połączoną kolumną. Ostatecznym rezultatem skryptu będzie to, że skrypt zgłosi kolumnę nullColumn jako zawierającą wszystkie wiersze NULL.
Chodziło o obliczenie funkcji DATALENGTH dla każdej kolumny (oblicza liczbę bajtów dla danego wyrażenia). Więc obliczyłem wartość DATALENGTH dla każdego wiersza każdej kolumny i stworzyłem SUMA na kolumnę. Jeśli SUMA na kolumnę ma wartość NULL, wówczas cała kolumna ma NULL wierszy, w przeciwnym razie wewnątrz są pewne dane.
Teraz musisz znaleźć tłumaczenie PostgreSQL i mam nadzieję, że kolega będzie w stanie Ci w tym pomóc. A może jest ładny widok systemu, który pokaże, jak głupi jestem na nowo opracowując koło :-).
Aby uzyskać takie informacje, należy przeszukać katalog informacyjny:
SELECT column_name FROM information_schema.columns WHERE table_name='your_table'
daje pasujące tabele dla twoich kolumn.
Nie mam pod ręką instalacji Postgres, ale reszta powinna być prosta
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
Po połączeniu z kilku zasobów wymyśliłem tę funkcję i zapytanie, aby znaleźć wszystkie puste kolumny we wszystkich tabelach bazy danych
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))
Cieszyć się :)