Question

J'ai quelques scénarios:

  1. Besoin de lire la valeur d'une colonne de trois tables différentes dans un ordre prédéfini et une seule table aura les données

  2. Lire les données de la table 1 si des enregistrements sont présents pour les critères, sinon lire les données de la Table2 pour les critères donnés

Dans les procédures stockées Oracle

Pour les traiter maintenant, il faut d'abord obtenir le nombre d'une requête donnée dans une variable, et si le nombre > 0, nous exécutons la même requête pour lire les données réelles comme dans:

select count(*) from table1 into v_count
if v_count > 0
then
    select data into v_data from table1
end if;

Return v_data

Ceci est fait pour éviter l'exception no_data_found, sinon il me faudrait trois blocs de gestionnaire d'exception pour intercepter l'exception no_data_found pour chaque accès à une table.

Actuellement, je suis en train de réimplémenter cela avec des curseurs afin d'avoir quelque chose comme ça:

cursor C1 is
    select data from table1;
Open C1
Fetch C1 into v_data
if C1%FOUND
then
    Close C1
    Return v_data
End If

Je voulais savoir lequel est le meilleur du point de vue des performances: celui avec Curseurs ou celui qui convertit une variable en variable avec trois blocs d'exception no_data_found. Je ne veux pas utiliser le processus de requête en deux étapes que nous avons actuellement.

Était-ce utile?

La solution

Je ne sais pas pourquoi vous êtes si désireux d'éviter l'exception? Quel est le problème avec:

begin
    begin
        select data into v_data from table1;
    exception
        when no_data_found then
        begin
            select data into v_data from table2;
        exception
            when no_data_found then
            begin
               select data into v_data from table3;
            exception
                when no_data_found then
                    v_data := null;
            end;
        end;
    end;
    return v_data;
end;

Je pense que cela fonctionnera mieux que votre autre solution car elle fait le minimum de travail possible pour atteindre le résultat souhaité.

Voir Comment ignorer l'exception Oracle DUP_VAL_ON_INDEX? où I démontrer que l'utilisation des exceptions est plus efficace que le comptage pour voir s'il existe des données.

Autres conseils

select count(*) from table1 into v_count
if v_count > 0 then
    select data into v_data from table1;
else
    v_data := null;
end if;
return v_data;

n'est pas équivalent à

begin
    select data into v_data from table1;
    return v_data;
exception
    when no_data_found then
        return null;
end;

dans un environnement multi-utilisateur. Dans le premier cas, quelqu'un pourrait mettre à jour la table entre les points où vous vérifiez l'existence et lorsque vous lisez les données.

En ce qui concerne les performances, je ne sais pas ce qui est préférable, mais je sais que la première option permet d'effectuer deux commutations de contexte vers le moteur SQL et que la seconde ne modifie qu'un contexte.

La façon dont vous gérez le scénario 1 n’est pas bonne. Non seulement vous faites deux requêtes quand une seule suffit, mais, comme le souligne Erik, cela ouvre la possibilité de données échangées entre les deux requêtes (sauf si vous utilisez une transaction en lecture seule ou sérialisable).

Etant donné que vous dites que dans ce cas, les données figureront exactement dans l'un des trois tableaux, qu'en est-il de cela?

SELECT data
  INTO v_data FROM
  (SELECT data FROM table1
   UNION ALL
   SELECT data FROM table2
   UNION ALL
   SELECT data FROM table3
  )

Une autre "astuce" vous pouvez utiliser pour éviter d'écrire plusieurs gestionnaires sans données trouvées:

SELECT MIN(data) INTO v_data FROM table1;
IF v_data IS NOT NULL THEN
   return v_data;
END IF;

SELECT MIN(data) INTO v_data FROM table2;
...etc...

mais je ne vois vraiment aucune raison qui soit meilleure que d'avoir trois gestionnaires d'exception.

Pour votre deuxième scénario, je pense que ce que vous voulez dire, c'est qu'il peut y avoir des données dans les deux tables et que vous souhaitez utiliser les données de table1, le cas échéant, sinon utilisez les données de la table 2. Encore une fois, vous pouvez le faire en une seule fois. requête:

SELECT data
  INTO v_data FROM
  (SELECT data FROM
    (SELECT 1 sort_key, data FROM table1
     UNION ALL
     SELECT 2 sort_key, data FROM table2
    )
   ORDER BY sort_key ASC
  )
  WHERE ROWNUM = 1

Une version améliorée de l'option MIN de "Dave Costa" ...

SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;

Maintenant, v_rowcount peut être vérifié pour les valeurs 0, > 1 (supérieures à 1) où la requête de sélection normale renvoie NO_DATA_FOUND ou TOO_MANY_ROWS exception. Valeur " 1 " indiquera qu’une seule ligne existe et servira notre objectif.

DECLARE
    A VARCHAR(35);
    B VARCHAR(35);
BEGIN
    WITH t AS
    (SELECT OM_MARCA, MAGAZIA FROM ifsapp.AKER_EFECTE_STOC WHERE (BARCODE = 1000000491009))
    SELECT
    (SELECT OM_MARCA FROM t) OM_MARCA,
    (SELECT MAGAZIA FROM t) MAGAZIA
    INTO A, B
    FROM DUAL;
    IF A IS NULL THEN
       dbms_output.put_line('A este null');
    END IF;
    dbms_output.put_line(A);
    dbms_output.put_line(B);
END;
/

Utilisez le " pour la ligne dans le curseur " forme d'une boucle et la boucle ne sera tout simplement pas traitée s'il n'y a pas de données:

declare cursor
t1Cur is
 select ... from table1;
t2Cur is
 select ... from table2;
t3Cur is
 select ... from table3;
t1Flag boolean FALSE;
t2Flag boolean FALSE;
t3Flag boolean FALSE;
begin
for t1Row in t1Cur loop
  ... processing, set t1Flag = TRUE
end loop;
for t2Row in t2Cur loop
  ... processing, set t2Flag = TRUE
end loop;
for t3Row in t3Cur loop
  ... processing, set t3Flag = TRUE
end loop;
... conditional processing based on flags
end;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top