2010-08-11 2 views
2

EDIT: modification du titre pour l'adapter au code ci-dessous.Comment puis-je vérifier une condition IN par rapport à une liste dynamique dans Oracle?

J'essaie de récupérer une liste de valeurs acceptables à partir d'une table Oracle, puis d'effectuer un SELECT par rapport à un autre en comparant certains champs à cette liste. J'essayais de le faire avec des curseurs (comme ci-dessous), mais cela échoue.

DECLARE 
    TYPE gcur IS REF CURSOR; 
    TYPE list_record IS TABLE OF my_table.my_field%TYPE; 
    c_GENERIC gcur; 
    c_LIST list_record; 
BEGIN 
    OPEN c_GENERIC FOR 
    SELECT my_field FROM my_table 
    WHERE some_field = some_value; 

    FETCH c_GENERIC BULK COLLECT INTO c_LIST; 

    -- try to check against list 
    SELECT * FROM some_other_table 
    WHERE some_critical_field IN c_LIST; 

END 

Fondamentalement, ce que je suis en train de faire est de mettre en cache la liste des valeurs acceptables dans une variable, parce que je vais vérifier à plusieurs reprises contre elle plus tard.

Comment procédez-vous dans Oracle?

+0

Annoyingly, votre code fonctionnerait parfaitement si votre opération finale était un UPDATE ou un DELETE - ce sont seulement des SELECT qui n'acceptent pas le bulk-binding comme une entrée. – JulesLt

+1

btw, vous avez une fuite de ressources - n'ont pas fermé le curseur ref. Pourquoi pas bon vieux curseur local? –

Répondre

4

Nous pouvons utiliser des collections pour stocker des valeurs en fonction de vos besoins, mais ils doivent être déclarés comme types SQL:

create type list_record is table of varchar2(128) 
/

Ceci parce que nous ne pouvons pas utiliser les types PL/SQL dans les instructions SQL. Hélas, cela signifie que nous ne pouvons pas utiliser %TYPE ou %ROWTYPE, car ce sont des mots-clés PL/SQL.

Votre procédure serait alors ressembler à ceci:

DECLARE 
    c_LIST list_record; 
BEGIN 

    SELECT my_field 
    BULK COLLECT INTO c_LIST 
    FROM my_table 
    WHERE some_field = some_value; 

    -- try to check against list 
    SELECT * FROM some_other_table 
    WHERE some_critical_field IN (select * from table (c_LIST); 

END;  

« Je vois que vous aviez encore d'effectuer une instruction SELECT pour remplir la liste la clause IN. »

Si les valeurs sont dans une table il n'y a pas d'autre moyen de les obtenir dans une variable :)

« Je pense qu'il ya un gain de performance significatif en utilisant ceci sur une directe semi-jointure "

Pas nécessairement. Si vous utilisez uniquement les valeurs une fois, la sous-requête est certainement la meilleure approche. Mais comme vous voulez utiliser les mêmes valeurs dans un certain nombre de requêtes discrètes, le remplissage d'une collection est l'approche la plus efficace.

Dans 11g Enterprise Edition, nous avons la possibilité d'utiliser result set caching. C'est une solution bien meilleure, mais qui n'est pas adaptée à toutes les tables.

+0

Merci. Je comprends ce que vous dites, mais je vois que vous deviez encore effectuer une instruction SELECT pour remplir la liste pour la clause IN. Je pense qu'il y a un gain de performance significatif en utilisant ceci sur une semi-jointure directe (comme proposé par Adam Musch ci-dessous)? :) –

1

Pourquoi tirer la liste au lieu d'utiliser une semi-jointure?

SELECT * 
    FROM some_other_table 
WHERE some_critical_field IN (SELECT my_field 
           FROM my_table 
           WHERE some_field = some_value); 
+0

Parce que l'instruction SELECT primaire peut être répétée. Je pensais que tous les SELECTs imbriqués seraient inefficaces si le nombre d'itérations était vraiment élevé, donc j'essaye de cacher ma liste à la place. –

+0

Pour ne pas paraître sarcastique, mais il semble que vous pensiez que vous avez un problème d'optimisation des performances, pas que vous sachiez que vous en avez un. Je recommanderais de comparer ce que j'ai fourni à la solution d'APC pour voir s'il y a une différence significative. –

+0

En fait, je sais que j'ai un problème d'optimisation.Je suis coincé en train de refactoriser le code de quelqu'un d'autre dans l'aube en ce moment parce qu'un SP composé de blocs comme le pseudo-code que je code ci-dessus est en train de se retourner contre nos grands ensembles de données. :) À vrai dire, je suis vraiment intéressé par l'analyse comparative de vos deux solutions pour satisfaire ma curiosité, mais c'est juste que je préfère essayer quelque chose de nouveau pour finir avec ça. : D –

Questions connexes