简体   繁体   中英

Oracle: Count non-null fields for each column in a table

I need a query to count the total number of non-null values for each column in a table. Since my table has hundreds of columns I'm looking for a solution that only requires me to input the table name.

Perhaps using the result of:

select COLUMN_NAME from ALL_TAB_COLUMNS where TABLE_NAME='ORDERS';

to get the column names and then a subquery to put counts against each column name? The additional complication is that I only have read-only access to the DB so I can't create any temp tables.

Slightly out of my league with this one so any help is appreciated.

Construct the query in SQL or using a spreadsheet. Then run the query.

For instance, assuming that your column names are simple and don't have special characters:

select replace('select ''[col]'', count([col]) from orders union all ',
               '[col]', COLUMN_NAME
              ) as sql
from ALL_TAB_COLUMNS
where TABLE_NAME = 'ORDERS';

(Of course, this can be adapted for more complex column names, but I'm trying to show the idea.)

Then copy the code, remove the final union all and run it.

You can put this in one string if there are not too many columns:

select listagg(replace('select ''[col]'', count([col]) from orders',
                       '[col]', COLUMN_NAME
                      ), ' union all '
               ) within group (order by column_name) as sql
from ALL_TAB_COLUMNS
where TABLE_NAME = 'ORDERS';

You can also use execute immediate using the same query, but that seems like overkill.

If you're happy with the results row-ar rather than column-ar:

SELECT 'SELECT ''dummy'', 0 FROM DUAL' FROM DUAL
UNION ALL 
SELECT 
  ' UNION ALL SELECT ''' || 
  column_name ||
  ''', COUNT(' || 
  column_name || 
  ') FROM ' || 
  TABLE_NAME
FROM 
  all_tab_columns
WHERE 
  table_name = 'ORDERS'

This is an "SQL that writes an SQL" that you can then copy and run to get your answers. Should make a resultset that looks like:

SELECT 'dummy', 0 FROM dual

UNION ALL SELECT 'col1', COUNT(col1) FROM ORDERS

UNION ALL SELECT 'col2', COUNT(col2) FROM ORDERS

...

If you want your results column-ar:

SELECT 'SELECT '
UNION ALL
SELECT 
  'COUNT(' || 
  column_name ||
  ') as count_' || 
  column_name || 
  ', ' || 
  TABLE_NAME
FROM 
  all_tab_columns
WHERE 
  table_name = 'ORDERS'
UNION ALL
SELECT 'null as dummy_column FROM ORDERS'

Should make a resultset that looks like:

SELECT

COUNT(col1) as count_col1,

COUNT(col2) as count_col2,

...

null as dummycoll FROM orders

Caveat: I don't have oracle installed anywhere I can test these, it's written from memory and may need some debugging

This will generate the SQL to get the counts in columns and will handle case sensitive column names and column names with non-alpha-numeric characters:

SELECT 'SELECT '
       || LISTAGG(
         'COUNT("' || column_name || '") AS "' || column_name || '"',
         ', '
       ) WITHIN GROUP ( ORDER BY column_id )
       || ' FROM "' || table_name || '"' AS sql
FROM   ALL_TAB_COLUMNS
WHERE  TABLE_NAME = 'ORDERS'
GROUP BY TABLE_NAME;

or, if you have a large number of columns that is generating a string longer than 4000 characters you can use a custom aggregation function to aggregate VARCHAR2 s into a CLOB and then do:

SELECT 'SELECT '
       || CLOBAgg( 'COUNT("' || column_name || '") AS "' || column_name || '"' )
       || ' FROM "' || table_name || '"' AS sql
FROM   ALL_TAB_COLUMNS
WHERE  TABLE_NAME = 'ORDERS'
GROUP BY TABLE_NAME;

In Oracle 19 (I used similar code in Ora 12, maybe that works too), this works without generating another select to execute:

select * from
(
    select table_name, column_name,
           to_number( extractvalue( xmltype(dbms_xmlgen.getxml('select count(to_char(substr('||column_name||',1,1))) c from '||table_name)) ,'/ROWSET/ROW/C')) count
    from all_tab_columns where owner = user
) 
--where table_name = 'MY_TABLE'
;

It will create XML with count, from which it extracts the current count. The substr and to_char functions here are used to extract first character, so it will works with CLOB columns also

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM