web-dev-qa-db-fra.com

Suppression de toutes les tables/séquences utilisateur dans Oracle

Dans le cadre de notre processus de construction et de notre base de données en évolution, j'essaie de créer un script qui supprimera toutes les tables et séquences d'un utilisateur. Je ne veux pas recréer l'utilisateur, car cela nécessitera plus d'autorisations que celles autorisées. 

Mon script crée une procédure pour supprimer les tables/séquences, exécute la procédure, puis supprime la procédure. J'exécute le fichier depuis sqlplus:

drop.sql:


create or replace procedure drop_all_cdi_tables
is
cur integer;
begin
cur:= dbms_sql.OPEN_CURSOR();
for t in (select table_name from user_tables) loop
execute immediate 'drop table ' ||t.table_name|| ' cascade constraints';
end loop;
dbms_sql.close_cursor(cur);

cur:= dbms_sql.OPEN_CURSOR();
for t in (select sequence_name from user_sequences) loop
execute immediate 'drop sequence ' ||t.sequence_name;
end loop;
dbms_sql.close_cursor(cur);
end;
/
execute drop_all_cdi_tables;
/
drop procedure drop_all_cdi_tables;
/

Malheureusement, abandonner la procédure pose un problème. Il semble y avoir une condition de concurrence critique et la procédure est abandonnée avant son exécution.
Par exemple.:

 SQL * Plus: Version 11.1.0.7.0 - Production le mar 30 mars 18:45:42 2010 

 Copyright (c) 1982, 2008, Oracle. Tous les droits sont réservés.


 Connecté à:
 Oracle Database 11g Édition Entreprise, version 11.1.0.7.0 - Production 64 bits 
 Avec les options Partitionnement, OLAP, Data Mining et Real Application Testing 


 Procédure créée .


 Procédure PL/SQL terminée avec succès .


 Procédure créée .


 Procédure abandonnée .

 déposer la procédure drop_all_user_tables 
 * 
 ERREUR à la ligne 1: 
 ORA-04043: l'objet DROP_ALL_USER_TABLES n'existe pas 


 SQL> Déconnecté de la base de données Oracle Enterprise Edition 11.1.0.7.0 - 64 
 Avec les options Partitionnement, OLAP, Data Mining et Real Application Testing 

Des idées sur la façon de faire fonctionner cela?

30
Ambience

Si vous ne souhaitez pas conserver la procédure stockée, j'utiliserais un bloc PLSQL anonymous :

BEGIN

  --Bye Sequences!
  FOR i IN (SELECT us.sequence_name
              FROM USER_SEQUENCES us) LOOP
    EXECUTE IMMEDIATE 'drop sequence '|| i.sequence_name ||'';
  END LOOP;

  --Bye Tables!
  FOR i IN (SELECT ut.table_name
              FROM USER_TABLES ut) LOOP
    EXECUTE IMMEDIATE 'drop table '|| i.table_name ||' CASCADE CONSTRAINTS ';
  END LOOP;

END;
76
OMG Ponies

Pour une instruction SQL, le point-virgule à la fin exécute l'instruction . Le/exécute l'instruction précédente . En tant que tel, vous terminez les lignes de

drop procedure drop_all_cdi_tables;
/

va abandonner la procédure, puis réessayez.

Si vous regardez votre résultat, vous verrez «PROCEDURE CREATED», puis exécuté, puis «PROCEDURE CREATED» à nouveau lorsqu'il ré-exécutera la dernière instruction (EXECUTE est une commande SQL * Plus, pas une instruction, elle n'est donc pas mise en mémoire tampon ) puis "PROCEDURE DROPPED" puis il essaie (et échoue) de le supprimer une deuxième fois.

PS. Je suis d'accord avec Dougman sur les appels DBMS_SQL impairs. 

6
Gary Myers

Il semble que votre exemple de message d'erreur reçoive une erreur sur drop_all_user_tables mais l'exemple que vous avez donné concerne drop_all_cdi_tables. Le code drop_all_user_tables est-il différent?

De plus, vous avez des appels à dbms_sql, mais vous ne semblez pas l'utiliser, ne faites aucune analyse.

2
Doug Porter

En plus de la solution présentée par OMG Ponies, si vous avez des séquences avec des espaces, vous devez améliorer un peu la PLSQL:

BEGIN
  FOR i IN (SELECT sequence_name FROM user_sequences)
    Loop
      EXECUTE IMMEDIATE('"DROP SEQUENCE ' || user || '"."' || i.sequence_name || '"');
    End Loop;
End;
/
1
bravenoob

Pour une raison quelconque, la solution OMG Ponies a donné une erreur "La commande SQL n'a pas été correctement terminée" sur PLSQL. Si quelqu'un d'autre rencontre le même problème, voici comment j'ai pu supprimer toutes les tables du schéma actuel.

DECLARE
  table_name VARCHAR2(30);
  CURSOR usertables IS SELECT * FROM user_tables WHERE table_name NOT LIKE 'BIN$%';
BEGIN
  FOR i IN usertables
  LOOP
  EXECUTE IMMEDIATE 'drop table ' || i.table_name || ' cascade constraints';
  END LOOP;
END;
/

Crédits: Snippler

0
ZerosAndOnes

Il suffit d’exécuter ces deux instructions, puis tous les résultats:

select 'drop table ' || table_name || ';' from user_tables;
select 'drop sequence ' || sequence_name || ';' from user_sequences;
0
Ahmed Elgamal