Есть ли простой способ в PL / pgSQL, чтобы проверить, если запрос не дал результата?

16

В настоящее время я немного экспериментирую с PL / pgSQL и хочу узнать, есть ли более элегантный способ сделать что-то вроде этого:

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
источник

Ответы:

21

Блоки исключений предназначены для отслеживания ошибок, а не проверки условий. Другими словами, если какое-то условие может быть обработано во время компиляции, оно не должно восприниматься как ошибка, а разрешаться обычной программной логикой.

В разделе Trapping Errors документации PL / PgSQL вы можете найти такой совет:

Совет: блок, содержащий предложение EXCEPTION, значительно дороже для входа и выхода, чем блок без такового. Поэтому не используйте EXCEPTION без необходимости.

Вместо этого, используя исключения (плохо) или IF / THEN / ELSIF (лучше), вы можете переписать это в один запрос:

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;

Если вы действительно хотите два запроса, вы можете использовать специальную переменную FOUND, чтобы проверить, дал ли предыдущий запрос какой-либо результат:

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;

Обязательные ссылки RTFM следующие :-)

Смотрите это для описания FOUNDпеременной, и это для IF/ THENблоков.

filiprem
источник
13

Вы можете проверить специальную переменную FOUND типа boolean. Из документации:

FOUND начинает false в каждом вызове функции PL / pgSQL. Он устанавливается каждым из следующих типов утверждений:

Оператор SELECT INTO устанавливает FOUND true, если назначена строка, и false, если строка не возвращается.

Оператор PERFORM устанавливает FOUND true, если он создает (и отбрасывает) одну или несколько строк, и false, если строка не создается.

Операторы UPDATE, INSERT и DELETE устанавливают FOUND true, если затронута хотя бы одна строка, и false, если строка не затрагивается.

Инструкция FETCH устанавливает FOUND true, если возвращает строку, и false, если строка не возвращается.

Оператор MOVE устанавливает FOUND true, если он успешно перемещает курсор, в противном случае - false.

Оператор FOR или FOREACH устанавливает FOUND true, если он повторяется один или несколько раз, в противном случае - false. FOUND устанавливается таким образом при выходе из цикла; внутри выполнения цикла FOUND не изменяется оператором цикла, хотя он может быть изменен выполнением других операторов в теле цикла.

Операторы RETURN QUERY и RETURN QUERY EXECUTE устанавливают FOUND true, если запрос возвращает хотя бы одну строку, и false, если строка не возвращается.

Другие операторы PL / pgSQL не изменяют состояние FOUND. В частности, обратите внимание, что EXECUTE изменяет вывод GET DIAGNOSTICS, но не меняет FOUND.

FOUND - локальная переменная в каждой функции PL / pgSQL; любые изменения в ней влияют только на текущую функцию.

AlexK
источник
но a, select intoкоторый не возвращает данных, все равно вызовет исключение, верно?
Джек говорит, попробуйте topanswers.xyz
3
как правило, нет, это вызывает исключения, только если указано условие STRICT, как SELECT * INTO STRICT моя запись ...
alexk
ах да, мой плохой - хотя разве это не означает, что обработчик исключений в примере OP никогда не сработает? :-)
Джек говорит, попробуйте topanswers.xyz
1
@JackDouglas: Нет данных, как правило, не является причиной для исключения (за исключением особых случаев, таких как модификатор STRICT выше). У ОП там было неправильное представление.
Эрвин Брандштеттер