it-swarm-eu.dev

Gibt es in PL / pgSQL eine einfache Möglichkeit, zu überprüfen, ob eine Abfrage kein Ergebnis liefert?

Ich experimentiere gerade ein bisschen mit PL/pgSQL und möchte wissen, ob es einen eleganteren Weg gibt, so etwas zu tun:

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

Ausnahmeblöcke dienen zum Überfüllen von Fehlern und nicht zum Überprüfen von Bedingungen. Mit anderen Worten, wenn eine Bedingung zur Kompilierungszeit behandelt werden kann, sollte sie nicht als Fehler abgefangen, sondern durch gewöhnliche Programmlogik behoben werden.

In Abschnitt Trapping Errors in der PL/PgSQL-Dokumentation finden Sie einen solchen Tipp:

Tipp: Ein Block mit einer EXCEPTION-Klausel ist beim Betreten und Beenden erheblich teurer als ein Block ohne eine. Verwenden Sie daher EXCEPTION nicht ohne Notwendigkeit.

Anstatt Ausnahmen (schlecht) oder IF/THEN/ELSIF (besser) zu verwenden, können Sie dies in eine Abfrage umschreiben:

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;

Wenn Sie wirklich zwei Abfragen wünschen, können Sie mit einer speziellen FOUND-Variablen testen, ob die vorherige Abfrage ein Ergebnis geliefert hat:

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;

Obligatorisch RTFM Links folgen :-)

Siehe this für die Beschreibung der Variablen FOUND und this für die Blöcke IF/THEN.

21
filiprem

Sie können eine spezielle Variable FOUND vom Typ Boolean untersuchen. Aus der Dokumentation:

FOUND beginnt bei jedem PL/pgSQL-Funktionsaufruf mit false. Es wird durch jede der folgenden Arten von Anweisungen festgelegt:

Eine SELECT INTO-Anweisung setzt FOUND auf true, wenn eine Zeile zugewiesen ist, auf false, wenn keine Zeile zurückgegeben wird.

Eine PERFORM-Anweisung setzt FOUND auf true, wenn eine oder mehrere Zeilen erzeugt (und verworfen) werden, auf false, wenn keine Zeile erzeugt wird.

Die Anweisungen UPDATE, INSERT und DELETE setzen FOUND auf true, wenn mindestens eine Zeile betroffen ist, auf false, wenn keine Zeile betroffen ist.

Eine FETCH-Anweisung setzt FOUND auf true, wenn eine Zeile zurückgegeben wird, auf false, wenn keine Zeile zurückgegeben wird.

Eine MOVE-Anweisung setzt FOUND auf true, wenn der Cursor erfolgreich neu positioniert wird, andernfalls auf false.

Eine FOR- oder FOREACH-Anweisung setzt FOUND auf true, wenn sie ein- oder mehrmals wiederholt wird, andernfalls auf false. FOUND wird auf diese Weise eingestellt, wenn die Schleife beendet wird. Innerhalb der Ausführung der Schleife wird FOUND nicht durch die Schleifenanweisung geändert, obwohl sie möglicherweise durch die Ausführung anderer Anweisungen innerhalb des Schleifenkörpers geändert wird.

Die Anweisungen RETURN QUERY und RETURN QUERY EXECUTE setzen FOUND auf true, wenn die Abfrage mindestens eine Zeile zurückgibt, auf false, wenn keine Zeile zurückgegeben wird.

Andere PL/pgSQL-Anweisungen ändern den Status von FOUND nicht. Beachten Sie insbesondere, dass EXECUTE die Ausgabe von GET DIAGNOSTICS ändert, FOUND jedoch nicht.

FOUND ist eine lokale Variable in jeder PL/pgSQL-Funktion. Änderungen daran wirken sich nur auf die aktuelle Funktion aus.

14
alexk