PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment renvoyer une valeur d'une fonction si aucune valeur n'est trouvée

Explication

La racine du problème est la définition floue de "pas n'importe quoi".

NULL n'est pas rien , on ne sait pas ce que c'est exactement. "Rien" en termes de SQL serait aucune ligne :rien n'est retourné du tout. Cela se produit généralement lorsqu'aucune ligne n'est trouvée. Mais lors de l'utilisation de fonctions d'agrégation , cela ne peut pas arriver car, par documentation :

avg() renvoie NULL lorsqu'aucune ligne n'est trouvée (donc pas "rien"). Vous obtenez une ligne avec un NULL valeur comme résultat - qui écrase votre valeur init dans le code que vous démontrez.

Solution

Enveloppez le résultat dans COALESCE . Démonstration d'une fonction SQL beaucoup plus simple :

CREATE OR REPLACE FUNCTION get_height_sql(firstn varchar, lastn varchar)
  RETURNS float AS
$func$
   SELECT COALESCE(AVG(((p.h_feet * 12) + p.h_inches) * 2.54)::float, 0)
   FROM   player p
   WHERE  p.firstname = firstn
   AND    p.lastname = lastn
$func$  LANGUAGE sql STABLE;

SQL Fiddle.

La même chose peut être utilisée dans une fonction plpgsql. Cette fonction peut être STABLE , peut améliorer les performances dans le contexte de requêtes plus volumineuses.

Autres cas

Si vous pouvez réellement obtenir aucune ligne à partir d'une requête, un simple COALESCE échouerait , car il n'est jamais exécuté.

Pour une valeur unique résultat, vous pouvez simplement envelopper toute la requête comme :

SELECT COALESCE((SELECT some_float FROM ... WHERE ... LIMIT 1), 0) AS result

PL/pgSQL a la capacité de vérifier avant de réellement revenir de la fonction. Cela fonctionne pour plusieurs lignes avec une ou plusieurs colonnes , aussi. Il existe un exemple dans le manuel démontrant l'utilisation de FOUND :

...
RETURN QUERY SELECT foo, bar ...;

IF NOT FOUND THEN
    RETURN QUERY VALUES ('foo_default'::text, 'bar_default'::text);
END IF;
...

Connexe :

Pour toujours renvoyer exactement une ligne , vous pouvez également utiliser SQL pur :

SELECT foo, bar FROM tbl
UNION ALL
SELECT 'foo_default', 'bar_default'
LIMIT 1;

Si le premier SELECT ne renvoie aucune ligne, la seconde SELECT renvoie une ligne avec les valeurs par défaut.