PostgreSQLでテーブルの空の列を見つける


17

すべての行がNULLであるテーブルの列の名前を返すクエリは何ですか?


特定のテーブル、またはスキーマ内のすべてのテーブルを意味しますか?
ジャックダグラス

1
なぜあなたはそれをする必要があるのですか?列/テーブルが多すぎるように聞こえますが、設計を再考する必要があります。
eevar

回答:


13

テストベッド:

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;

関数:

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

クエリ:

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

結果:

 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)

さらに、カタログを照会することにより、おおよその答えを得ることができます- null_fracゼロの場合、nullがないことを示しますが、「実際の」データに対してダブルチェックする必要があります。

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
これは非常に古い質問ですが、空間拡張(postgis)を使用する人pg_statsは、テーブル作成時に空の空間列が表示されないことに注意してください。今日、ハウスキーピングをするときにこれを見つけました。を使用して、いくつかの歴史的な空間テーブルがインポートされたことを発見しましたogr2ogr。インポートされるデータに空間列がない場合、でogr2ogrいっぱいのジオメトリ列を作成します<NULL>。Myにpg_statsは、インポートされた空間テーブルのジオメトリ列がありません(これらのテーブルの他のすべての列があります)。かなり奇妙だと思った。
GT。

6

Postgresqlでは、統計から直接データを取得できます。

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;

いくつかの誤検知が発生する可能性があるため、候補を見つけた後、再チェックが適切に行われます。


以外の条件が必要null_frac=1ですか?
ジャックダグラス

よく分かりません。null_fracはおそらく実数なので、奇妙な場合には1に丸められる可能性があります。しかし、1万行のうち1行であっても、適切なものになります。
デニスドバーナルディ

1

私は、SQL Server 2008で動作するT-SQLでのソリューションを紹介します。PostgreSQLに精通していませんが、私のソリューションにガイダンスが見つかることを願っています。

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

要するに、IDとgetdate()関数によって生成されるIDとtestTimeの5つの列を持つテストテーブルを作成し、3つのvarchar列が対象の列であるということです。1つはNULL値のみ、1つはNULL値を持たず、もう1つは結合列になります。スクリプトの最終結果は、すべての行がNULLであるとして列nullColumnをレポートすることです。

アイデアは、各列の関数DATALENGTHを計算することでした(特定の式のバイト数を計算します)。そこで、各列の各行のDATALENGTH値を計算し、列ごとにSUMを作成しました。列ごとのSUMがNULLの場合、完全な列にはNULL行が含まれます。それ以外の場合は、内部にデータがあります。

今、あなたはPostgreSQLの翻訳を見つけなければなりません、そして、うまくいけば、同僚がそれであなたを助けることができるでしょう。または、車輪を再発明するのがいかに愚かかを示す素晴らしいシステムビューがあるかもしれません:-)。


1

そのような情報については、情報カタログを照会する必要があります。

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

列に一致するテーブルを提供します。

現在、postgresのインストールはありませんが、残りは簡単です

   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

これは機能していますが、反復的なアプローチです:-)。セットベースのアプローチが好きです。
マリアン

0

複数のリソースを組み合わせた後、この関数とクエリを使用して、すべてのデータベーステーブルのすべての空の列を見つけました。

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

楽しい :)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.