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?
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;
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.
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.
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;
/
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
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;