Тест 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;