SELECT v.*
FROM (
SELECT count(column_a) AS ct_column_a
, count(column_b) AS ct_column_b
, count(column_c) AS ct_column_c
, count(*)::numeric AS ct
FROM my_table
) sub
, LATERAL (
VALUES
(text 'column_a', ct_column_a, round(ct_column_a/ct, 3))
, (text 'column_b', ct_column_b, round(ct_column_b/ct, 3))
, (text 'column_c', ct_column_c, round(ct_column_c/ct, 3))
) v(field_name, fill_count, fill_percentage);
決定的な「トリック」がここにありますそのcount()
は、最初に0以外の値をカウントするだけで、トリックは必要ありません。
パーセントを3桁の小数点以下に丸めました。これはオプションです。このため私はnumeric
にキャストします。
VALUES
式を使用して、結果をピボット解除し、フィールドごとに1行を取得します。
繰り返し使用する場合や処理する列が長い場合は、クエリを動的に生成して実行することができます。しかし、再び、各列に対して個別のカウントを実行しないでください。ただ、動的上記のクエリを構築する:
CREATE OR REPLACE FUNCTION get_fill_rates(tbl regclass, fields text[])
RETURNS TABLE (field_name text, fill_count bigint, fill_percentage numeric) AS
$func$
BEGIN
RETURN QUERY EXECUTE (
-- RAISE NOTICE '%', ( -- to debug if needed
SELECT
'SELECT v.*
FROM (
SELECT count(*)::numeric AS ct
, ' || string_agg(format('count(%I) AS %I', fld, 'ct_' || fld), ', ') || '
FROM ' || tbl || '
) sub
, LATERAL (
VALUES
(text ' || string_agg(format('%L, %2$I, round(%2$I/ ct, 3))', fld, 'ct_' || fld), ', (') || '
) v(field_name, fill_count, fill_pct)
ORDER BY v.fill_count DESC'
FROM unnest(fields) fld
);
END
$func$ LANGUAGE plpgsql;
コール:あなたが見ることができるように
SELECT * FROM get_fill_rates('my_table', '{column_a, column_b, column_c}');
が、これは今任意の与えられたテーブルと列のリストの作品を。
すべての識別子は、format()
またはregclass
タイプの組み込み機能によって自動的に正しく引用されます。
関連:
あなたの元のクエリを改善することができリクこれは豚の口紅です。 この非効率的なアプローチを使用しないでください。
CREATE OR REPLACE FUNCTION get_fill_rates()
RETURNS TABLE (field_name text, fill_count bigint, fill_percentage float) AS
$$
DECLARE
fields text[] := '{column_a, column_b, column_c}'; -- must be legal identifiers!
total_rows float; -- use float right away
BEGIN
SELECT reltuples INTO total_rows FROM pg_class WHERE relname = 'my_table';
FOREACH field_name IN ARRAY fields -- use FOREACH
LOOP
EXECUTE 'SELECT COUNT(*) FROM big WHERE ' || field_name || ' IS NOT NULL'
INTO fill_count;
fill_percentage := fill_count/total_rows; -- already type float
RETURN NEXT;
END LOOP;
END
$$ LANGUAGE plpgsql;
プラス、pg_class.reltuples
はあくまでも目安です。あなたはとにかく数えているので、実際の数を使用してください。
関連:
たぶん良いアイデアは、識別子、ワイルドカードでのフォーマットを使用しています。それはSQLインジェクションを避けるでしょう。 –