Как проверить все атрибуты объекта на NULL?
Переменная объектного типа может быть NULL. Выловить эту ситуацию очень просто строкой:
if v_obj is null then ...
Но что, если сама переменная инициализирована, но при этом абсолютно каждый атрибут содержит значение NULL? С массивами всё просто. Мы можем отловить этот момент:
if v_arr is null or v_arr is empty then ...
Есть ли подобный способ понять, что все атрибуты объекта содержат пустое значение?
Например:
create or replace type t_obj as object (
a number,
b number,
c number,
constructor function t_obj return self as result);
/
create or replace type body t_obj as
constructor function t_obj return self as result is
begin
return;
end;
end;
/
declare
v_obj t_obj;
begin
if v_obj is null /* or ??? */
then dbms_output.put_line('v_obj is null');
else dbms_output.put_line('v_obj is not null');
end if;
v_obj := t_obj();
if v_obj is null /* or ??? */
then dbms_output.put_line('v_obj is null');
else dbms_output.put_line('v_obj is not null');
end if;
v_obj.a := 5;
if v_obj is null /* or ??? */
then dbms_output.put_line('v_obj is null');
else dbms_output.put_line('v_obj is not null');
end if;
end;
В результате, в консоли мы увидим:
v_obj is null
v_obj is not null
v_obj is not null
А хотелось бы увидеть (после замены ??? и раскрытия комментариев)
v_obj is null
v_obj is null
v_obj is not null
Как вариант вижу: добавить MAP MEMBER FUNCTION в тело типа объекта и if v_obj = t_obj(). Но, к сожалению, отсутствует доступ к коду типа (поставляется генератором).
Ответы (1 шт):
Встроенной функции, которая проверяет все атрибуты на NULL, нет.
Если добaвить свою функцию в тип не представляется возможным, то самое простое, добавить логику проверки явно в код:
if obj is null or (obj.a is null and obj.b is null and obj.c is null) then [...]
Можно коненчно сделать более комфортно динамическим запросом, но за счёт потери производительности. Создайте для каждого типа перегруженую функцию:
create or replace function isempty (o t_obj) return boolean is
expr varchar2 (32000);
res boolean;
begin
for r in (select attr_name from user_type_attrs where type_name='T_OBJ') loop
expr := expr||'o.'||r.attr_name||' is null and ';
end loop;
execute immediate 'declare o t_obj := :o;
begin :r := ('||rtrim (expr, ' and ')||');
end;' using o, out res;
return res;
end;
/
Пример блока из вопроса вернёт ожидаемый результат:
declare
obj t_obj;
begin
if obj is null or isempty (obj)
then dbms_output.put_line ('obj is null or empty');
else dbms_output.put_line ('obj is not null');
end if;
obj := t_obj();
if obj is null or isempty (obj)
then dbms_output.put_line('obj is null or empty');
else dbms_output.put_line('obj is not null');
end if;
obj.a := 5;
if obj is null or isempty (obj)
then dbms_output.put_line('obj is null or empty');
else dbms_output.put_line('obj is not null');
end if;
end;
/
obj is null or empty
obj is null or empty
obj is not null