Czy w PL / pgSQL istnieje prosty sposób sprawdzenia, czy zapytanie nie zwróciło żadnego wyniku?

16

Obecnie eksperymentuję trochę z PL / pgSQL i chcę wiedzieć, czy istnieje bardziej elegancki sposób na zrobienie czegoś takiego:

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;
Icefex
źródło

Odpowiedzi:

21

Bloki wyjątków służą do wychwytywania błędów, a nie sprawdzania warunków. Innymi słowy, jeśli jakiś warunek może być obsłużony w czasie kompilacji, nie powinien być uwięziony jako błąd, ale rozwiązany przez zwykłą logikę programu.

W sekcji Błędy pułapkowania w dokumentacji PL / PgSQL można znaleźć taką wskazówkę:

Wskazówka: Blok zawierający klauzulę WYJĄTKOWOŚĆ jest znacznie droższy przy wchodzeniu i wychodzeniu niż blok bez niej. Dlatego nie używaj WYJĄTKU bez potrzeby.

Zamiast używać wyjątków (zły) lub IF / THEN / ELSIF (lepszy), możesz przepisać to na jedno zapytanie:

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;

Jeśli naprawdę chcesz dwa zapytania, możesz użyć specjalnej zmiennej FOUND, aby sprawdzić, czy poprzednie zapytanie dało jakikolwiek wynik:

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;

Obowiązkowe linki RTFM obserwują :-)

Zobacz to dla opisu FOUNDzmiennej, a to dla IF/ THENbloków.

filiprem
źródło
13

Możesz sprawdzić specjalną zmienną FOUND typu boolean. Z dokumentacji:

FOUND zaczyna fałsz w każdym wywołaniu funkcji PL / pgSQL. Ustawia go każdy z następujących typów instrukcji:

Instrukcja SELECT INTO ustawia ZNALEZIONO true, jeśli wiersz jest przypisany, false, jeśli żaden wiersz nie jest zwracany.

Instrukcja PERFORM ustawia ZNALEZIONĄ wartość true, jeśli produkuje (i odrzuca) jeden lub więcej wierszy, fałsz, jeśli żaden wiersz nie jest generowany.

Instrukcje UPDATE, INSERT i DELETE ustawiają FUNDACJA na true, jeśli ma to wpływ na co najmniej jeden wiersz, false, jeśli nie ma to wpływu na żaden wiersz.

Instrukcja FETCH ustawia ZNALEZIONĄ wartość true, jeśli zwraca wiersz, fałsz, jeśli żaden wiersz nie jest zwracany.

Instrukcja MOVE ustawia ZNALEZIONO wartość true, jeśli z powodzeniem zmienia położenie kursora, w przeciwnym razie wartość false.

Instrukcja FOR lub FOREACH ustawia ZNALEZIONĄ wartość true, jeśli iteruje jeden lub więcej razy, w przeciwnym razie fałsz. FOUND jest ustawiany w ten sposób, gdy pętla wychodzi; wewnątrz wykonywania pętli FOUND nie jest modyfikowany przez instrukcję pętli, chociaż może zostać zmieniony przez wykonanie innych instrukcji w treści pętli.

RETURN QUERY i RETURN QUERY EXECUTE instrukcje ustawione FUNDACJA true, jeśli zapytanie zwraca co najmniej jeden wiersz, false, jeśli żaden wiersz nie jest zwracany.

Inne instrukcje PL / pgSQL nie zmieniają stanu FUNDACJI. W szczególności zauważ, że EXECUTE zmienia dane wyjściowe GET DIAGNOSTICS, ale nie zmienia FOUND.

FOUND jest lokalną zmienną w ramach każdej funkcji PL / pgSQL; wszelkie zmiany w nim wpływają tylko na bieżącą funkcję.

alexk
źródło
ale to, select intoże nie zwraca żadnych danych, nadal spowoduje wyjątek, prawda?
Jack mówi, że spróbuj topanswers.xyz
3
generalnie nie, podnosi wyjątki tylko wtedy, gdy określona jest klauzula
STRICT
ah tak, mój zły - choć czy to nie znaczy, że moduł obsługi wyjątków w przykładzie PO nigdy się nie uruchomi? :-)
Jack mówi, spróbuj wypróbować topanswers.xyz 11.01.12
1
@JackDouglas: Żadne dane nie są generalnie przyczyną wyjątku (z wyjątkiem szczególnych przypadków, takich jak modyfikator STRICT powyżej). OP miał tam błędne przekonanie.
Erwin Brandstetter