You can get the first part of that done easily like this,
SELECT FORMAT(
E'SELECT %s\nFROM %I.%I.%I;' -- query template
, string_agg( -- generate the select list for query template
FORMAT('count(DISTINCT %I) AS %I', column_name, column_name)
, E',\n\t'
),
table_catalog, -- not strictly required, but future safe
table_schema,
table_name
)
FROM information_schema.columns
WHERE table_name = 'foo'
GROUP BY table_catalog, table_schema, table_name;
This will return a query like this,
SELECT count(DISTINCT column1) AS column1,
count(DISTINCT column2) AS column2,
count(DISTINCT column3) AS column3,
count(DISTINCT column4) AS column4
FROM ecarroll.public.foo;
Which is pretty much what you want, except you need to pivot it.
column1 | column2 | column3 | column4
---------+---------+---------+---------
2 | 3 | 3 | 0
To do that pivot, we can use unnest(ARRAY[cols]) AS col_name
, so we essentially have to generate
- dynamic SQL to do the count()
- wrap that with more dynamic sql to do the pivot.
Like this,
SELECT FORMAT(
$$
SELECT ordinality AS column_number, distinct_values -- the col#, and count
FROM (
SELECT %s -- This was the query we
FROM %I.%I.%I -- used previously
) AS t
CROSS JOIN unnest(ARRAY[%s]) WITH ORDINALITY -- Here we use unnest(array)
AS distinct_values; -- to pivot the table
$$,
string_agg(
FORMAT('count(DISTINCT %I) AS %I', column_name, column_name)
, E',\n\t'
),
table_catalog,
table_schema,
table_name,
string_agg(column_name, ', ')
)
FROM information_schema.columns
WHERE table_name = 'foo'
GROUP BY table_catalog, table_schema, table_name;
That returns a query like this..
SELECT ordinality AS column_number, distinct_values
FROM (
SELECT count(DISTINCT column1) AS column1,
count(DISTINCT column2) AS column2,
count(DISTINCT column3) AS column3,
count(DISTINCT column4) AS column4
FROM ecarroll.public.foo
) AS t
CROSS JOIN unnest(ARRAY[column1, column2, column3, column4]) WITH ORDINALITY
AS distinct_values;
And you can just run \gexec
and you'll get,
column_number | distinct_values
---------------+-----------------
1 | 2
2 | 3
3 | 3
4 | 0
abc
?