tags:

views:

107

answers:

5

I need to display all tables that have zero records.

I tried,

select * from user_all_tables where (select count(*) from user_all_tables)=0;

But it doesn't seem to work. How should I go about redesigning this query? Thanks.

+4  A: 

If all of your tables are analyzed, you can check the column num_rows of table user_tables.

Otherwise, you will need PL/SQL to make this work. This will output all tables of your current user without records (use all_tables if you need tables of other users):

Set Serveroutput On;

Declare
  cnt PLS_INTEGER;
Begin
  For c In ( Select table_name From user_tables ) Loop
    Execute Immediate 'Select Count(*) From "' || c.table_name || '" where rownum=1'
            Into cnt;
    If( cnt = 0 ) Then
      dbms_output.put_line( c.table_name );
    End If;
  End Loop;
End;
Peter Lang
+1 The clearest solution.
Rob van Wijk
Thanks a lot for the fast reply! :-)
sqlgrasshopper5
-1 for being a very inefficient method. Avoid using count(*) for determining whether or not a table has records.
Rene
@Rene: I admit that I didn't optimize my solution, as I was under the impression that this is not going to be executed regularly. The OP and some others found this answer useful though, so I am surprised by your down-vote. Never mind, `+1` for your answer...
Peter Lang
FTFY. table names are not always necessarily all uppercase and devoid of spaces; added rownum filter so that query execution will stop as soon as a row is found.
Jeffrey Kemp
Ah I wondered what inefficiencies Rene found... but now I see the rownum = 1 predicate was added later. Nice job Jeff. Take a good answer and making it better rather than just downvoting it like Rene. At least Rene provided feedback with the downvote.
Stephanie Page
@Jeffrey Kemp: Thanks for your edit!
Peter Lang
A: 
select TABLE_NAME
from USER_ALL_TABLES
where NUM_ROWS = 0
Cătălin Pitiș
This relies on the statistics being accurate. Which can never be 100% true. At least you don't know for sure.
Rob van Wijk
Thanks! Didn't know about num_rows
sqlgrasshopper5
@Rob van Wijk: How is that calculated then?. It won't work all the time then?
sqlgrasshopper5
The num_rows column is updated when statistics are being gathered for the table. Look at the dbms_stats package for how this is done. Typically this is done once per night/week/month and only when sufficient data has been altered.
Rob van Wijk
+2  A: 

You'd have to resort to PL/SQL and issue a select count(*) for every table. Or you can use dbms_xmlgen to do this for you in a tricky way:

select table_name
  from ( select table_name
              , extractvalue
                ( dbms_xmlgen.getxmltype('select count(*) c from '|| table_name)
                , '/ROWSET/ROW/C'
                ) cnt
              , rownum to_prevent_predicate_push
           from user_tables
       )
 where cnt = '0'

Regards, Rob.

Rob van Wijk
Now that's some heavy stuff :) `+1`
Peter Lang
Pwning the newbies like me? ;-)
sqlgrasshopper5
+1  A: 

Variation of the accepted answer but using a more efficient method.

Declare
  cnt PLS_INTEGER;
Begin
  For c In ( Select table_name From user_tables ) Loop
    begin
       Execute Immediate 'Select 1 From dual where exists (select 1 from ' || c.table_name ||')' Into cnt;
    exception when no_data_found then
      dbms_output.put_line( c.table_name );
    end;  
  End Loop;
End;
Rene
A: 

This answer is one Fetch-per-table more efficient than Rene's. SELECT INTO requires an Extra Fetch to see if the "TOO_MANY_ROWS" exception should be raised. We can take control of that process with an explicit cursor and NOT doing an unnecessary extra fetch.

Declare
  cnt PLS_INTEGER;
  s_Cur Varchar2(255);
  c_Cur Sys_refcursor;
Begin
   For c In ( Select table_name From user_tables ) Loop

      s_Cur := 'Select 1  From dual where exists (select 1 from ' || c.table_name ||')';    

      Open c_Cur For s_cur ;
      Fetch c_cur into cnt;        
      If c_cur%NOTFOUND then 
          dbms_output.put_line( c.table_name );
      end if;

   End Loop;
End;
Stephanie Page
slightly better would be to select the table name form dual... that way at least you end up with a list of tables.
Randy