2009-05-12 5 views
3

Je dois retourner un ensemble de lignes à partir d'une procédure Oracle, puis les supprimer dans la même procédure. Existe-t-il une manière ordonnée de faire ceci sans tables temporaires? Quelque chose comme un curseur en mémoire peut-être? Fondamentalement, je saute les dossiers d'une file d'attente, et je veux éviter deux allers-retours parce que c'est un processus très fréquent.Oracle - sélectionnez et supprimez dans une procédure

Répondre

8

En fait, vous pouvez le faire sans SELECT ces jours-ci. Vous pouvez simplement SUPPRIMER les enregistrements qui vous intéressent et utiliser la clause RETURNING pour récupérer ces enregistrements dans une variable locale à mesure qu'ils sont supprimés. La partie un peu ennuyante de cette méthode est que vous avez besoin d'aller chercher chaque colonne dans une variable distincte. Vous ne pouvez pas utiliser un type d'enregistrement dans ce contexte. Donc, si vous avez beaucoup de colonnes, cela peut devenir encombrant.

+0

Serait utile (pour les autres) de déclarer les tableaux (array1, array2) etc avant l'instruction delete, à titre d'exemple pour d'autres ... – AshesToAshes

3

Vous pouvez utiliser un curseur pour la mise à jour, par ex. Remplir les données dans un TYPE et renvoyer cela??

DECLARE 
    CURSOR c_updates 
    IS 
    SELECT * 
    FROM table1 t1 
    LEFT JOIN table2 t2 ON t1.field = t2.field 
    WHERE t2.field IS NULL 
    FOR UPDATE OF t1.field; 

    l_record c_updates%ROWTYPE; 
BEGIN 
    OPEN c_updates; 

    LOOP 
    FETCH c_updates INTO l_record; 
    EXIT WHEN c_updates%NOTFOUND; 

    --Do what you want with l_record 

    DELETE FROM table1 
    WHERE CURRENT OF c_updates; 
    END LOOP; 

    CLOSE c_updates; 
END; 
2

par exemple.

CREATE TYPE blah as (data-columns-go-here) 
/

CREATE TYPE blah_table AS TABLE OF blah; 
/
2
bâtiment

sur reubenpeeris' answer et cagcowboy's answer:

AVERTISSEMENT: Je n'ai pas accès à un compilateur PL/SQL pour le moment, donc il y a une chance que quelque chose ne va pas.

TYPE popped_records_table_type IS TABLE OF my_table%ROWTYPE INDEX BY BINARY_INTEGER; 

FUNCTION pop_records(...) RETURN popped_records_table_type IS 
    popped_records popped_records_table_type; 
    popped_record my_table%ROWTYPE; 
    next_popped_record_index BINARY_INTEGER; 

    CURSOR popped_records_cursor IS 
     SELECT * FROM my_table WHERE ... FOR UPDATE; 
BEGIN 
    next_popped_record_index := 1; 

    OPEN popped_records_cursor; 

    LOOP 
     FETCH popped_records_cursor INTO popped_record; 
     EXIT WHEN popped_records_cursor%NOTFOUND; 

     DELETE FROM my_table WHERE CURRENT OF popped_records_cursor; 

     popped_records(next_popped_record_index) := popped_record; 
     next_popped_record_index := next_popped_record_index + 1; 
    END LOOP; 

    CLOSE popped_records_cursor; 

    RETURN popped_records; 
END; 

Edit: Je crois que cela va également travailler avec une procédure stockée, tant que vous fournissez une instance du popped_records_table_type comme paramètre IN/OUT:

PROCEDURE pop_records(popped_records IN OUT popped_records_table_type, ...) IS 
    -- Pretty much the same as above 
3

Vous pouvez retourner un curseur de une procédure ou un bloc anonyme:

BEGIN 
     OPEN :cur FOR 
     SELECT * 
     FROM table 
     WHERE condition; 

     DELETE 
     FROM table 
     WHERE condition; 

END; 

Le curseur est conservé après la suppression.

Voir l'entrée dans mon blog pour des explications détaillées:

, et est ici cette entrée en un mot:

CREATE TABLE t_deleter (id INT NOT NULL PRIMARY KEY, value VARCHAR2(50)) 
/
INSERT 
INTO t_deleter (id, value) 
VALUES (1, 'Value 1') 
/
INSERT 
INTO t_deleter (id, value) 
VALUES (2, 'Value 2') 
/
COMMIT 
/
SELECT * 
FROM t_deleter 
/
VAR cur REFCURSOR 
BEGIN 
     OPEN :cur FOR 
     SELECT * 
     FROM t_deleter 
     WHERE id = 1; 
     DELETE 
     FROM t_deleter 
     WHERE id = 1; 
END; 
/
PRINT cur 
SELECT * 
FROM t_deleter 
/

Table created. 


1 row created. 


1 row created. 


Commit complete. 


     ID VALUE 
---------- -------------------------------------------------- 
     1 Value 1 
     2 Value 2 


PL/SQL procedure successfully completed. 


/* 
    PRINT CUR 
    This is what returned to the client 
*/ 

     ID VALUE 
---------- -------------------------------------------------- 
     1 Value 1 

/* 
    SELECT * 
    FROM t_deleter 

    This is what's left after the procedure completed 
*/ 


     ID VALUE 
---------- -------------------------------------------------- 
     2 Value 2 
0

Oracle a quelque chose d'appeler la mise en file d'attente avancée, il est peut-être préférable d'utiliser cette fonctionnalité plutôt que de créer votre propre système de mise en file d'attente.

+1

je voudrais examiner cela, mais nous essayons de ne pas lier à oracle de trop près –

Questions connexes