IS NOT NULL тест для записи не возвращает TRUE, когда установлена ​​переменная

Используя процедуру plpgsql для извлечения записи, если она существует, а затем, если это так, сделайте что-нибудь с ней.

Эта переменная является типом rowtype:

my_var my_table%rowtype;

Я заполняю его оператором SQL:

select * from my_table where owner_id = 6 into my_var;

Я знаю, что определенно есть строка:

raise notice 'my_var is %', my_var;

Возврат:

NOTICE:  my_var is (383,6,10)

Но теперь я хочу проверить, что он получил запись и ОБА из них, если условия не работают:

if my_var is null then
  raise notice 'IT IS NULL';
end if;
if my_var is not null then
  raise notice 'IT IS NOT NULL';
end if;

Ни один из этих повышений не появляется в моем журнале сообщений - он просто не входит в блоки. Какой правильный способ проверить, получили ли вы строку из SELECT * INTO?

Ответ 1

Я вижу две возможные причины, почему...

Ни один из этих повышений не отображается в журнале сообщений

Не зарегистрировано

Во-первых, NOTICE обычно не записывается в журнал базы данных с настройками по умолчанию. Я цитирую руководство здесь:

log_min_messages (enum)

Управляет, какие уровни сообщений записываются в журнал сервера. Допустимые значения: DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, INFO, NOTICE, WARNING, ERROR, LOG, FATAL и PANIC. (...)
Значение по умолчанию ПРЕДУПРЕЖДЕНИЕ. Заметим, что LOG здесь имеет другой ранг, чем в client_min_messages.

Смелый акцент мой. Также обратите внимание на разное значение по умолчанию (NOTICE) для client_min_messages (предыдущий элемент в руководстве).

Неверный тест

Во-вторых, рассмотрим, как оценивается выражение строки. Тест row_variable IS NULL возвращает TRUE, если (и только если) каждый отдельный элемент NULL. В следующем примере:

SELECT (1, NULL) IS NULL AS a     -- FALSE
      ,(1, NULL) IS NOT NULL AS b -- also FALSE

Оба выражения возвращают FALSE. Другими словами, переменная строки (или записи) (1, NULL) не является ни NULL, ни ее NOT NULL. Поэтому оба ваших теста не работают.

- > SQLfiddle с более подробной информацией.

Дополнительные сведения, объяснения, ссылки и возможное приложение для этого поведения в ограничении CHECK в этом связанном ответе:
NOT NULL ограничение по набору столбцов

Вы даже можете назначить переменную записи с NULL (rec := NULL), что приводит к тому, что каждый элемент имеет значение NULL - если тип является известным типом строки. В противном случае мы имеем дело с анонимной записью, а структура undefined, и вы не можете получить доступ к элементам для начала. Но это не тот случай с rowtype, как в вашем примере (который всегда хорошо известен).

Решение: FOUND

Какой правильный способ проверить, получили ли вы строку из SELECT * INTO?

Вы должны учитывать, что строка может быть NULL, даже если она была назначена. Запрос мог бы очень хорошо вернуть кучу значений NULL (если определение таблицы в вашем запросе допускает значения NULL). Такой тест будет ненадежным по дизайну.

Существует простой и безопасный подход. Используйте GET DIAGNOSTICS ... или (если применимо) специальную переменную FOUND:

SELECT * FROM my_table WHERE owner_id = 6 INTO my_var;

IF NOT FOUND THEN
   RAISE NOTICE 'Query did not return a row!';
END IF;

Подробности в руководстве.