Si vous êtes d'accord avec une ligne d'ensemble de résultats par colonne, vous pouvez adapter ce tour de magie XML :
select owner, table_name, column_name,
to_number(xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml(
'select count(distinct "' || column_name || '") as c '
|| 'from "' || owner || '"."' || table_name || '"'))
returning content)) as c
from all_tab_columns
where owner = '<your table owner>'
and data_type in ('NUMBER', 'DATE', 'TIMESTAMP', 'CHAR', 'VARCHAR2', 'NCHAR', 'NVARCHAR2');
... répertoriant tous les types de données dont vous avez besoin pour pouvoir compter ; c'est vraiment pour exclure ceux qui ne peuvent pas gérer distinct
comme CLOB, mais comme vous pouvez avoir des tables imbriquées, etc., il sera probablement plus simple de lister celles que vous faites veulent et s'attendent à pouvoir compter.
Le dbms_xmlgen()
call convertit le résultat de ce select count(distinct ...) ...
requête, qui est effectivement construite dynamiquement, dans une structure XML, et vous pouvez ensuite en extraire le décompte avec XMLQuery()
(au lieu de l'obsolète extractvalue()
dans la réponse liée).
En guise de démo très rapide :
create table t42 (id number, str varchar2(20));
insert into t42 values (1, 'Test');
insert into t42 values (2, 'Test');
insert into t42 values (3, 'Test 2');
insert into t42 values (3, null);
select owner, table_name, column_name,
to_number(xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml(
'select count(distinct "' || column_name || '") as c '
|| 'from "' || owner || '"."' || table_name || '"'))
returning content)) as c
from all_tab_columns
where owner = 'MY_SCHEMA'
and table_name = 'T42'
and data_type in ('NUMBER', 'DATE', 'TIMESTAMP', 'CHAR', 'VARCHAR2', 'NCHAR', 'NVARCHAR2');
OWNER TABLE_NAME COLUMN_NAME C
--------------- --------------- --------------- ----------
MY_SCHEMA T42 ID 3
MY_SCHEMA T42 STR 2
Le count()
la fonction ignore les valeurs nulles, donc pour compter celles-ci, vous devez les convertir, par ex. avec
count(case when <your_column> is null then 1 end)
Vous pouvez l'inclure ici soit avec une seconde clause XMLQuery :
select owner, table_name, column_name,
to_number(xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml(
'select count(distinct "' || column_name || '") as c '
|| 'from "' || owner || '"."' || table_name || '"'))
returning content)) as distinct_count,
to_number(xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml(
'select count(case when "' || column_name || '" is null then 1 end) as c '
|| 'from "' || owner || '"."' || table_name || '"'))
returning content)) as null_count
from all_tab_columns
where owner = 'MY_SCHEMA'
and table_name = 'T42'
and data_type in ('NUMBER', 'DATE', 'TIMESTAMP', 'CHAR', 'VARCHAR2',
'NCHAR', 'NVARCHAR2');
OWNER TABLE_NAME COLUMN_NAME DISTINCT_COUNT NULL_COUNT
--------------- --------------- --------------- -------------- ----------
MY_SCHEMA T42 ID 3 0
MY_SCHEMA T42 STR 2 1
ou avec un seul XMLTable qui extrait les valeurs des deux colonnes du XML généré, qui est modifié pour faire les deux comptages à la fois :
select a.owner, a.table_name, a.column_name,
x.distinct_count, x.null_count
from
(
select owner, table_name, column_name,
dbms_xmlgen.getxml(
'select count(distinct "' || column_name || '") as c1,'
|| 'count(case when "' || column_name || '" is null then 1 end) as c2 '
|| 'from "' || owner || '"."' || table_name || '"') as xml_clob
from all_tab_columns
where owner = 'MY_SCHEMA'
and table_name = 'T42'
and data_type in ('NUMBER', 'DATE', 'TIMESTAMP', 'CHAR', 'VARCHAR2',
'NCHAR', 'NVARCHAR2')
) a
cross join xmltable (
'/ROWSET/ROW'
passing xmltype(a.xml_clob)
columns distinct_count number path 'C1',
null_count number path 'C2'
) x;
OWNER TABLE_NAME COLUMN_NAME DISTINCT_COUNT NULL_COUNT
--------------- --------------- --------------- -------------- ----------
MY_SCHEMA T42 ID 3 0
MY_SCHEMA T42 STR 2 1