PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

So geben Sie einen Wert von einer Funktion zurück, wenn kein Wert gefunden wird

Erklärung

Die Wurzel des Problems ist die unscharfe Definition von „nichts“.

NULL ist nicht nichts , es ist nur unbekannt, was es genau ist. "Nichts" in Bezug auf SQL wäre keine Zeile :Es wird überhaupt nichts zurückgegeben. Dies geschieht normalerweise, wenn keine Zeile gefunden wird. Aber bei der Verwendung von Aggregatfunktionen , das kann nicht passieren, weil laut Dokumentation:

avg() gibt NULL zurück wenn keine Zeilen gefunden werden (also nicht "nichts"). Sie erhalten eine Zeile mit einem NULL Wert als Ergebnis - der überschreibt Ihren Init-Wert in dem Code, den Sie demonstrieren.

Lösung

Schließen Sie das Ergebnis in COALESCE ein . Demonstration einer viel einfacheren SQL-Funktion:

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.

Dasselbe kann in einer plpgsql-Funktion verwendet werden. Diese Funktion kann STABLE sein , kann bei größeren Abfragen die Leistung verbessern.

Andere Fälle

Wenn Sie wirklich können bekomme keine Zeile aus einer Abfrage ein einfaches COALESCE würde scheitern , weil es nie ausgeführt wird.

Für einen einzelnen Wert Als Ergebnis können Sie die gesamte Abfrage einfach wie folgt umschließen:

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

PL/pgSQL hat die Fähigkeit zu prüfen, bevor es tatsächlich von der Funktion zurückkehrt. Dies funktioniert für mehrere Zeilen mit einer oder mehreren Spalten , zu. Es gibt ein Beispiel in das Handbuch Demonstration der Verwendung von FOUND :

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

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

Verwandte:

Um immer genau eine Zeile zurückzugeben , können Sie auch reines SQL verwenden :

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

Wenn das erste SELECT gibt keine Zeile zurück, die zweite SELECT gibt eine Zeile mit Standardwerten zurück.