web-dev-qa-db-fra.com

Existe-t-il un moyen simple en PL / pgSQL de vérifier si une requête n'a retourné aucun résultat?

J'expérimente actuellement un peu avec PL/pgSQL et je veux savoir s'il existe une façon plus élégante de faire quelque chose comme ceci:

select c.data into data from doc c where c.doc_id = id and c.group_cur > group_cur order by c.id desc limit 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        select c.data into data from doc c where c.doc_id = id and c.global_cur > global_cur order by c.id desc limit 1;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN NULL;
17
icefex

Les blocs d'exception sont destinés à intercepter les erreurs, pas à vérifier les conditions. En d'autres termes, si une condition peut être gérée au moment de la compilation, elle ne doit pas être piégée comme une erreur mais résolue par la logique de programme ordinaire.

Dans section Trapping Errors de la documentation PL/PgSQL vous pouvez trouver une telle astuce:

Conseil: Un bloc contenant une clause EXCEPTION est beaucoup plus cher à entrer et à quitter qu'un bloc sans un. Par conséquent, n'utilisez pas EXCEPTION sans besoin.

Au lieu d'utiliser des exceptions (mauvaises) ou IF/THEN/ELSIF (mieux), vous pouvez réécrire ceci dans une requête:

SELECT c.data into data
FROM  doc c
WHERE c.doc_id = id
  and (
    c.group_cur > group_cur
    or
    c.global_cur > global_cur
  )
ORDER BY
  -- this will make group always preferred over global
  case when c.group_cur > group_cur then 1 else 2 end ASC,
  -- and this is your normal ordering
  c.id DESC
limit 1;

Si vous voulez vraiment deux requêtes, vous pouvez utiliser une variable FOUND spéciale pour tester si la requête précédente a donné un résultat:

select c.data into data
from doc c
where c.doc_id = id and c.group_cur > group_cur
order by c.id desc limit 1;
if not found then
    select c.data into data
    from doc c
    where c.doc_id = id and c.global_cur > global_cur
    order by c.id desc limit 1;
    if not found then return null; end if;
end if;

Obligatoire RTFM liens suivants :-)

Voir this pour la description de la variable FOUND, et this pour les blocs IF/THEN.

21
filiprem

Vous pouvez examiner une variable spéciale FOUND d'un type booléen. De la documentation:

FOUND commence faux dans chaque appel de fonction PL/pgSQL. Il est défini par chacun des types d'instructions suivants:

Une instruction SELECT INTO définit FOUND true si une ligne est affectée, false si aucune ligne n'est renvoyée.

Une instruction PERFORM définit FOUND true si elle produit (et supprime) une ou plusieurs lignes, false si aucune ligne n'est produite.

Les instructions UPDATE, INSERT et DELETE définissent FOUND true si au moins une ligne est affectée, false si aucune ligne n'est affectée.

Une instruction FETCH définit FOUND true si elle renvoie une ligne, false si aucune ligne n'est renvoyée.

Une instruction MOVE définit FOUND true si elle repositionne correctement le curseur, false dans le cas contraire.

Une instruction FOR ou FOREACH définit FOUND true si elle itère une ou plusieurs fois, sinon false. FOUND est défini de cette façon lorsque la boucle se termine; à l'intérieur de l'exécution de la boucle, FOUND n'est pas modifié par l'instruction de boucle, bien qu'il puisse être modifié par l'exécution d'autres instructions dans le corps de la boucle.

Les instructions RETURN QUERY et RETURN QUERY EXECUTE définissent FOUND true si la requête renvoie au moins une ligne, false si aucune ligne n'est renvoyée.

Les autres instructions PL/pgSQL ne modifient pas l'état de FOUND. Notez en particulier qu'EXECUTE modifie la sortie de GET DIAGNOSTICS, mais ne change pas FOUND.

FOUND est une variable locale dans chaque fonction PL/pgSQL; ses modifications n'affectent que la fonction actuelle.

14
alexk