Oracle manually update statistics on all tables - oracle

Is there a way to update all statistics for all tables regardless of the owner?
I found this sniplet, but I'm not sure if this will grab all tables....
BEGIN
FOR A IN ( SELECT owner FROM SYS.all_tables ) LOOP
execute immediate
EXEC dbms_stats.gather_schema_stats( 'A.owner', cascade='TRUE');
END LOOP;
END;

Use DBMS_STATS.GATHER_DATABASE_STATS:
begin
dbms_stats.gather_database_stats;
end;
/

No the DBMS_STATS package can do at most one schema at a time.
You can use the script below to gather stats for all objects types in all schemas. The one you listed has a couple of issues (needless execute immediate, `A.owner' is a string but it should be an object, etc).
You can add additional schemas to skip in the IN list as you probably don't want to do this for the built in schemas (they're mostly static anyway so it'd be waste). Also, you'll need to have the appropriate privileges for each schema you are gathering stats on (or be logged in as a DBA).
Gather stats on all objects (probably what you really want):
BEGIN
FOR rec IN (SELECT *
FROM all_users
WHERE username NOT IN ('SYS','SYSDBA'))
LOOP
dbms_stats.gather_schema_stats(rec.username);
END LOOP;
END;
Gather stats on just tables:
BEGIN
FOR rec IN (SELECT *
FROM all_tables
WHERE owner NOT IN ('SYS','SYSDBA'))
LOOP
dbms_stats.gather_table_stats(rec.owner, rec.table_name);
END LOOP;
END;

I did a modification to #sehrope procedure to skip locked stats and IOT tables as they will through exceptions.
BEGIN
FOR rec IN (SELECT a.owner, a.table_name
FROM all_tables a, dba_tab_statistics s
WHERE a.owner NOT IN ('SYS','SYSDBA')
AND
(a.iot_type IS NULL
OR
a.iot_type != 'IOT_OVERFLOW')
and a.owner = s.owner and a.table_name = s.table_name and s.STATTYPE_LOCKED is null)
LOOP
dbms_stats.gather_table_stats(rec.owner, rec.table_name);
END LOOP;
END;

Related

How to write procedure to copy data from one table to another table

Hello I have this situation
I have a table with 400 millions of records I want to migrate some data to another table for get better performance.
I know that the process could be slow and heavy and I want to execute something like this
INSERT INTO TABLLE_2 SELECT NAME,TAX_ID,PROD_CODE FROM TABLE_1;
But I want this in a procedure that iterates the table from 50000 to 50000 records.
I saw this but it DELETE the rows and the target is SQLServer and not Oracle
WHILE 1 = 1
BEGIN
DELETE TOP (50000) FROM DBO.VENTAS
OUTPUT
Deleted.AccountNumber,
Deleted.BillToAddressID,
Deleted.CustomerID,
Deleted.OrderDate,
Deleted.SalesOrderNumber,
Deleted.TotalDue
INTO DATOS_HISTORY.dbo.VENTAS
WHERE OrderDate >= '20130101'
and OrderDate < '20140101'
IF ##ROWCOUNT = 0 BREAK;
END;
If it's just for a one-time migration, don't paginate/iterate at all. Just use a pdml append insert-select:
BEGIN
EXECUTE IMMEDIATE 'alter session enable parallel dml';
INSERT /*+ parallel(8) nologging append */ INTO table_2
SELECT name,tax_id,prod_code from table_1;
COMMIT;
EXECUTE IMMEDIATE 'alter session disable parallel dml';
END;
Or if the table doesn't yet exist, CTAS it to be even simpler:
CREATE OR REPLACE TABLE table_2 PARALLEL (DEGREE 8) NOLOGGING AS
SELECT name,tax_id,prod_code FROM table_1;
If you absolutely must iterate due to other business needs you didn't mention, you can use PL/SQL for that as well:
DECLARE
CURSOR cur_test
IS
SELECT name,tax_id,prod_code
FROM table_1;
TYPE test_tabtype IS TABLE OF cur_test%ROWTYPE;
tab_test test_tabtype;
var_limit integer := 50000;
BEGIN
OPEN cur_test;
FETCH cur_test BULK COLLECT INTO tab_test LIMIT var_limit;
LOOP
-- do whatever else you need to do
FORALL i IN tab_test.FIRST .. tab_test.LAST
INSERT INTO table_2
(name,tax_id,prod_code)
VALUES (tab_test(i).name, tab_test(i).tax_id, tab_test(i).prod_code);
COMMIT;
EXIT WHEN tab_test.COUNT < var_limit;
FETCH cur_test BULK COLLECT INTO tab_test LIMIT var_limit;
END LOOP;
CLOSE cur_test;
END;
That won't be nearly as fast, though. If you need even faster, you can create a SQL object and nested table type instead of the PL/SQL types you see here and then you can do a normal INSERT /*+ APPEND */ SELECT ... statement that will use direct path. But honestly, I doubt you really need iteration at all..

ORACLE EXECUTE IMMEDIATE FOR LOOP ORA-06512

I am trying to EXECUTE IMMEDIATE an entire FOR LOOP, but it is not working.
It is possible to do that?
BEGIN
FOR V_ROW IN (SELECT ROWNUM AS RN,ID AS ID FROM (SELECT ID FROM T_OPDM_PLANDEACCION WHERE IDOPORTUNIDAD=2 ORDER BY ORDEN)) LOOP UPDATE T_OPDM_PLANDEACCION SET ORDEN=V_ROW.RN WHERE ID=V_ROW.ID;END LOOP;
EXECUTE IMMEDIATE 'FOR V_ROW IN (SELECT ROWNUM AS RN,ID AS ID FROM (SELECT ID FROM T_OPDM_PLANDEACCION WHERE IDOPORTUNIDAD=2 ORDER BY ORDEN)) LOOP UPDATE T_OPDM_PLANDEACCION SET ORDEN=V_ROW.RN WHERE ID=V_ROW.ID;END LOOP';
END;
/
The second line works very well, but the 3rd line (EXECUTE IMMEDIATE 'FOR V_ROW ...') not works. String inside EXECUTE IMMEDIATE is exactly the same as the 2nd line.
I need to execute a FOR LOOP for a parametric SELECT.
A for loop is PL/SQL. Dynamic SQL is not. If you want to run PL/SQL code dynamically then you need to have it in a PL/SQL block within the dynamic statement:
BEGIN
EXECUTE IMMEDIATE 'BEGIN FOR V_ROW IN (SELECT ROWNUM AS RN,ID AS ID FROM (SELECT ID FROM T_OPDM_PLANDEACCION WHERE IDOPORTUNIDAD=2 ORDER BY ORDEN)) LOOP UPDATE T_OPDM_PLANDEACCION SET ORDEN=V_ROW.RN WHERE ID=V_ROW.ID;END LOOP;END;';
END;
That is, with BEGIN and END; (and a missing semicolon) added around what you had.
As #APC hinted, you can split your statement into multiple lines to improve readability, e.g.:
BEGIN
EXECUTE IMMEDIATE '
BEGIN
FOR V_ROW IN (
SELECT ROWNUM AS RN,ID AS ID
FROM (
SELECT ID
FROM T_OPDM_PLANDEACCION
WHERE IDOPORTUNIDAD=2
ORDER BY ORDEN
)
)
LOOP
UPDATE T_OPDM_PLANDEACCION
SET ORDEN=V_ROW.RN
WHERE ID=V_ROW.ID;
END LOOP;
END;
';
END;
It isn't obvious why you would want to do that with this example. If your going to use a 'parametric select' then you might be planning to inject that into the dynamic statement; but even that might not be necessary, depending on exactly what you mean and how you get the query. It isn't even clear why you would do this in a loop, or with PL/SQL, at all.

What is the solution for the errors in this PL/SQL code? [duplicate]

The database-schema (Source and target) are very large (each has over 350 tables). I have got the task to somehow merge these two tables into one. The data itself (whats in the tables) has to be migrated. I have to be careful that there are no double entries for primary keys before or while merging the schemata. Has anybody ever done that already and would be able to provide me his solution or could anyone help me get a approach to the task? My approaches all failed and my advisor just tells me to get help online :/
To my approach:
I have tried using the "all_constraints" table to get all pks from my db.
SELECT cols.table_name, cols.column_name, cols.position, cons.status, cons.owner
FROM all_constraints cons, all_cons_columns cols
WHERE cols.owner = 'DB'
AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position;
I also "know" that there has to be a sequence for the primary keys to add values to it:
CREATE SEQUENCE seq_pk_addition
MINVALUE 1
MAXVALUE 99999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
Because I am a noob if it comes to pl/sql (or sql in general)
So how/what I should do next? :/
Here is a link for an ERD of the database: https://ufile.io/9tdoj
virus scan: https://www.virustotal.com/#/file/dbe5f418115e50313a2268fb33a924cc8cb57a43bc85b3bbf5f6a571b184627e/detection
As promised to help in my comment, i had prepared a dynamic code which you can try to get the data merged with the source and target tables. The logic is as below:
Step1: Get all the table names from the SOURCE schema. In the query below you can you need to replace the schema(owner) name respectively. For testing purpose i had taken only 1 table so when you run it,remove the table name filtering clause.
Step2: Get the constrained columns names for the table. This is used to prepared the ON clause which would be later used for MERGE statement.
Step3: Get the non-constrainted column names for the table. This would be used in UPDATE clause while using MERGE.
Step4: Prepare the insert list when the data doesnot match ON conditon of MERGE statement.
Read my inline comments to understand each step.
CREATE OR REPLACE PROCEDURE COPY_TABLE
AS
Type OBJ_NME is table of varchar2(100) index by pls_integer;
--To hold Table name
v_obj_nm OBJ_NME ;
--To hold Columns of table
v_col_nm OBJ_NME;
v_othr_col_nm OBJ_NME;
on_clause VARCHAR2(2000);
upd_clause VARCHAR2(4000);
cntr number:=0;
v_sql VARCHAR2(4000);
col_list1 VARCHAR2(4000);
col_list2 VARCHAR2(4000);
col_list3 VARCHAR2(4000);
col_list4 varchar2(4000);
col_list5 VARCHAR2(4000);
col_list6 VARCHAR2(4000);
col_list7 VARCHAR2(4000);
col_list8 varchar2(4000);
BEGIN
--Get Source table names
SELECT OBJECT_NAME
BULK COLLECT INTO v_obj_nm
FROM all_objects
WHERE owner LIKE 'RU%' -- Replace `RU%` with your Source schema name here
AND object_type = 'TABLE'
and object_name ='TEST'; --remove this condition if you want this to run for all tables
FOR I IN 1..v_obj_nm.count
loop
--Columns with Constraints
SELECT column_name
bulk collect into v_col_nm
FROM user_cons_columns
WHERE table_name = v_obj_nm(i);
--Columns without Constraints remain columns of table
SELECT *
BULK COLLECT INTO v_othr_col_nm
from (
SELECT column_name
FROM user_tab_cols
WHERE table_name = v_obj_nm(i)
MINUS
SELECT column_name
FROM user_cons_columns
WHERE table_name = v_obj_nm(i));
--Prepare Update Clause
FOR l IN 1..v_othr_col_nm.count
loop
cntr:=cntr+1;
upd_clause := 't1.'||v_othr_col_nm(l)||' = t2.' ||v_othr_col_nm(l);
upd_clause:=upd_clause ||' and ' ;
col_list1:= 't1.'||v_othr_col_nm(l) ||',';
col_list2:= col_list2||col_list1;
col_list5:= 't2.'||v_othr_col_nm(l) ||',';
col_list6:= col_list6||col_list5;
IF (cntr = v_othr_col_nm.count)
THEN
--dbms_output.put_line('YES');
upd_clause:=rtrim(upd_clause,' and');
col_list2:=rtrim( col_list2,',');
col_list6:=rtrim( col_list6,',');
END IF;
dbms_output.put_line(col_list2||col_list6);
--dbms_output.put_line(upd_clause);
End loop;
--Update caluse ends
cntr:=0; --Counter reset
--Prepare ON clause
FOR k IN 1..v_col_nm.count
loop
cntr:=cntr+1;
--dbms_output.put_line(v_col_nm.count || cntr);
on_clause := 't1.'||v_col_nm(k)||' = t2.' ||v_col_nm(k);
on_clause:=on_clause ||' and ' ;
col_list3:= 't1.'||v_col_nm(k) ||',';
col_list4:= col_list4||col_list3;
col_list7:= 't2.'||v_col_nm(k) ||',';
col_list8:= col_list8||col_list7;
IF (cntr = v_col_nm.count)
THEN
--dbms_output.put_line('YES');
on_clause:=rtrim(on_clause,' and');
col_list4:=rtrim( col_list4,',');
col_list8:=rtrim( col_list8,',');
end if;
dbms_output.put_line(col_list4||col_list8);
-- ON clause ends
--Prepare merge Statement
v_sql:= 'MERGE INTO '|| v_obj_nm(i)||' t1--put target schema name before v_obj_nm
USING (SELECT * FROM '|| v_obj_nm(i)||') t2-- put source schema name befire v_obj_nm here
ON ('||on_clause||')
WHEN MATCHED THEN
UPDATE
SET '||upd_clause ||
' WHEN NOT MATCHED THEN
INSERT
('||col_list2||','
||col_list4||
')
VALUES
('||col_list6||','
||col_list8||
')';
dbms_output.put_line(v_sql);
execute immediate v_sql;
end loop;
End loop;
END;
/
Execution:
exec COPY_TABLE
Output:
anonymous block completed
PS: i have tested this with a table with 2 columns out of which i was having unique key constraint .The DDL of table is as below:
At the end i wish you could understand my code(you being a noob) and implement something similar if the above fails for your requirement.
CREATE TABLE TEST
( COL2 NUMBER,
COLUMN1 VARCHAR2(20 BYTE),
CONSTRAINT TEST_UK1 UNIQUE (COLUMN1)
) ;
Oh dear! Normally, such a question would be quickly closed as "too broad", but we need to support victims of evil advisors!
As for the effort, I would need a week full time for an experienced expert plus two days quality checking for an experierenced QA engineer.
First of all, there is no way that such a complex data merge will work on the first try. That means that you'll need test copies of both schemas that can be easily rebuild. And you'll need a place to try it out. Normally this is done with an export of both schemas and an empty dev database.
Next, you need both schemas close enough to be able to compare the data. I'd do it with an import of the export files mentione above. If the schema names are identical than rename one during import.
Next, I'd doublecheck if the structure is really identical, with queries like
SELECT a.owner, a.table_name, b.owner, b.table_name
FROM all_tables a
FULL JOIN all_tables b
ON a.table_name = b.table_name
AND a.owner = 'SCHEMAA'
AND b.owner = 'SCHEMAB'
WHERE a.owner IS NULL or b.owner IS NULL;
Next, I'd check if the primary and unique keys have overlaps:
SELECT id FROM schemaa.table1
INTERSECT
SELECT id FROM schemab.table1;
As there are 300+ tables, I'd generate those queries:
DECLARE
stmt VARCHAR2(30000);
n NUMBER;
schema_a CONSTANT VARCHAR2(128 BYTE) := 'SCHEMAA';
schema_b CONSTANT VARCHAR2(128 BYTE) := 'SCHEMAB';
BEGIN
FOR c IN (SELECT owner, constraint_name, table_name,
(SELECT LISTAGG(column_name,',') WITHIN GROUP (ORDER BY position)
FROM all_cons_columns c
WHERE s.owner = c.owner
AND s.constraint_name = c.constraint_name) AS cols
FROM all_constraints s
WHERE s.constraint_type IN ('P')
AND s.owner = schema_a)
LOOP
dbms_output.put_line('Checking pk '||c.constraint_name||' on table '||c.table_name);
stmt := 'SELECT count(*) FROM '||schema_a||'.'||c.table_name
||' JOIN '||schema_b||'.'||c.table_name
|| ' USING ('||c.cols||')';
--dbms_output.put_line('Query '||stmt);
EXECUTE IMMEDIATE stmt INTO n;
dbms_output.put_line('Found '||n||' overlapping primary keys in table '||c.table_name);
END LOOP;
END;
/
1st of all, for 350 tables, most probably, would need an dynamic SQL.
Declare a CURSOR or a COLLECTION - table of VARCHAR2 with all table names.
Declare a string variable to build the dynamic SQL.
loop through the entire list of the tables name and, for each table generates a string which will be executed as SQL with EXECUTE IMMEDIATE command.
The dynamic SQL which will be built, should insert the values from source table into the target table. In case the PK already exists, in target table, should be checked the field which represents the last updated date and if in source table it is bigger than in target table, then perform an update in target table, else, do nothing.

Back up Oracle with script (Insert statements, DDL)

I would like to backup part of a database with Insert and DDL statements with output similar to what you can get with TOAD or SQL Developer, but from a script.
Details:
This is to be able to see changes and differences with source control.
We are using SQL Developer, LINUX tools and Python (With Oracle).
try this? Change settings as per your need.
Exporting Schema:
1) Run following in command prompt (not mandatory though)
SET NLS_LANG AMERICAN_AMERICA.UTF.8
2) Once above is set run the below, run the below. Change username/password/schemaname, path to export
exp userid=<schemaname>/<pwd>#<dbname or SID> file=<localpath\1.dmp>
log=<localpath\2.log> buffer=1000000000 feedback=25000
direct=y recordlength=64000 owner=<schemaname>
There must be tools for what you are trying to do (other than TOAD and PL/SQL).
This is a great project you have if you intend to write the code for this. You must work as follows:
For DDLs
. Write a script that list all the objects you need to extract; this will be tables, schemas, procedures, functions:
for x in (
select * from dba_objects where object_type in ('PACKAGES', 'TABLES', '>others>') loop
--- things to do with x.>columns<
end loop;
for u in (
select * from dba_users where username in ( <list of needed schemas> ) loop
)
--- things to do with users
end loop;
. Then from above list, you have Oracle function dbms_metadata.get_ddl that generates the DDL. e.g. with users:
begin
for u in (select * from dba_users where <list of needed schemas>
order by username)
loop
dbms_metadata.get_ddl('USER', u.username);
end loop;
end;
For the inserts
(this could take time to generate on databases with large tables (thousands of rows is already a lot for my approach).
I advise you create a generic function that generates the insert statements. This is rather simple as long as it does not include BLOB and CLOB. You take each column of each table.
Remember to generate the inserts in an orderly way, otherwise the comparison will not be possible.
The generic function should take a table as input. From the table name, it gets the columns from dba_tables, then selects the table.
--- plsql code below lists the columns of the tables
begin
for t in (select * from dba_tables order by table_name) loop
for c in (select * from dba_tab_columns where table_name=t.table_name and owner=t.owner order by owner, table_name, column_name) loop
dbms_output.put_line(c.table_name||'.'||c.column_name);
end loop;
end loop;
end;
Here is how you could collect the values in an array, then loop on this array to display the insert statements as text (with dbms_output.put_line)
declare
type t_v is table of varchar2(32000);
t_vchars t_v;
v_ins varchar2(2000):=' ';
v_sel varchar2(2000):=' ';
v_res varchar2(4030):=' ';
begin
for t in (select * from dba_tables order by table_name) loop
v_ins :='insert into '||t.table_name||'(';
v_sel :=' select ';
for c in (select * from dba_tab_columns where table_name=t.table_name and owner=t.owner) loop
v_ins:= v_ins||c.column_name||',';
v_sel:= v_sel||'''''''||'||c.column_name||'||'''''',';
end loop;
-- remove last comma
v_ins:= substr(v_ins,1,length(v_ins)-1);
v_sel:= substr(v_sel,1,length(v_sel)-1);
v_ins:= v_ins||')';
v_sel:= v_sel||' from dual';
v_res:= 'select '''||v_ins||v_sel||''' from '||t.table_name;
-- above, you still need to insert an order by, but I let you choose which solution
execute immediate v_res bulk collect into t_vchars;
FOR i in 1..t_vchars.count LOOP
dbms_output.put_line(t_vchars(i)||';');
END LOOP;
end loop;
end;
After you're done and want to test the whole script.
One tricky thing when you want to test and run the inserts is if you have foreign key. You must deactivate them before inserting, otherwise you need to do the inserts in a ordered way, which is not easy to do.
for c in (select * from dba_constraints)
loop
--- disable constraint
end loop;
Then after inserts are done
for c in (select * from dba_constraints)
loop
--- enable constraint
end loop;

PLSQL - Drop all database objects of a user

I'm trying to use a procedure (no parameters) to drop all of the user-created database objects located within the schema from where the procedure is launched, but I'm really not sure on how to go about this. Here's what I have so far, but I think I'm going about this the wrong way.
create or replace procedure CLEAN_SCHEMA is
cursor schema_cur is
select 'drop '||object_type||' '|| object_name|| DECODE(OBJECT_TYPE,'TABLE',' CASCADE CONSTRAINTS;',';')
from user_objects;
schema_rec schema_cur%rowtype;
begin
select 'drop '||object_type||' '|| object_name|| DECODE(OBJECT_TYPE,'TABLE',' CASCADE CONSTRAINTS;',';')
into schema_rec
from user_objects;
end;
/
create or replace
FUNCTION DROP_ALL_SCHEMA_OBJECTS RETURN NUMBER AS
PRAGMA AUTONOMOUS_TRANSACTION;
cursor c_get_objects is
select object_type,'"'||object_name||'"'||decode(object_type,'TABLE' ,' cascade constraints',null) obj_name
from user_objects
where object_type in ('TABLE','VIEW','PACKAGE','SEQUENCE','SYNONYM', 'MATERIALIZED VIEW')
order by object_type;
cursor c_get_objects_type is
select object_type, '"'||object_name||'"' obj_name
from user_objects
where object_type in ('TYPE');
BEGIN
begin
for object_rec in c_get_objects loop
execute immediate ('drop '||object_rec.object_type||' ' ||object_rec.obj_name);
end loop;
for object_rec in c_get_objects_type loop
begin
execute immediate ('drop '||object_rec.object_type||' ' ||object_rec.obj_name);
end;
end loop;
end;
RETURN 0;
END DROP_ALL_SCHEMA_OBJECTS;
Create the above function (autonomous so DDL can be called via a function)
then you can just:
select DROP_ALL_SCHEMA_OBJECTS from dual;
when you want to drop all your objects, make sure you dont try to drop the proc your running (i dont care about the procs thats why i dont have procs or functions in the object_type list)
if you want to drop everything you need an anonymous block
but i needed to be able to do this from a tool that only allowed ansi sql (not plsql) hence a stored proc.
Enjoy.
declare
cursor ix is
select *
from user_objects
where object_type in ('TABLE', 'VIEW', 'FUNCTION', 'SEQUENCE');
begin
for x in ix loop
execute immediate('drop '||x.object_type||' '||x.object_name);
end loop;
end;
Unless the user has hard to reapply permissions, its probably easier to just drop the user and recreate them.
Thanks Martin Brambley,
I feel we can simplify your answer in the following way.
CREATE OR REPLACE
procedure DROP_ALL_SCHEMA_OBJECTS AS
PRAGMA AUTONOMOUS_TRANSACTION;
cursor c_get_objects is
select object_type,'"'||object_name||'"'||decode(object_type,'TABLE' ,' cascade constraints',null) obj_name
FROM USER_OBJECTS
where object_type in ('TABLE','VIEW','PACKAGE','SEQUENCE','SYNONYM', 'MATERIALIZED VIEW', 'TYPE')
order by object_type;
BEGIN
begin
for object_rec in c_get_objects loop
execute immediate ('drop '||object_rec.object_type||' ' ||object_rec.obj_name);
end loop;
end;
END DROP_ALL_SCHEMA_OBJECTS;
/
execute DROP_ALL_SCHEMA_OBJECTS;
What you've got is a good start.
Here is the rest:
You have a cursor AND a select statement. You only need the cursor.
Your next step is to call the drop statement using dynamic PLSQL. I'd use the EXECUTE IMMEDIATE statement. Its more elegant and preformance friendly to just select the name of the thing you're dropping and submit it as a bind variable to EXECUTE IMMEDIATE.
In order to drop the objects of the schema calling the method and not the schema owning the method you have to use "AUTHID CURRENT_USER". See the Oracle documentation for more info.
Other things to drop: packages, functions, procedures (the system will likely hang then timeout if you try to drop this method while its running), Java classes, triggers, views, types
Lastly, this is obviously a very dangerous method so you may want to consider putting it in a script instead of a stored procedure so it isn't left in the database for anyone to run.
You're close - as someone else has noted you need an "EXECUTE IMMEDIATE" for the statement. You should consider:
Instead of creating a procedure to do this, run this as an anonymous PL/SQL block so you don't have the issue of trying to drop a procedure that is running.
Add a test for object type of TABLE and for that case modify the drop statement to include the cascade option to handle tables that are "parents" of other tables via foreign key constraints. Remember that you'll probably be generating the cursor list in an order that doesn't consider dependencies that will block the drop.
Also on the subject of dependencies, it is probably best to drop tables first (add a DECODE in your cursor that assigns a lower numeric value to this object type and order the cursor select by this value). If you have Oracle objects of type TYPE that are used as column types in a table definition the table must be dropped first.
If you use Oracle Advanced Queuing the objects related to this MUST be dropped with the AQ package API calls. Although you can drop the Oracle-generated tables for queue support with a regular DROP TABLE, you will find yourself in the catch-22 position of then not being able to drop the related queues nor add them back. Up to version 10g at least you couldn't even drop the containing schema without putting the database in a special mode when this situation existed
Thanks Martin Brambley and Vijayan Srinivasan!
But Vijayan Srinivasan's version is not correct, because dependent objects of type 'TYPE' sometime generates errors during drop them:
ORA-02303: cannot drop or replace a type with type or table dependents
My version drop ALL objects from Schema with additional:
drop procedures and functions (expect 'DROP_ALL_SCHEMA_OBJECTS')
drop all jobs and dbms_jobs
drop all db_links
do not drop nested tables, because DROPing of nested tables not supported
CREATE OR REPLACE
procedure DROP_ALL_SCHEMA_OBJECTS AS
PRAGMA AUTONOMOUS_TRANSACTION;
cursor c_get_objects is
select uo.object_type object_type_2,'"'||uo.object_name||'"'||decode(uo.object_type,'TABLE' ,' cascade constraints',null) obj_name2
FROM USER_OBJECTS uo
where uo.object_type in ('TABLE','VIEW','PACKAGE','SEQUENCE','SYNONYM', 'MATERIALIZED VIEW', 'FUNCTION', 'PROCEDURE')
and not (uo.object_type = 'TABLE' and exists (select 1 from user_nested_tables unt where uo.object_name = unt.table_name))
and not (uo.object_type = 'PROCEDURE' and uo.object_name = 'DROP_ALL_SCHEMA_OBJECTS')
order by uo.object_type;
cursor c_get_objects_type is
select object_type, '"'||object_name||'"' obj_name
from user_objects
where object_type in ('TYPE');
cursor c_get_dblinks is
select '"'||db_link||'"' obj_name
from user_db_links;
cursor c_get_jobs is
select '"'||object_name||'"' obj_name
from user_objects
where object_type = 'JOB';
cursor c_get_dbms_jobs is
select job obj_number_id
from user_jobs
where schema_user != 'SYSMAN';
BEGIN
begin
for object_rec in c_get_objects loop
execute immediate ('drop '||object_rec.object_type_2||' ' ||object_rec.obj_name2);
end loop;
for object_rec in c_get_objects_type loop
begin
execute immediate ('drop '||object_rec.object_type||' ' ||object_rec.obj_name);
end;
end loop;
for object_rec in c_get_dblinks loop
execute immediate ('drop database link '||object_rec.obj_name);
end loop;
for object_rec in c_get_jobs loop
DBMS_SCHEDULER.DROP_JOB(job_name => object_rec.obj_name);
end loop;
commit;
for object_rec in c_get_dbms_jobs loop
dbms_job.remove(object_rec.obj_number_id);
end loop;
commit;
end;
END DROP_ALL_SCHEMA_OBJECTS;
/
execute DROP_ALL_SCHEMA_OBJECTS;
drop procedure DROP_ALL_SCHEMA_OBJECTS;
exit;

Resources