Row count of all tables in a schema - oracle

DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name
, user
from user_tables
where lower(user) = 'schema_name'
;
BEGIN
OPEN get_tables;
LOOP
FETCH get_tables
INTO v_table_name
, v_owner
;
EXIT WHEN get_tables%NOTFOUND;
EXECUTE IMMEDIATE
'INSERT
INTO STATS_TABLE
( TABLE_NAME
, SCHEMA_NAME
, RECORD_COUNT
, CREATED
)
SELECT '''
|| v_table_name
|| ''' , ''' || v_owner
|| ''' , COUNT(*)
, TO_DATE(SYSDATE,''DD-MON-YY'')
FROM ' || v_table_name
;
END LOOP;
CLOSE get_tables;
END;
I am using this to get row counts of all tables in a schema. I got this query from stackoverflow.
I ran this as a procedure its successfully compiled but i am unable to view the result y is it so?
I am new to pl/sql can anyone explain what does the select statement do after the excute immediate query I am unable to understand the logic behind.

Try this:
select TABLE_NAME, NUM_ROWS from dba_tables where owner = 'xxxxx'

You can simply get row count against tables by:
select owner, table_name, nvl(num_rows,-1)
from all_tables
order by nvl(num_rows,-1) desc
https://livesql.oracle.com/apex/livesql/file/content_EPJLBHYMPOPAGL9PQAV7XH14Q.html

The row counts are inserted into a table name STATS_TABLE. You need to run a
select *
from stats_table
after running the procedure

This procedure is running successfully
DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name, user
from user_tables
where lower(user) = 'coreown' ;
BEGIN
OPEN get_tables;
LOOP
FETCH get_tables
INTO v_table_name, v_owner;
EXIT WHEN get_tables%NOTFOUND;
EXECUTE IMMEDIATE 'INSERT
INTO STATS_TABLE
( TABLE_NAME
, SCHEMA_NAME
, RECORD_COUNT
, CREATED
)
SELECT ''' || v_table_name ||
''' , ''' || v_owner || ''' , COUNT(*)
, TO_DATE(SYSDATE,''DD-MON-YY'')
FROM ' || v_table_name;
END LOOP;
CLOSE get_tables;
END;
/
I tried at my end.
After executing USE COMMIT.So that it will save the change is DB.
Then check again.

