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

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

Переменная является типом строки:

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 - если тип является хорошо известным типом строки. В противном случае мы имеем дело с анонимной записью, структура которой не определена, и вы не сможете получить доступ к элементам для начала. Но это не так с 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;

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

Другие вопросы по тегам