Поиск значений NULL для разных типов Oracle

Я делаю набор из двух столбцов (col & val). Во второй select col является параметром других столбцов, а val — значением этого столбца.

введите здесь описание изображения

declare
  TYPE t_my_list is record(id varchar2(1000), col VARCHAR2(4000),val VARCHAR2(4000));
  TYPE list_3STR is table of t_my_list;    
  v_stmt    VARCHAR2(32000) := 'SELECT id, col, val FROM userA.tableA';
  v_lstmt   VARCHAR2(32000);
  v_ret     list_3STR := list_3STR();
  cDel   number;

begin
 EXECUTE IMMEDIATE v_stmt BULK COLLECT INTO v_ret;

  for i in v_ret.first..v_ret.last loop
   v_lstmt := 'SELECT count(*) FROM userB.tableB 
      WHERE NVL('||v_ret (i).col||', ''<null>'') in ('''||v_ret (i).val||''', ''<null>'') and idB = '''||v_ret (i).id||'''';

   EXECUTE IMMEDIATE v_lstmt INTO cDel;
    If cDel > 0 Then
    --some code
    cDel = 0;   
    end if;
  end loop;
end;

Но в моем операторе выбора у меня может быть нуль, поэтому я использую NVL. Кроме того, поскольку у меня может быть число, мне нужно использовать convert to_char('||v_ret (i).col||'). Кроме того, тип столбца - число, RAW, дата и т. Д.

Мой вопрос:

  • есть ли другие возможности, кроме NVL?

  • если нет, есть ли у оракула преобразователь по умолчанию? (все типы должны быть Varchar2)


person 4est    schedule 03.08.2018    source источник
comment
Пожалуйста, размещайте текст, а не изображения. И включите результат, который вы видите в настоящее время, и то, что вы хотите увидеть, если они отличаются. Предполагается, что ваша нулевая обработка говорит о том, что целевой столбец может быть нулевым или соответствовать целевому val?   -  person Alex Poole    schedule 03.08.2018


Ответы (2)


Вы можете изменить свой код, чтобы сделать:

   v_lstmt := 'SELECT count(*) FROM userB.tableB WHERE id = '''||v_ret (i).id||''''
     || ' and ('||v_ret (i).col||' is null or '||v_ret (i).col||' = :val)';

   EXECUTE IMMEDIATE v_lstmt INTO cDel using v_ret (i).val;

Это проверяет, что столбец имеет значение null или и соответствует предоставленному val, и использует переменную связывания для предоставления значения для проверки, чтобы немного сократить синтаксический анализ.

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

Вы можете использовать представление all_tab_columns, чтобы найти тип данных целевого столбца и выполнить явное преобразование val в этот тип перед привязкой. Более сложным, но, возможно, более надежным подходом было бы использование dbms_sql для внутреннего динамического SQL вместо execute immediate.

Внешний запрос, похоже, не должен быть динамическим, вы можете сделать это:

declare
  v_lstmt   VARCHAR2(32000);
  cDel   number;
begin
  for rec in (SELECT id, col, val FROM tableA) loop
    v_lstmt := 'SELECT count(*) FROM tableB WHERE id = '''||rec.id||''''
      || ' and ('||rec.col||' is null or '||rec.col||' = :val)';


    dbms_output.put_line(v_lstmt);
    EXECUTE IMMEDIATE v_lstmt INTO cDel using rec.val;
    If cDel > 0 Then
      --some code
      cDel := 0;   
    end if;
  end loop;
end;
/
person Alex Poole    schedule 03.08.2018
comment
Спасибо, все в порядке, но что, если я получу нуль для обоих сайтов? ** v_ret (i).val**, поэтому мне нужно сравнить значение null с значением null... как это сделать? - person 4est; 03.08.2018
comment
Что ты имеешь в виду? Если tablea.val равно нулю? Если да, то что должно соответствовать в tableb? В любом случае он будет совпадать в данный момент, если целевой столбец имеет значение null, из rec.col is null? - person Alex Poole; 03.08.2018
comment
tableA - для id10, colAAAA, val равно null..... теперь равняется этому нулю с tableB - id10, AAAA = null....как это сравнить? Результат для меня должен быть 1 - person 4est; 03.08.2018
comment
Запрос в ответе оценивается как and (AAAA is null or AAAA = :val), так что это будет соответствовать. (Ничто не равно или не равно нулю, поэтому вы должны использовать is null). - person Alex Poole; 03.08.2018
comment
:val — это заполнитель для переменной привязки, он не должен заключаться в двойные кавычки. - person Alex Poole; 03.08.2018

Если я правильно понял ваш вопрос, вы хотите включить ситуации, когда v_ret(i).col равен NULL.

Если это так, вы можете попробовать использовать следующий код в своем операторе select:

WHERE ('||v_ret (i).col||' is null OR '||v_ret (i).col||' = '||v_ret (i).val||')

вместо:

WHERE NVL('||v_ret (i).col||', ''<null>'') in ('''||v_ret (i).val||''', ''<null>'')

В качестве конвертера по умолчанию вы можете попробовать использовать функцию CAST: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/CAST.html.

person Goran Kutlaca    schedule 03.08.2018
comment
Может быть полезнее дать ссылку на СУБД Oracle. docs *8-) Вам все равно нужно знать, к какому типу данных нужно привести. - person Alex Poole; 03.08.2018
comment
@AlexPoole, ха-ха, это правда! :D - person Goran Kutlaca; 03.08.2018