web-dev-qa-db-ja.com

PostgreSQLでのテーブルの空の列の検索

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

17
Seb

テストベッド:

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)

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;

いくつかの誤検知が発生する可能性があるため、候補を見つけた後、再チェックを行う必要があります。

8

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

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

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

ここで、PostgreSQLの翻訳を見つける必要があります。うまくいけば、同僚がそれを手伝ってくれるでしょう。あるいは、私がホイールを再発明するのがいかに馬鹿であるかを示す、Niceシステムビューがあるかもしれません:-)。

1
Marian

このような情報については、インフォメーションカタログをクエリする必要があります。

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
1
DrColossos

いくつかのリソースから組み合わせた後、私はこの関数とクエリを考え出し、すべてのデータベーステーブルですべての空の列を見つけました

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

楽しい :)

0
obenda