Well, user_tables does not have a user column, so that query is invalid. Always test the queries in isolation -- you probably want all_tables or dba_tables. Also, do you think you need a DISTINCT on that query?
Use an implicit cursor instead of an explicit one wherever you can -- less code, less error prone in coding, and faster.
Do not store dates as character types -- you just insert sysdate, not a representation of it as a string.
Don't prefix variable names with "v_" -- just namespace them with the procedure or block name.
The Execute Immediate constructs a SQL statement that performs an insert into the stats_table (why does it have the word "table" in the name? That's redundant, surely?)
The query will be constructed as something like:
INSERT INTO STATS_TABLE
( TABLE_NAME
, SCHEMA_NAME
, RECORD_COUNT
, CREATED
)
SELECT 'MY_TABLE_NAME' , 'MY_USERNAME' , COUNT(*) , SYSDATE
FROM MY_TABLE_NAME;

Related

Create procedure in oracle DB for finding and deleting foreign key constraints for specific tables

I am new to Oracle, I am trying to write a procedure in Oracle to delete foreign key constraints for a table. I have already done this for MySQL and its working. I am not sure with the syntax, apologies for that, but my query is working If I run it individually. I want to do the same thing(removing foreign key constraints) for multiple tables and don't want to write queries multiple times. hence first I am finding the foreign keys associated with that table , storing them in cursor and later removing all of the foreign keys by creating and executing drop constraints query associated with that table. following code is giving multiple errors to me.
CREATE OR REPLACE PROCEDURE removeConstraintsForTable(vTableName IN varchar2) IS
BEGIN
cName VARCHAR(2048);
sql_stmt VARCHAR2(2048);
CURSOR cur IS
SELECT DISTINCT CONSTRAINT_NAME
FROM ALL_CONSTRAINTS WHERE OWNER= sys_context('userenv','current_schema')
AND TABLE_NAME = vTableName AND CONSTRAINT_TYPE='R';
BEGIN
OPEN cur;
LOOP
FETCH cur INTO cName;
EXIT WHEN cur%notfound;
sql_stmt := CONCAT(CONCAT(CONCAT('ALTER TABLE ',vTableName),CONCAT(' DROP FOREIGN KEY ',cName)),';');
SELECT sql_stmt FROM dual;
INSERT INTO TEMP(Name) VALUES(sql_stmt);
COMMIT;
END LOOP;
END
/
CALL removeConstraintsForTable('table1');
CALL removeConstraintsForTable('table2');
CALL removeConstraintsForTable('table3');
CALL removeConstraintsForTable('table4');
COMMIT;
You have an extra BEGIN right at the start of your procedure, and the final END is missing a semicolon. You shouldn't really be using VARCHAR, and you could declare the cName variable using the data dictionary anyway; however an implicit loop will be simpler, as will using the concatenation operator || instead of nested CONCAT() calls, and the generated statement should not end in a semicolon:
create or replace procedure removeconstraintsfortable(p_table_name in varchar2) is
sql_stmt varchar2(2048);
begin
for rec in (
select owner, constraint_name
from all_constraints
where owner = sys_context('userenv','current_schema')
and table_name = p_table_name
and constraint_type = 'R'
)
loop
sql_stmt := 'ALTER TABLE "' || rec.owner || '"."' || p_table_name || '"'
|| ' DROP CONSTRAINT "' || rec.constraint_name || '"';
insert into temp(name) values(sql_stmt);
end loop;
commit;
end;
/
As pointed out in comments, the generated statement should be drop constraint.
I'm not sure why you're inserting into a table or where you execute the statement, but you can do it all in one if you prefer:
create or replace procedure removeconstraintsfortable(p_table_name in varchar2) is
sql_stmt varchar2(2048);
begin
for rec in (
select owner, constraint_name
from all_constraints
where owner = sys_context('userenv','current_schema')
and table_name = p_table_name
and constraint_type = 'R'
)
loop
sql_stmt := 'ALTER TABLE "' || rec.owner || '"."' || p_table_name || '"'
|| ' DROP CONSTRAINT "' || rec.constraint_name || '"';
dbms_output.put_line(sql_stmt);
execute immediate sql_stmt;
end loop;
end;
/
The dbms_output call just shows you the generated statement(s), before execute immediate executes it, well, immediately.
Quick demo; very basic table set-up:
create table t42 (id number primary key);
create table t43 (id number references t42 (id));
select table_name, constraint_name, constraint_type
from all_constraints
where table_name in ('T42', 'T43');
TABLE_NAME CONSTRAINT_NAME C
------------------------------ ------------------------------ -
T43 SYS_C00138153 R
T42 SYS_C00138152 P
Then call the procedure which shows the generated statement:
set serveroutput on
exec removeConstraintsForTable('T43');
ALTER TABLE "STACKOVERFLOW"."T43" DROP CONSTRAINT "SYS_C00138153"
PL/SQL procedure successfully completed.
and then check the constraint has gone:
select table_name, constraint_name, constraint_type
from all_constraints
where table_name in ('T42', 'T43');
TABLE_NAME CONSTRAINT_NAME C
------------------------------ ------------------------------ -
T42 SYS_C00138152 P
I fixed a number of syntax issues for you. Try this.
CREATE OR REPLACE PROCEDURE removeConstraintsForTable(vTableName IN varchar2) IS
cName VARCHAR2(30); -- identifiers are max 30 chars
sql_stmt VARCHAR2(2048);
CURSOR cur IS
SELECT DISTINCT CONSTRAINT_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = vTableName AND CONSTRAINT_TYPE='R';
BEGIN
OPEN cur;
LOOP
FETCH cur INTO cName;
EXIT WHEN cur%notfound;
sql_stmt := 'ALTER TABLE ' || vTableName || ' DROP CONSTRAINT ' || cName;
INSERT INTO RANGERADMIN1.TEMP(Name) VALUES(sql_stmt);
END LOOP;
COMMIT;
END removeConstraintsForTable;
/
call removeConstraintsForTable('table1');
call removeConstraintsForTable('table2');
call removeConstraintsForTable('table3');
call removeConstraintsForTable('table4');
-- COMMIT; -- not necessary

Loop tables into pl/sql and display number of rows

I have loop for all the tables into db:
declare
V_TABL_NM ALL_TABLES.TABLE_NAME%TYPE;
BEGIN
FOR GET_TABL_LIST IN (SELECT TABLE_NAME FROM ALL_TABLES )LOOP
V_TABL_NM := GET_TABL_LIST.TABLE_NAME;
DBMS_OUTPUT.PUT_LINE(V_TABL_NM);
END LOOP;
END;
How can I sort my result and add number of records for each tables?
I try below but it does not work:
declare
V_TABL_NM ALL_TABLES.TABLE_NAME%TYPE;
table_row number;
BEGIN
FOR GET_TABL_LIST IN (SELECT TABLE_NAME FROM ALL_TABLES )LOOP
V_TABL_NM := GET_TABL_LIST.TABLE_NAME;
table_row: = select count(*) from TABLE_NAME;
DBMS_OUTPUT.PUT_LINE(V_TABL_NM, table_row);
END LOOP;
END;
You can not make a query that way; TABLE_NAME has no meaning there (and you're missing to use the cursor name), so you need to build a dynamic SQL and run it to put the value into a variable.
Besides, the PUT_LINE does not accept that parameters.
This should work:
DECLARE
table_row NUMBER;
BEGIN
FOR GET_TABL_LIST IN ( SELECT OWNER || '.' || TABLE_NAME AS TABLE_NAME
FROM ALL_TABLES
ORDER BY TABLE_NAME)
LOOP
EXECUTE IMMEDIATE 'select count(*) from ' || GET_TABL_LIST.TABLE_NAME INTO table_row;
DBMS_OUTPUT.PUT_LINE(GET_TABL_LIST.TABLE_NAME || ' - ' || table_row);
END LOOP;
END;
About the ordering, simply add an ORDER BY to the query looping through the tables
This assumes that you have rights to query all the tables listed in ALL_TABLES If you simply need to query all the tables of your schema, use USER_TABLES instead of ALL_TABLES.
to sort the results add order by clausel:
FOR GET_TABL_LIST IN
(
SELECT TABLE_NAME
FROM ALL_TABLES
ORDER BY TABLE_NAME --
)LOOP
to count the records use dynamic sql :
execute immediate 'select count(*) from ' || V_TABL_NM INTO table_row;
This can be done completely without PL/SQL:
select table_name,
to_number(extractvalue(xmltype(dbms_xmlgen.getxml('select count(*) c from '||table_name)),'/ROWSET/ROW/C')) as rowcount
from user_tables
order by rowcount;
also I did:
select TABLE_NAME, NUM_ROWS, LAST_ANALYZED
from user_tables
order by 1;

How to determine row count for all tables in an Oracle Schema [duplicate]

I am trying to get the record counts of all tables in a schema. I am having trouble writing the PL/SQL. Here is what I have done so far, but I am getting errors. Please suggest any changes:
DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name,user
from user_tables
where lower(user) = 'SCHEMA_NAME';
begin
open get_tables;
fetch get_tables into v_table_name,v_owner;
INSERT INTO STATS_TABLE(TABLE_NAME,SCHEMA_NAME,RECORD_COUNT,CREATED)
SELECT v_table_name,v_owner,COUNT(*),TO_DATE(SYSDATE,'DD-MON-YY') FROM v_table_name;
CLOSE get_tables;
END;
This can be done with a single statement and some XML magic:
select table_name,
to_number(extractvalue(xmltype(dbms_xmlgen.getxml('select count(*) c from '||owner||'.'||table_name)),'/ROWSET/ROW/C')) as count
from all_tables
where owner = 'FOOBAR'
This should do it:
declare
v_count integer;
begin
for r in (select table_name, owner from all_tables
where owner = 'SCHEMA_NAME')
loop
execute immediate 'select count(*) from ' || r.table_name
into v_count;
INSERT INTO STATS_TABLE(TABLE_NAME,SCHEMA_NAME,RECORD_COUNT,CREATED)
VALUES (r.table_name,r.owner,v_count,SYSDATE);
end loop;
end;
I removed various bugs from your code.
Note: For the benefit of other readers, Oracle does not provide a table called STATS_TABLE, you would need to create it.
select owner, table_name, num_rows, sample_size, last_analyzed from all_tables;
This is the fastest way to retrieve the row counts but there are a few important caveats:
NUM_ROWS is only 100% accurate if statistics were gathered in 11g and above with ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE (the default), or in earlier versions with ESTIMATE_PERCENT => 100. See this post for an explanation of how
the AUTO_SAMPLE_SIZE algorithm works in 11g.
Results were generated as of LAST_ANALYZED, the current results may be different.
If you want simple SQL for Oracle (e.g. have XE with no XmlGen) go for a simple 2-step:
select ('(SELECT ''' || table_name || ''' as Tablename,COUNT(*) FROM "' || table_name || '") UNION') from USER_TABLES;
Copy the entire result and replace the last UNION with a semi-colon (';'). Then as the 2nd step execute the resulting SQL.
Get counts of all tables in a schema and order by desc
select 'with tmp(table_name, row_number) as (' from dual
union all
select 'select '''||table_name||''',count(*) from '||table_name||' union ' from USER_TABLES
union all
select 'select '''',0 from dual) select table_name,row_number from tmp order by row_number desc ;' from dual;
Copy the entire result and execute
You have to use execute immediate (dynamic sql).
DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name,user
from user_tables
where lower(user) = 'schema_name';
begin
open get_tables;
loop
fetch get_tables into v_table_name,v_owner;
EXIT WHEN get_tables%NOTFOUND;
execute immediate 'INSERT INTO STATS_TABLE(TABLE_NAME,SCHEMA_NAME,RECORD_COUNT,CREATED)
SELECT ''' || v_table_name || ''' , ''' || v_owner ||''',COUNT(*),TO_DATE(SYSDATE,''DD-MON-YY'') FROM ' || v_table_name;
end loop;
CLOSE get_tables;
END;

Oracle select across a group of tables by partial name

I'm trying to select information from a group of tables. Originally, I had
SELECT table_name,
to_number(
extractvalue(
xmltype(
dbms_xmlgen.getxml('select count(*) c '|| ' from ' ||owner||'.'||table_name))
,'/ROWSET/ROW/C')) count
from all_tables
where table_name like 'PAY0%' OR table_name like 'PAY1%'
Then looped through all the tables in my code using
foreach(table_name in tables){
SELECT CUST_NUMBER
FROM #table_name#
}
Now I'm trying to combine the two by doing the following in order to get the cust_number from every table, but it's saying '"CUST_NUMBER": invalid identifier'
select CUST_NUMBER
from ( SELECT table_name,
to_number(
extractvalue(
xmltype(
dbms_xmlgen.getxml('select count(*) c '|| ' from ' ||owner||'.'||table_name))
,'/ROWSET/ROW/C')) count
from all_tables
where table_name like 'PAY0%' OR table_name like 'PAY1%') PayTables
I know the problem is the first query gets table names and not the data, but I've no idea how to get the data as well without looping through them seperately.
If I correctly understand your need, something like the following could help:
declare
vSQL varchar2(32767);
type tabNum is table of number;
vResult tabNum;
begin
select listagg( 'select cust_number from ' || owner || '.' || table_name,
' UNION ALL '
) within group ( order by null)
into vSQL
from dba_tables
where table_name like 'PAY0%' OR table_name like 'PAY1%';
--
dbms_output.put_line(vSQL);
--
execute immediate vSQL bulk collect into vResult;
--
for i in vResult.first .. vResult.last loop
dbms_output.put_line(vResult(i));
end loop;
end;
It dynamically builds an SQL statement that extracts values from all the tables matching you criteria; in the example I run the statement fetching the result into a structure, but you can open a cursor, or do whatever you need.

Got an ORA-01788 error without using level or start with

I have just started to learn PL/SQL. Following a post in stackoverflow, I have written a script to search a certain value in Oracle as below:
DECLARE
match_count INTEGER;
v_owner VARCHAR2(255);
v_search_value NUMBER;
BEGIN
v_owner:='USERA USERB';
v_search_value:=4823.0;
EXECUTE IMMEDIATE
'INSERT INTO TMP SELECT owner, table_name, column_name FROM all_tab_cols WHERE instr(:1, owner)>0 AND data_type like ''%NUMBER%''' USING v_owner;
commit;
FOR t IN (SELECT owner, table_name, column_name FROM TMP) LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.owner||'.'||t.table_name||' WHERE '||t.column_name||'= :1'
INTO match_count
USING v_search_value;
IF match_count > 0 THEN
EXECUTE IMMEDIATE
'INSERT INTO RESULT VALUES(:1, :2, :3, :4)'
USING t.owner, t.table_name, t.column_name, match_count;
commit;
END IF;
END LOOP;
END;
The table TMP and RESULT have been properly created before executing the script. However, when I run the script, I get an ORA-01788 error saying that "connect by clause required" on line 12. I wonder why the code cause this error and how to change the script to be executed properly. Thanks!
You probably have a table with a column called level (as Florin suggested while I wasn't looking), which is a reserved word.
It may be in any case - not just level, but LEVEL, or Level - so to check you could do:
select owner, table_name, column_name
from all_tab_columns
where upper(column_name) = 'LEVEL';
Or to look for any reserved words in use (though this won't always find all potential problems):
select atc.owner, atc.table_name, atc.column_name, vrw.keyword
from all_tab_columns atc
join v$reserved_words vrw on vrw.keyword = upper(atc.column_name);
You could run similar queries against all_tables or all_objects to find potential problems elsewhere.
If I run a modified version of your query which doesn't bother with the TMP table - not sure why you'd want that; doesn't use dynamic SQL for the inserts; doesn't commit (which is an odd thing to do in a block - you don't need to do it after every insert anyway); and just for my benefit just displays the matches instead of needing to build a results table:
declare
match_count integer;
v_owner varchar2(255);
v_search_value number;
begin
v_owner := 'USERA USERB';
v_search_value := 4823.0;
for t in (
select owner, table_name, column_name
from all_tab_cols
where instr(v_owner, owner) > 0
and data_type like '%NUMBER%'
) loop
execute immediate
'select count(*) from ' || t.owner ||'.'|| t.table_name
|| ' where ' || t.column_name || ' = :1'
into match_count using v_search_value;
if match_count > 0 then
-- insert into results values (t.owner, t.table_name,
-- t.column_name, match_count);
dbms_output.put_line('Matched ' || t.owner ||'.'|| t.table_name
||'.'|| t.column_name ||': '|| match_count);
end if;
end loop;
end;
/
... this completes successfully. If I add a table with a level column:
create table t42 ("LEVEL" number);
... and then run the same block again then I also get:
ORA-01788: CONNECT BY clause required in this query block
ORA-06512: at line 14
01788. 00000 - "CONNECT BY clause required in this query block"
*Cause:
*Action:
Aside from avoiding reserved words in object names, you can make this work by enclosing all of your object names in double-quotes:
execute immediate
'select count(*) from "' || t.owner ||'"."'|| t.table_name
|| '" where "' || t.column_name || '" = :1'
into match_count using v_search_value;
This will also cope with mixed-case object names, which you should also avoid.

Resources