web-dev-qa-db-fra.com

Comment sélectionner une variable en PL / SQL lorsque le résultat peut être nul?

Existe-t-il un moyen de simplement exécuter une requête une fois pour la sélectionner dans une variable, sachant que la requête risque de ne rien renvoyer; dans ce cas, la variable doit être null.

Actuellement, je ne peux pas faire un select into une variable directement, car si la requête ne renvoie rien, la variable PL/SQL se plaindrait que la variable ne soit pas définie. Je ne peux exécuter la requête que deux fois. Le premier compte et si le nombre est égal à zéro, définissez la variable sur null et si le nombre est égal à 1, sélectionnez-le dans la variable.

Donc, le code serait comme:

v_column my_table.column%TYPE;
v_counter number;
select count(column) into v_counter from my_table where ...;
if (v_counter = 0) then
    v_column := null;
elsif (v_counter = 1) then
    select column into v_column from my_table where ...;
end if;

merci.

Mise à jour: La raison pour laquelle je n'ai pas utilisé exception est que j'ai toujours une certaine logique à suivre après avoir affecté le v_column, et que je dois utiliser goto dans la section exception pour revenir au code suivant. Je suis un peu hésitant de goto lignes.

65
Sapience

Vous pouvez simplement gérer l'exception NO_DATA_FOUND en définissant votre variable sur NULL. De cette façon, une seule requête est requise.

    v_column my_table.column%TYPE;

BEGIN

    BEGIN
      select column into v_column from my_table where ...;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        v_column := NULL;
    END;

    ... use v_column here
END;
107
Adam Paynter

Je sais que c'est un vieux fil, mais je pense toujours qu'il vaut la peine d'y répondre.

select (
        SELECT COLUMN FROM MY_TABLE WHERE ....
        ) into v_column
from dual;

Exemple d'utilisation:

declare v_column VARCHAR2(100);
begin
  select (SELECT TABLE_NAME FROM ALL_TABLES WHERE TABLE_NAME = 'DOES NOT EXIST')
  into v_column 
  from dual;
  DBMS_OUTPUT.PUT_LINE('v_column=' || v_column);
end;
14
jpe

Utiliser une déclaration Cursor FOR LOOP est ma manière préférée de le faire.

Il est plus sûr d'utiliser un curseur explicite, car vous n'avez pas besoin de vous rappeler de le fermer, vous ne pouvez donc pas "laisser fuir" les curseurs.

Vous n'avez pas besoin de variables "en", vous n'avez pas besoin de "FETCH", vous n'avez pas besoin d'attraper et de gérer les exceptions "NO DATA FOUND".

Essayez, vous ne reviendrez jamais.

v_column my_table.column%TYPE;

v_column := null;

FOR rMyTable IN (SELECT COLUMN FROM MY_TABLE WHERE ....) LOOP
  v_column := rMyTable.COLUMN;
  EXIT;  -- Exit the loop if you only want the first result.
END LOOP;
7
jmc

Qu'en est-il de l'utilisation de MAX? Ainsi, si aucune donnée n'est trouvée, la variable est définie sur NULL, sinon, la valeur maximale.
Puisque vous attendez 0 ou 1 valeur, MAX devrait pouvoir être utilisé.

v_column my_table.column%TYPE;
select MAX(column) into v_column from my_table where ...;
6
Björn

De toutes les réponses ci-dessus, réponse de Björn semble être la plus élégante et la plus courte. J'ai personnellement utilisé cette approche plusieurs fois. La fonction MAX ou MIN fera le travail aussi bien. Complet PL/SQL suit, juste la clause where doit être spécifiée.

declare v_column my_table.column%TYPE;
begin
    select MIN(column) into v_column from my_table where ...;
    DBMS_OUTPUT.PUT_LINE('v_column=' || v_column);
end;
4
schemerys

Je recommanderais d'utiliser un curseur. Une extraction de curseur est toujours une seule ligne (sauf si vous utilisez une collection en bloc), et les curseurs ne lancent pas automatiquement les exceptions no_data_found ou too_many_rows; Cependant, vous pouvez inspecter l'attribut curseur une fois ouvert pour déterminer si vous avez une ligne et combien.

declare
v_column my_table.column%type;
l_count pls_integer;
cursor my_cursor is
  select count(*) from my_table where ...;

begin
  open my_cursor;
    fetch my_cursor into l_count;
  close my_cursor;

  if l_count = 1 then
    select whse_code into v_column from my_table where ...;
  else
    v_column := null;
  end if;
end;

Ou, encore plus simple:

    declare
    v_column my_table.column%type;
    cursor my_cursor is
      select column from my_table where ...;

    begin
      open my_cursor;
        fetch my_cursor into v_column;
        -- Optional IF .. THEN based on FOUND or NOTFOUND
        -- Not really needed if v_column is not set
        if my_cursor%notfound then
          v_column := null;
        end if;
      close my_cursor;
    end;
3
Wolf

J'utilise cette syntaxe pour plus de flexibilité et de rapidité -

    begin
    --
    with KLUJ as
    ( select 0 ROES from dual
       union 
      select count(*) from MY_TABLE where rownum = 1
    ) select max(ROES) into has_rows from KLUJ;
    --
    end;

Dual renvoie 1 ligne, rownum ajoute 0 ou 1 ligne et max () à exactement 1. Cela donne 0 pour aucune ligne dans une table et 1 pour tout autre nombre de lignes.

J'étend la clause where pour compter les lignes par condition, supprime rownum pour compter les lignes répondant à une condition et j'augmente rownum pour compter les lignes répondant à la condition jusqu'à une limite.

2
user2168235