Search code examples
oracle-databaseoracle-sqldeveloperoracle12c

List all tables,numrows,numcol and primary key for table if any in oracle


I want to QUERY to generate a table like below:

Tablename||noofrows||noofcolumns||PRIMARKEYCOL(IF ANY for the table)
xyz.       590.         11.           xyz_id
bcd.       934          15            null
...
...

So far I was able to do this until now in 2 query:

Query 1:

select a.table_name,count_rows(a.table_name) total_rows,count(b.column_name) total_cols from user_tables a,
     ,user_tab_columns b
where a.table_name =b.table_name 
and a.table_name not like('amp%')
group by a.table_name;

note:Count_rows() is function to calculate rows as stats are not up to date

query 2:

select b.table_name b.column_name PRIMKEY_COL FROM user_constraints a,user_cons_columns b
where 
a.constraint_type = 'P'
and a.constraint_name=b.constraint_name 
and a.table_name=b.table_name
and b.table_name not like ('amp%');

Problem

I need to merge this table to one query (as shown in example above) so that I can represent the data in one table. My issue in clubbing the table is, with joins and how to make sure table without any primary keys are represent because if I just directly give constraint type ='p' in the where clause of the join I see that it only shows table with Primarykeys I am not able to figure this out.


Solution

  • Primary key can have more than just a single column, so - if you'd want to return them all, you'd either have to "aggregate" them, somehow (listagg looks like a natural choice, but - in 12c - you can't fetch distinct list of columns which you might need because of joining those tables duplicates appear).

    As you already use a function to return number of rows (you'd probably rather regularly collect statistics, though, but yes - if tables are frequently modified (inserts and deletes), counting on-the-fly is the way to go.

    So, alternative approach with 2 functions and 1 simple query. Yes, I know - context switching and stuff, but - see if it does any good.

    This is what you already have (see if your and my code look similar):

    SQL> create or replace function count_rows (par_table_name in varchar2)
      2    return number
      3  is
      4    -- return number of rows in PAR_TABLE_NAME
      5    retval number;
      6  begin
      7    execute immediate 'select count(*) from ' ||
      8      dbms_assert.sql_object_name(par_table_name) into retval;
      9    return retval;
     10  end;
     11  /
    
    Function created.
    

    This is new (to simplify fetching distinct list of primary key columns):

    SQL> create or replace function pk_cols (par_table_name in varchar2)
      2    return varchar2
      3  is
      4    -- return list of primary key columns for PAR_TABLE_NAME, sorted by column's
      5    -- position within the primary key constraint
      6    retval varchar2(100);
      7  begin
      8    select listagg(b.column_name, ', ') within group (order by b.position)
      9      into retval
     10      from user_constraints a join user_cons_columns b on b.constraint_name = a.constraint_name
     11      where upper(a.table_name) = dbms_assert.sql_object_name(upper(par_table_name))
     12        and a.constraint_type = 'P';
     13    return retval;
     14  end;
     15  /
    
    Function created.
    

    Finally, that simple query I mentioned:

    SQL> select a.table_name,
      2         count_rows(a.table_name) total_rows,
      3         max(a.column_id) total_cols,
      4         pk_cols(a.table_name) primkey_cols
      5  from user_tab_columns a
      6  group by a.table_name;
    
    TABLE_NAME      TOTAL_ROWS TOTAL_COLS PRIMKEY_COLS
    --------------- ---------- ---------- -------------------------
    DEPT                     4          3 DEPTNO
    SO_TEST                  0          1
    TEST                     7          3 ORD, TERMREGIONAL
    EMP                     14          8 EMPNO
    TRAINING                 0          5 TRAINING_PLACE_ID
    TEMP_SE                 10          3
    <snip>