Ошибка ora 01403 данные не найдены

I am getting ORA-01403: no data found exception for the following query. What are the possibilities of this error?

SELECT trim(name)
  INTO fullname
  FROM ( SELECT n.name
         FROM directory dir, store n
        WHERE dir.name = n.name
          AND dir.status NOT IN ('F', 'L', 'M')
        ORDER BY n.imp, dir.date)
  WHERE rownum <= 1;

How can I handle this error?

diziaq's user avatar

diziaq

7,00116 gold badges56 silver badges100 bronze badges

asked Jan 17, 2014 at 12:47

Nidheesh's user avatar

4

Although you have put a WHERE condition, a better way would be to handle case of record not found or ‘No Data Found’ error. I would write above code with wrapping the SELECT statement with it’s own BEGIN/EXCEPTION/END block.

Code could be something like this:

BEGIN
    SELECT trim(name) 
    INTO fullName
    FROM (
        SELECT n.name
        FROM directory dir, store n
        WHERE dir.name = n.name
        AND dir.STATUS NOT IN ('F','L','M')           
        ORDER BY n.imp, dir.date
    )
    WHERE rownum <= 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        fullName := NULL;
END;

Robin A. Meade's user avatar

answered Jan 17, 2014 at 12:59

Sandeep's user avatar

SandeepSandeep

5685 silver badges7 bronze badges

4

If the standard exception handling described by Sandeep seems to much overhead (like in my case) and you’re fine with a NULL or some individual <not found> value), you might just transform it like this:

select  col  into  v_foo  from  bar  where 1=0  -- would provoke ORA-01403

=> no ORA-01403 raised:

-- if NULL would be fine:

select  (select  col  from  bar  where 1=0)  into  v_foo  from dual

-- if individual "NOT_FOUND" value should be set to avoid standard exception handling:
--    (it depends on your col type, so it could e.g. be 'NOT_FOUND' or -1 
--     or to_date( 'yyyy-mm-dd', '2100-01-01') )

select  nvl(  (select  col  from  bar  where 1=0),  'NOT_FOUND'  )  into  v_foo  from dual

answered Feb 23, 2017 at 12:12

Andreas Covidiot's user avatar

Andreas CovidiotAndreas Covidiot

4,3465 gold badges51 silver badges97 bronze badges

1

Probably because your Query

SELECT n.name
        FROM directory dir,
          store n
        WHERE dir.name            = n.name
        AND dir.STATUS NOT                IN ('F','L','M')           
        ORDER BY n.imp,
          dir.date

is not returning any rows

answered Jan 17, 2014 at 12:53

A Nice Guy's user avatar

A Nice GuyA Nice Guy

2,6764 gold badges30 silver badges54 bronze badges

If dir.status has any nulls in your table, then not in is probably not doing what you think it is. You may get zero rows even though you think you should get one or more rows. You can switch to and not (dir.status in ('F,'L','M')) instead of dir.status not in ('F','L','M').

See this for reference.

answered Jan 17, 2014 at 15:40

GriffeyDog's user avatar

GriffeyDogGriffeyDog

8,2663 gold badges23 silver badges34 bronze badges

forget the exceptions… just use the dual table:

select (
SELECT trim(name)
  FROM ( SELECT n.name
         FROM directory dir, store n
        WHERE dir.name = n.name
          AND dir.status NOT IN ('F', 'L', 'M')
        ORDER BY n.imp, dir.date)
  WHERE rownum <= 1
) into fullname
from dual;

B-) that way if your query don’t return anything the variable will be populated with null.

answered Sep 26, 2022 at 16:07

Rafael Gil's user avatar

I’ve a SQL query where if output is NULL it should not send warning .

l_sup_id    NUMBER;

begin

SELECT  per_all_assignments_f.supervisor_id
    INTO  l_sup_id
FROM    per_all_assignments_f
WHERE   person_id = p_person_id
    AND     trunc (sysdate) BETWEEN effective_start_date
                    AND     effective_end_date
    AND     primary_flag = 'Y';

elsif (p_person_type = 'APPRAISER' AND  l_sup_id IS NOT NULL) then
        hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
        hr_utility.raise_error;
end if;

Whenever l_sup_id is null according to logic

  hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');

should not be executed

But whenever l_sup_id is null I am getting

ORA-01403: no data found

error in logs

If l_sup_id is not null application working is fine

jarlh's user avatar

jarlh

42.8k8 gold badges45 silver badges64 bronze badges

asked Apr 28, 2015 at 6:52

Pravin Kottawar's user avatar

5

From documentation,

NO_DATA_FOUND

A SELECT INTO statement returns no rows, or your program references a
deleted element in a nested table or an uninitialized element in an
index-by table.

In your PL/SQL code, the SELECT .. INTO statement returns no rows, thus it raises NO_DATA_FOUND error. It never goes to the next line, i.e. your IF-ELSE construct.

If you want to continue the operation, then you need to handle the EXCEPTION gracefully.

For example,

SQL> SET serveroutput ON
SQL>
SQL> DECLARE
  2    o_ename emp.ename%TYPE;
  3    i_empno emp.empno%TYPE;
  4  BEGIN
  5    SELECT ename INTO o_ename FROM emp WHERE empno = i_empno;
  6    -- Handle no_data_found
  7  EXCEPTION
  8  WHEN no_data_found THEN
  9    -- do something
 10    dbms_output.put_line('No records found for employee no '|| i_empno);
 11  END;
 12  /
No records found for employee no

PL/SQL procedure successfully completed.

SQL>

answered Apr 28, 2015 at 7:11

Lalit Kumar B's user avatar

Lalit Kumar BLalit Kumar B

47.7k13 gold badges99 silver badges125 bronze badges

As the error suggests its pointing to NO DATA for the condition, to handle that you need to use «Exception Handling», Please see the code for the changes,

declare
l_sup_id    NUMBER;

begin

SELECT  per_all_assignments_f.supervisor_id
    INTO  l_sup_id
FROM    per_all_assignments_f
WHERE   person_id = p_person_id
    AND     trunc (sysdate) BETWEEN effective_start_date
                    AND     effective_end_date
    AND     primary_flag = 'Y';

elsif (p_person_type = 'APPRAISER' AND  l_sup_id IS NOT NULL) then
        hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
        hr_utility.raise_error;
end if;
--changes start
exception
when no_Data_found then
dbms_output.put_line('No data exists for lsup '|| l_sup_id)

--changes end
end;

Edit:

   SQL> SELECT * FROM TESTEMP WHERE EMPNO=6677;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      6677 JUPITER    CLERK           7902 17-DEC-80        800                    20

SQL>
SQL>  declare
  2   l_count number;
  3   begin
  4   select comm into l_count from testemp where empno=6677 ;
  5   DBMS_OUTPUT.PUT_LINE('lcount is'||l_count);
  6   if (l_count IS NULL) then
  7   dbms_output.put_line('no data');
  8   else
  9   dbms_output.put_line('data');
 10   end if;
 11   end;
 12  /

lcount is
no data

PL/SQL procedure successfully completed.

Your condition wont go into the if at all if you compare to NULL or how ever you want to use it according to your specification

answered Apr 28, 2015 at 6:55

anudeepks's user avatar

anudeepksanudeepks

1,0901 gold badge12 silver badges23 bronze badges

2

Thank you for all the responses.
Instead of plain sql I created the following cursor

cursor csr_supervisor_id 
                    is
        SELECT  supervisor_id
        FROM    per_all_assignments_f
        WHERE   person_id = p_person_id
            AND     trunc (sysdate) BETWEEN effective_start_date
                    AND     effective_end_date
            AND     primary_flag = 'Y';

and fetched it in l_sup_id

open csr_supervisor_id;
fetch csr_supervisor_id into l_sup_id;

Now no data received error is not coming.

answered Apr 28, 2015 at 7:55

Pravin Kottawar's user avatar

Уровень сложности
Средний

Время на прочтение
17 мин

Количество просмотров 5.4K

Предисловие

Убедительная просьба, рассматривать данный текст только как продолжение к статье о «Событийной модели логирования». Эта статья будет полезна тем, у кого уже реализовано логирование событий в БД и кто хотел бы осуществлять сбор статистики и начать проводить аналитику этих событий. Только представьте, что ваша БД сможет информировать вас о критичных сбоях системы, накапливать информацию о событиях в БД (кол-во повторений, период повторений и т.д.). И всё это без использования стороннего ПО силами одного PL/SQL.

Введение

В этом цикле статей будет показано как реализованный функционал «логирования» позволяет фиксировать факт возникновения не только ошибок (сообщение с типом «Error»), но и сообщений с предупреждением (тип «Warning»), информативных сообщений (с типом «Info») и т.д., поэтому, в рамках данных статей введём термин — «Модель логирования событий» (далее по тексту — «модель») или коротко «Логирование событий», где под «событием» подразумевается некоторое ожидаемое действие, возникшее в ходе штатной/внештатной работы алгоритма.

Модель логирования позволяет реализовать:

  1. Единый подход в обработке и хранении событий (статья)

  2. Собственную нумерацию и идентификацию событий происходящих в БД

  3. Единый мониторинг событий (статья в разработке)

  4. Анализ событий происходящих в БД (статья в разработке)

Описанные выше характеристики указаны в порядке нумерации и каждый следующий пункт (шаг) есть улучшение и усложнение существующей модели. Описание этой модели будет сложно выполнить в рамках одной статьи, поэтому опишем их последовательно. В этой (второй) статье создадим собственную нумерацию кодов для событий, а также создадим функционал идентификации событий происходящих в БД.

Для чего это нужно?

Для начала давайте рассмотрим пример. Вы реализовали логирование ошибок в вашей БД. С течением времени в ваш лог «прилетают» самые разнообразные ошибки. Предположим, имеются две ошибки вида «no_data_found» возникшие в двух разных процедурах при двух разных запросах (select). Первая ошибка возникла при попытке найти «email» клиента, что в принципе не является критичной ошибкой. Вторая ошибка возникла при попытке найти номер лицевого счета клиента, что вполне может являться критичной ошибкой. При этом если мы посмотрим в таблицу лога (из статьи), то увидим, что указанные ошибки будут храниться с одинаковым кодом 1403 (ORA-01403) в столбце msgcode. Более того, текст указанных ошибок будет практически аналогичным (текст полученный с помощью функции SQLERRM) за исключением имен объектов, на которых произошла ошибка. Для того чтобы понять является ли критичной конкретная ошибка, разработчику необходимо вникать в текст ошибки, смотреть в каком объекте возникла ошибка и на основе этой информации сделать вывод о срочности исправления. При этом, если мы сможем задать более четкое описание ошибки отличное от текста Oracle (SQLERRM), то это позволит упростить понимание причин возникновения и способов решения ошибки.

Ошибка

Как сейчас

Как должно быть (в идеале)

Не найдена запись в таблице содержащей адреса электронной почты клиентов

ORA-01403: данные не найдены

USR0001: Не найден адрес электронной почты клиента id = *** (идентификатор клиента)

Не найдена запись в таблице содержащей лицевые счета клиентов

ORA-01403: данные не найдены

USR0002: Не найден лицевой счет клиента id = *** (идентификатор клиента)

 Из этого примера видно, что одна и та же ошибка «no_data_found» (ORA-01403: данные не найдены) может иметь совершенно разное значение с точки зрения бизнес логики, а значит нам необходимо разработать механизм, который позволит идентифицировать каждое событие происходящее в БД как отдельное событие с нашим внутренним уникальным кодом и текстом события (отличную от Oracle). Таким образом мы решаем две проблемы:

1) В месте возникновения ошибки мы устанавливаем уникальный код ошибки. В будущем это позволяет достаточно быстро найти место возникновения ошибки. Также, наличие уникальных кодов позволяет нам произвести точечный подсчет повторений и на основании этой информации принять решение об устранении данной ошибки.

2) Дополнительный «читаемый» текст позволяет сильно упростить понимание ошибки. В таблице выше показано, как одна и та же ошибка может запутать или разъяснить пользователю сведения об ошибке.

Надеюсь мне удалось объяснить зачем необходимо кодировать события в таблице логов. Далее по тексту, будут введены термины «Архитектурный лог» и «Пользовательский лог». На примере процедуры поиска активного номера телефона клиента будет показано как и зачем создано разделение на архитектурный и пользовательский лог.

Архитектурное логирование событий

Давайте рассмотрим пример, имеется процедура поиска активного номера телефона принадлежащего конкретному клиенту (для примера его id = 43). Предположим, что при постановке задачи для разработчика не было описания каких-либо особых условий т.е. по условиям задачи предполагалось, что для конкретного пользователя (id = 43, идентификатор передается в качестве параметра) в таблице client_telnumbers всегда будет хотя бы одна запись с номером телефона клиента и признаком «активный» (значение поля enddate равно дате 31.12.5999 23:59:59, что означает что номер используется клиентом. В случае, любой другой даты в указанном поле означает, что номер перестал быть активным и более не используется), поэтому наша процедура будет выглядеть примерно так:

Исходный код демонстрационной процедуры

procedure p_get_telnumber(p_userid    in number,
                          p_telnumber out number,
                          p_errcode   out number,
                          p_errtext   out varchar2)
  is
    v_objname   varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
    v_telnumber client_telnumbers.telnumber%type;
  begin
    select telnumber
      into v_telnumber
      from client_telnumbers
     where id = p_userid
       and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');

    p_telnumber := v_telnumber;
    p_errcode   := 1;
  exception
    when others then
      pkg_msglog.p_log_err(p_objname    => v_objname,
                           p_msgcode    => SQLCODE,
                           p_msgtext    => SQLERRM,
                           p_paramvalue => 'p_userid = '||p_userid,
                           p_backtrace  => dbms_utility.format_error_backtrace);
      raise;
  end p_get_telnumber;

Важно! Представленный код является примерным (примитивным) и служит только для демонстрации логирования в рамках данной статьи. В своих статьях я не выкладываю текст кода из реально действующих БД. Надеюсь, вы понимаете, что в реальности указанная процедура написана гораздо сложнее.

*Исходный код других используемых объектов смотрите в Git

  Если мы будем использовать логирование ошибок как показано в предыдущей статье, то с течением времени обнаружим, что идентифицировать ошибки из данной процедуры будет сложно. Поэтому для всех ошибок попадающих в обработку исключения «WHEN OTHERS» реализована процедура pkg_msglog.p_log_archerr, которая при первом возникновении ошибки автоматически присваивает ей уникальный код и сохраняет ошибку в таблице лога. В дальнейшем, при повторении данной ошибки процедура найдет ранее созданный код и использует его при логировании в таблице лога.

В итоге, после добавления блока «архитектурного» логирования (строки с 18 по 24), наша процедура будет выглядеть следующим образом:

Исходный код демонстрационной процедуры

procedure p_get_telnumber(p_userid    in number,
                          p_telnumber out number,
                          p_errcode   out number,
                          p_errtext   out varchar2)

  is
    v_objname   varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
    v_telnumber client_telnumbers.telnumber%type;
  begin
    select telnumber
      into v_telnumber
      from client_telnumbers
     where id = p_userid
       and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');

    p_telnumber := v_telnumber;
    p_errcode   := 1;
  exception
    -- Архитектурное логирование
    when others then
      pkg_msglog.p_log_archerr(p_objname    => v_objname,
                               p_msgcode    => SQLCODE,
                               p_msgtext    => SQLERRM,
                               p_paramvalue => 'p_userid = '||to_char(p_userid),
                               p_backtrace  => dbms_utility.format_error_backtrace);
      raise;
  end p_get_telnumber; 

*Исходный код других используемых объектов смотрите в Git

  На этапе написания текста процедуры разработчик не всегда может предугадать возникновение той или иной ошибки (если честно, не всегда есть на это время), поэтому на начальном этапе ему достаточно «отлавливать» абсолютно все ошибки возникающие в данной процедуре с помощью оператора «WHEN OTHERS». Таким образом мы можем ввести новый термин (в рамках данного цикла статей), «Архитектурные логирование» — это логирование всех ошибок, возникновение которых не предполагается при штатной работе алгоритма. Для функционала «Архитектурных ошибок» были созданы объекты: отдельный справочник ошибок messagecodes_arch и процедура pkg_msglog.p_log_archerr создания записи в таблице лога для указанного типа ошибок.

Исходный код таблицы

create table messagecodes_arch(objectname  varchar2(120) not null,
                               sqlerrcode  number        not null,
                               msgcode     varchar2(10)  not null,
                               insertdate  date          default sysdate,
                               constraint pk_msgcode_arch_id primary key (objectname,sqlerrcode));

Ограничение в таблице на комбинацию (Имя объекта, код ошибки SQLCODE). При первом появлении ошибки создается запись в таблице и генерируется код ошибки «SYS0000» + счетчик ошибок. При повторном появлении указанной ошибки будет взят уже сгенерированный ранее код ошибки.

рис. Пример содержимого таблицы messagecodes_arch

рис. Пример содержимого таблицы messagecodes_arch

*Исходный код других используемых объектов смотрите в Git

Обратите внимание, что при использовании описанной модели «архитектурного» логирования у вас появляется функционал позволяющий максимально быстро реагировать на первое появление ошибки (в конкретной функции/процедуре). Для этого необходимо реализовать отдельный мониторинг архитектурных ошибок, который постараюсь продемонстрировать в следующей (третьей) статье. Использование процедуры pkg_msglog.p_log_archerr не требует каких-либо действий кроме описания входных параметров.

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

Шаблон процедуры/функции с архитектурным логированием

  -- Шаблон процедуры/функции для построения Событийной модели логирования
  -- Обратите внимание, что каждый блок "begin ... end" содержит исключение вида "when others",
  -- который осуществляет логирование Архитектурных ошибок.
  -- Все остальные исключения вида "no_data_found", "too_many_rows" и др. 
  -- будут осуществлять логирование Пользовательских ошибок
  procedure p_procedure_name(p_param1  in number,
                             p_param2  in varchar2,
                             p_param3  in date,
                             /* others param */
                             p_errcode out number,
                             p_errtext out varchar2)
  is
    v_objname varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
    /* variable */
    v_msgcode   messagelog.msgcode%type;
    v_msgtext   messagelog.msgtext%type;
  begin
  
    /* code */

    begin
    
      /* code */
  
    exception
      -- Пользовательское логирование
      when no_data_found then
        v_msgcode := 'USR0000'; -- внутренний код
        v_msgtext := pkg_msglog.f_get_errcode(v_msgcode);
        pkg_msglog.p_log_wrn(p_objname    => v_objname,
                             p_msgcode    => v_msgcode,
                             p_msgtext    => v_msgtext,
                             p_paramvalue => 'p_param1 = '||to_char(p_param1)
                                                ||', p_param2 = '||p_param2
                                                ||', p_param3 = '||to_char(p_param3,'dd.mm.yyyy hh24:mi:ss'));
	      p_errcode := -1;
        p_errtext := v_msgtext;                                           
    end;   
    
    /* code */
    
    /* result */
    p_errcode := 1;
  exception
    -- Пользовательское логирование
    when no_data_found or too_many_rows then
      v_msgcode := 'USR0000';  -- внутренний код
      v_msgtext := pkg_msglog.f_get_errcode(v_msgcode);
      pkg_msglog.p_log_wrn(p_objname    => v_objname,
                           p_msgcode    => v_msgcode,
                           p_msgtext    => v_msgtext,
                           p_paramvalue => 'p_param1 = '||to_char(p_param1)
                                                ||', p_param2 = '||p_param2
                                                ||', p_param3 = '||to_char(p_param3,'dd.mm.yyyy hh24:mi:ss'));
    	p_errcode := -1;
      p_errtext := v_msgtext;
    -- Архитектурное логирование
    when others then
      pkg_msglog.p_log_archerr(p_objname    => v_objname,
                               p_msgcode    => SQLCODE,
                               p_msgtext    => SQLERRM,
                               p_paramvalue => 'p_param1 = '||to_char(p_param1)
                                                ||', p_param2 = '||p_param2
                                                ||', p_param3 = '||to_char(p_param3,'dd.mm.yyyy hh24:mi:ss'),
                               p_backtrace  => dbms_utility.format_error_backtrace);
      raise;
 end p_procedure_name;

Рекомендую использовать данный шаблон для построения «Событийной модели логирования».

*Исходный код других используемых объектов смотрите в Git

В рамках событийной модели логирования, предполагается, что все архитектурные ошибки будут исправляться отдельной задачей т.е. основная цель это устранить повторное появление ошибок с кодом «SYS****» в таблице лога. В указанной задаче вам необходимо либо устранить причины возникновения данной ошибки, либо добавить отдельную обработку ошибки отличную от «when others», которую в дальнейшем будем назвать «пользовательское» логирование (в рамках данного цикла статей).

Пользовательское логирование событий

Предположим, что однажды в нашей процедуре get_telnumber произошла «архитектурная ошибка». В частности, для конкретного пользователя в таблице client_telnumbers хранится два номера телефона с признаком «активный». В таком случае, процедура «упадёт» с ошибкой «ORA-01422: too_many_rows». При этом, наш функционал архитектурного логирования сгенерировал новый код ошибки «SYS0061» и создал запись в таблице лога.

рис. Код архитектурной ошибки SYS0061

рис. Код архитектурной ошибки SYS0061

Самое важно в такой ситуации это не откладывать «на потом» исправление архитектурных ошибок. В идеале, необходимо создать отдельную задачу (баг) и в рамках неё устранить ошибку.

Предположим ,что была создана отдельная задача для устранения ошибки и назначена разработчику. В рамках этой задачи, разработчик совместно с технологом, аналитиком и др. коллегами пришел к выводу, что указанная ошибка носит систематический характер, является некорректной работой системы и требует исправления. В качестве мер исправления было решено добавить обработку события «too_many_rows» с последующим логированием события в таблице лога и выводом текста ошибки для пользователя.

Для этого в процедуре get_telnumber добавлено исключение (exception) «too_many_rows» пользовательского логирования. Также, был создан справочник пользовательских ошибок отличный от архитектурного справочника, тем что в него все записи добавляются разработчиком «вручную». Наверное это самое слабое место во всей архитектуре логирования. Предполагается, что разработчик должен описать исключение (exception) и создать для него уникальный код ошибки. Также, желательно к указанной ошибке сформулировать читаемый текст ошибки (для своих коллег, пользователя, техподдержки и т.д.), что бывает иногда очень сложным (из личного опыта).

Таблица пользовательских ошибок и процедура их «регистрации» будет выглядеть следующим образом:

Исходный код таблицы пользовательских ошибок и процедуры регистрации

create table messagecodes(msgcode     varchar2(10)  not null,
                          rustext     varchar2(500) not null,
                          msgpriority number(1)     default 1,
                          insertdate  date          default sysdate,
                          lastupdate  date          default null,
                          constraint pk_messagecodes_id primary key (msgcode));

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

-- Пример регистации пользовательских ошибок
begin
  pkg_msglog.p_insert_msgcode('USR0001','Не найден адрес электронной почты клиента id = $1!',1);
  pkg_msglog.p_insert_msgcode('USR0002','Не найден лицевой счет клиента id = $1!',5);
  pkg_msglog.p_insert_msgcode('USR0003','Для клиента id = $1 найдено два и более активных номеров телефона!',1);
  pkg_msglog.p_insert_msgcode('USR0004','Номер мобильного телефона не соответствует маске (clientid = $2)',1);
  commit;
end;

Обратите внимание, что текст ошибок имеет параметризацию т.е. для ошибки в тексте имеются специальные символы $1, $2, $3 и т.д. Например, рассмотрим ошибку «USR0003» с текстом «Для клиента id = $1 найдено два и более активных номеров телефона!» при вызове функции f_get_errcode на вход подаётся код ошибки и параметры ошибки. Далее, функция по коду ошибки найдет строку, в тексте ошибки заменит подстроку «$1» на значение параметра to_char(p_userid) т.е. подставит значение to_char(p_userid).

v_msgcode := 'USR0003'; -- внутренний код
v_msgtext := pkg_msglog.f_get_errcode(p_msgcode  => v_msgcode,
                                      p_msgparam => to_char(p_userid));

В случае если в тексте ошибки будут два и более спецсимвола $1, $2, $3 и т.д., то параметры передаются с использованием символа-разделителя «;».

Итого, содержимое справочника пользовательских ошибок будет выглядеть следующим образом:

рис. Пример содержимого справочника пользовательских ошибок

рис. Пример содержимого справочника пользовательских ошибок

*Исходный код других используемых объектов смотрите в Git

После того, как мы «зарегистрировали» пользовательскую ошибку «USR0003» и добавив отдельную обработку пользовательского логирования (строки с 19 по 28), наша процедура get_telnumber будет выглядеть следующим образом:

Исходный код демонстрационной процедуры

  procedure p_get_telnumber(p_userid    in number,
                            p_telnumber out number,
                            p_errcode   out number,
                            p_errtext   out varchar2)
  is
    v_objname   varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
    v_telnumber client_telnumbers.telnumber%type;
    v_msgcode   messagelog.msgcode%type;
    v_msgtext   messagelog.msgtext%type;
  begin
    select telnumber
      into v_telnumber
      from client_telnumbers
     where id = p_userid
       and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');

    p_telnumber := v_telnumber;
    p_errcode   := 1;
  exception
    -- Пользовательское логирование
    when too_many_rows then
      v_msgcode := 'USR0003'; -- внутренний код
      v_msgtext := pkg_msglog.f_get_errcode(v_msgcode,to_char(p_userid));
      pkg_msglog.p_log_wrn(p_objname    => v_objname,
                           p_msgcode    => v_msgcode,
                           p_msgtext    => v_msgtext,
                           p_paramvalue => 'p_userid = '||to_char(p_userid));
      p_errcode := -1;
      p_errtext := v_msgtext;
    -- Архитектурное логирование
    when others then
      pkg_msglog.p_log_archerr(p_objname    => v_objname,
                               p_msgcode    => SQLCODE,
                               p_msgtext    => SQLERRM,
                               p_paramvalue => 'p_userid = '||to_char(p_userid),
                               p_backtrace  => dbms_utility.format_error_backtrace);
      raise;
  end p_get_telnumber;

*Исходный код других используемых объектов смотрите в Git

При повторном возникновении ошибки «too_many_rows» обработка события пройдет по нашему сценарию «пользовательского» логирования. Таким образом мы можем ввести второй термин (в рамках данного цикла статей), «Пользовательские логирование» — это логирование всех ошибок, возникновение которых предполагается и ожидается при нештатной работе алгоритма. В итоге, пользователь получит читаемый текст ошибки с кодом «USR0003», также, мы же всегда сможем подсчитать количество ошибок с указанным кодом. В случае большого количества ошибок у нас на руках будет «живая» статистика частоты возникновения ошибки и их количества, что позволит нам выйти на руководство с предложением по доработке/оптимизации процесса.

Давайте рассмотрим еще один пример (кейс из реального случая), в момент когда процедура get_telnumber по id клиента находит один «активный» номер телефона иногда возникает ситуация, что номер телефона не принадлежит мобильному оператору. Ситуации бывают разные иногда указанный номер мог быть номером городской телефонной сети, иногда номером международного оператора, а иногда вообще набор из нескольких цифр и т.д. Основным требованием от бизнес-заказчика было использование номера телефона российских операторов мобильной связи. Поэтому было решено добавить проверку соответствия найденного номера некому «корректному» шаблону (строки с 18 по 29). В случае обнаружения некорректного номера, логировать данное событие отдельным кодом «USR0004» и типом «WRN». Добавим функцию проверки корректности номера телефона, если номер соответствует шаблону (требованиям), то вернем номер телефона, иначе пустое значение.

Исходный код демонстрационной процедуры

  procedure p_get_telnumber(p_userid    in number,
                            p_telnumber out number,
                            p_errcode   out number,
                            p_errtext   out varchar2)
  is
    v_objname      varchar2(60) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
    v_telnumber    client_telnumbers.telnumber%type;
    v_newtelnumber client_telnumbers.telnumber%type;
    v_msgcode      messagelog.msgcode%type;
    v_msgtext      messagelog.msgtext%type;
  begin
    select telnumber
      into v_telnumber
      from client_telnumbers
     where id = p_userid
       and enddate = to_date('31.12.5999 23:59:59', 'dd.mm.yyyy hh24:mi:ss');
    
    v_newtelnumber := f_check_telnumber(v_telnumber);
    if v_newtelnumber is not null then
      p_telnumber := v_telnumber;
      p_errcode   := 1;
    else
      -- Пользовательское логирование
      v_msgcode := 'USR0004'; -- внутренний код
      v_msgtext := pkg_msglog.f_get_errcode(v_msgcode,to_char(p_userid));
      pkg_msglog.p_log_wrn(p_objname    => v_objname,
                           p_msgcode    => v_msgcode,
                           p_msgtext    => v_msgtext,
                           p_paramvalue => 'p_userid = '||to_char(p_userid));
      p_errcode := -1;
      p_errtext := v_msgtext;
    end if;
  exception
    -- Пользовательское логирование
    when too_many_rows then
      v_msgcode := 'USR0003'; -- внутренний код
      v_msgtext := pkg_msglog.f_get_errcode(v_msgcode,to_char(p_userid));
      pkg_msglog.p_log_wrn(p_objname    => v_objname,
                           p_msgcode    => v_msgcode,
                           p_msgtext    => v_msgtext,
                           p_paramvalue => 'p_userid = '||to_char(p_userid));
      p_errcode := -1;
      p_errtext := v_msgtext;
    -- Архитектурное логирование
    when others then
      pkg_msglog.p_log_archerr(p_objname    => v_objname,
                               p_msgcode    => SQLCODE,
                               p_msgtext    => SQLERRM,
                               p_paramvalue => 'p_userid = '||to_char(p_userid),
                               p_backtrace  => dbms_utility.format_error_backtrace);
      raise;
 end p_get_telnumber;

*Исходный код других используемых объектов смотрите в Git

После сбора статистических данных по конкретной ошибке с кодом «USR0004», руководству стало понятно, что ошибка актуальна и количество ошибок с течением времени не только не уменьшается, а наоборот растет с линейной прогрессией. В дальнейшем, были выявлены источники «кривых» данных и были установлены внутренние требования по первичной обработке номера телефона клиентов. В итоге, со временем количество ошибок уменьшилось до нуля. И этого нельзя было добиться до тех пор, пока у всех участвующих лиц не возникло понимание о масштабе проблемы.

Выполняя самый банальный запрос в таблицу лога с группировкой по типу сообщения (msgtype), имени объекта (objname) и вашему внутреннему коду ошибки (msgcode) за отдельный квартал, вы сможете увидеть реальную картинку частоты возникновения той или иной ошибки. Как только в вашей БД появляется ошибка с большим количеством повторений вы всегда сможете выявить это событие и принять решение об устранении.

Исходный код запроса

select msgtype, 
       objname, 
       msgcode, 
       count(*) 
  from messagelog
where insertdate between to_date('01.01.2021', 'dd.mm.yyyy') and to_date('31.03.2021', 'dd.mm.yyyy')
group by msgtype, objname, msgcode
order by 4 desc

Результат запроса:

рис. Пример результата запроса с группировкой

рис. Пример результата запроса с группировкой

*Исходный код других используемых объектов смотрите в Git

Заключение

В заключении наверное скажу банальную вещь, о том что ваша БД является сложным механизмом ежесекундно выполняющая рутинные операции. Прямо сейчас в БД могут происходить различные ошибки. Критичные, которые вы исправляете практически сразу или некритичные, о которых вы можете вообще не знать. И если у вас нет информации о подобных ошибках, то возникает вопрос: «Нужно ли их вообще исправлять? Или можно подождать до тех пор, пока проблема не всплывёт?». Вопрос наверное «риторический».

Я же данной статьёй хотел показать один из способов ведения логирования с кодированием отдельных событий. Данный метод требует некоторых «обязательств» от разработчика и в нынешнее время этого тяжело добиться. В следующей статье постараюсь показать один из способов мониторинга ошибок основанный напрямую по кодам ошибок созданных в текущей статье.

Спасибо за внимание.

dykee

0 / 0 / 0

Регистрация: 28.04.2015

Сообщений: 53

1

16.09.2015, 21:26. Показов 18913. Ответов 4

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Нужно при выборе людей с 20 отдела(таких людей 4) сделать надбавку к зарплате. Я пошарился по форума и понял что инто только для одного значения делает вывод. Как сделать так что б для 4х?? Покажите реализацию пожалуйста

SQL
1
2
3
4
5
6
7
8
9
10
CREATE OR REPLACE PROCEDURE lab3 IS
sum_sal NUMBER;
nadbavka NUMBER;
BEGIN
  SELECT SUM(t.sal) INTO sum_sal FROM emp t;
  SELECT sal+(0.2*7) INTO nadbavka FROM emp WHERE deptno=20;
  dbms_output.put_line(' Всего бабок зарплата в отделах:'||sum_sal);
  dbms_output.put_line(' Надбавка:'||nadbavka);
 
  END lab3;



0



Lorsik

105 / 49 / 26

Регистрация: 01.09.2014

Сообщений: 140

16.09.2015, 23:14

2

ORA- 01403 Данные не найдены
Говорит о том что какой-то из твоих селектов не возвращает ни одной строки. В таких случаях обычно делают

SQL
1
2
3
4
5
6
7
8
DECLARE
....
BEGIN
....
exception 
  WHEN no_data_found THEN чтото_сделать;
  WHEN too_many_rows чтото_сделать;
END;

Если будет несколько строк то ошибка будет to_many_rows.



0



263 / 109 / 26

Регистрация: 16.03.2013

Сообщений: 272

17.09.2015, 03:44

3

dykee, т.е. тебе нужно для каждого сотрудника из 20 отдела вывести его исходную з/п и з/п с прибавкой? Если да, нужна будет группировка, так как тот селект тебе возвращает общую з/п на отдел.
Я бы это делал через курсор. И объединил бы два твоих селекта в 1, ведь данные то из одной и той же таблицы и там и там берутся.



0



StalkerIQ

22 / 20 / 3

Регистрация: 21.05.2013

Сообщений: 408

22.09.2015, 07:13

4

А разве обычный update тут не поможет?

SQL
1
UPDATE emp SET sal=sal+(0.2*7) WHERE deptno=20

????



0



263 / 109 / 26

Регистрация: 16.03.2013

Сообщений: 272

22.09.2015, 07:54

5

Цитата
Сообщение от StalkerIQ
Посмотреть сообщение

А разве обычный update тут не поможет?

Ну если TC не нужны изначальные данные без надбавки, то да. Но я бы так не делал, вдруг завтра формула надбавки изменится, пересчитать её тогда не получится. Если апдейтом — то нужно дополнительную заводить.
А так как TC использует dbms_output.put_line, чтоб меньше переписывать я и предложил курсор.



0



Ошибка ORA-01403 — это сообщение об ошибке, которое может возникать при выполнении SQL-запросов в базах данных Oracle. Она указывает на то, что в результате выполнения запроса не было найдено никаких данных, соответствующих указанным критериям поиска.

Существует несколько причин, по которым может возникнуть ошибка ORA-01403. Одной из основных причин является неправильно указанный критерий поиска или неверно составленное условие WHERE в запросе. Если условие WHERE неверно, то база данных не будет находить данные, которые следует вернуть в результате выполнения запроса.

Еще одной причиной может быть отсутствие данных, которые должны быть найдены по указанным критериям. Если в базе данных отсутствуют данные, удовлетворяющие заданным условиям, то ошибка ORA-01403 будет сгенерирована.

Для решения проблемы с ошибкой ORA-01403 необходимо внимательно проверить правильность указанного условия WHERE. Убедитесь, что оно соответствует требованиям вашего запроса. Если возникает ошибка из-за отсутствия данных, попробуйте проверить базу данных на наличие соответствующих записей. В случае необходимости, вы можете исправить запрос или добавить нужные данные в базу данных.

Содержание

  1. Проблемы с запросом
  2. Отсутствие данных в таблице
  3. Проблемы с правами доступа
  4. Неправильное использование функций
  5. Исправление ошибки ORA-01403

Проблемы с запросом

При возникновении ошибки ORA-01403: не найдены данные может быть несколько причин, связанных с самим запросом и обращением к данным:

  • Некорректные условия поиска — в запросе могут быть указаны неправильные или неполные условия, в результате чего требуемые данные не найдены. Проверьте правильность указанных условий поиска.
  • Отсутствие данных в таблице — в таблице, к которой обращается запрос, может не быть данных, удовлетворяющих указанным условиям. Проверьте наличие данных в таблице и убедитесь, что они соответствуют условиям запроса.
  • Несовпадение типов данных — возможно, в запросе используются данные неправильного типа. Убедитесь, что типы данных, указанные в запросе, соответствуют типам данных, используемым в таблице.
  • Ошибка в структуре запроса — небрежность при написании запроса или ошибка в синтаксисе запроса может привести к тому, что данные не будут найдены. Обратитесь к справочной документации для проверки правильности написания запроса.
  • Неверная настройка прав доступа — если у пользователя отсутствуют необходимые права доступа к таблице или данным, то запрос может завершиться с ошибкой ORA-01403. Убедитесь, что пользователю предоставлены соответствующие права доступа.

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

Отсутствие данных в таблице

Ошибка ORA-01403: не найдены данные может возникать, когда в таблице отсутствуют записи, и программа или запрос пытаются получить доступ к данным, которых нет.

Причины возникновения ошибки могут быть различными:

  • Пустая таблица: Если таблица не содержит ни одной записи, то при попытке выполнить операцию, которая требует наличия данных в таблице, будет возникать ошибка ORA-01403.
  • Удаление данных: Если данные, на которые ссылается программа или запрос, были удалены, то при попытке получить доступ к этим данным будет возникать ошибка ORA-01403.
  • Некорректный запрос: Ошибка ORA-01403 может возникнуть при выполнении некорректного запроса, например, при попытке выбрать данные, которые не существуют в таблице.

Для решения проблемы отсутствия данных в таблице можно предпринять следующие шаги:

  1. Проверить наличие данных: Проверьте, содержат ли таблицы необходимые данные для выполнения операции. Если таблица пуста, необходимо добавить данные.
  2. Проверить корректность запроса: Проверьте, правильно ли составлен запрос. Убедитесь, что запрос выбирает данные из правильной таблицы и использует правильные условия.
  3. Восстановить удаленные данные: Если данные были удалены, необходимо восстановить их из резервной копии или другого источника.

При возникновении ошибки ORA-01403: не найдены данные рекомендуется также обратиться к документации Oracle или к специалистам для получения дополнительной помощи и конкретного решения проблемы в вашем конкретном случае.

Проблемы с правами доступа

Одной из распространенных причин возникновения ошибки ORA-01403 являются проблемы с правами доступа к данным в базе данных Oracle. Это может быть вызвано несоответствием прав доступа пользователя к определенным таблицам, представлениям или другим объектам базы данных.

Если пользователь не имеет необходимых прав доступа для выполнения запроса, то база данных выдаст ошибку ORA-01403, указывая на отсутствие данных.

Для решения проблемы с правами доступа рекомендуется выполнить следующие действия:

  1. Проверить права доступа пользователя. Убедитесь, что пользователь имеет необходимые права для выполнения запросов, включая доступ к требуемым таблицам и представлениям. Если необходимо, обратитесь к администратору базы данных для уточнения и настройки прав.
  2. Убедитесь в корректности имени и схемы объектов базы данных. При выполнении запросов необходимо указывать правильные имена таблиц, представлений и других объектов базы данных.
  3. Проверьте, что объекты базы данных существуют и доступны. Убедитесь, что требуемые таблицы и представления существуют, а также что они доступны для пользователя.
  4. Обратитесь к администратору базы данных для проверки наличия и настройки ролей, привилегий и других аспектов безопасности. Возможно, пользователь не имеет прав на выполнение определенных операций в базе данных.

При решении проблем с правами доступа в Oracle рекомендуется также обратить внимание на возможные ошибки в SQL-запросах, использование правильного синтаксиса и именования объектов, а также на наличие ограничений целостности данных, которые могут повлиять на доступ пользователя к данным.

В случае продолжающихся проблем с правами доступа, рекомендуется обратиться к опытному специалисту или администратору базы данных Oracle для более детального анализа и решения проблемы.

Неправильное использование функций

ORA-01403: не найдены данные — это ошибка, которая возникает, когда функция не находит нужные данные при выполнении запроса к базе данных Oracle.

Ошибки такого типа могут возникать при нескольких ситуациях, связанных с неправильным использованием функций:

  1. Функция вызывается с неправильными параметрами. В некоторых случаях, неправильные параметры, переданные в функцию, могут привести к тому, что не будут найдены нужные данные. Например, если в функцию передать некорректное значение искомого ID, то запрос может не найти соответствующую запись и выдаст ошибку ORA-01403.

  2. Функция используется без необходимой предварительной настройки. Некоторые функции требуют определенных предварительных действий для их правильной работы. Например, перед использованием функции, которая выполняет выборку данных из таблицы, необходимо предварительно подготовить данные или убедиться в наличии нужных записей в базе данных. Если не выполнить эти действия, может возникнуть ошибка ORA-01403.

  3. Неправильное использование встроенных функций. В Oracle есть множество встроенных функций, таких как функции агрегации (SUM, AVG, MAX, MIN), функции преобразования (TO_CHAR, TO_NUMBER, TO_DATE) и другие. Неправильное использование таких функций может привести к ошибке ORA-01403. Например, если в функцию агрегации не передать ни одного значения, то она не сможет выполнить вычисления и вызовет ошибку.

Для исправления ошибки ORA-01403, связанной с неправильным использованием функций, необходимо внимательно проверить корректность вызова функции, правильность передаваемых параметров и выполнить все необходимые предварительные настройки. Также стоит обратиться к документации Oracle или обратиться к специалисту по базам данных для получения дополнительной помощи.

Ошибка ORA-01403: не найдены данные может возникать при выполнении запроса к базе данных Oracle, когда результат запроса не содержит ни одной записи.

Есть несколько возможных причин, по которым может возникнуть ошибка ORA-01403:

  1. Неправильно составлен запрос. Проверьте правильность написания условий, таблиц и столбцов в запросе.
  2. Отсутствие данных, удовлетворяющих условиям запроса. Убедитесь, что в базе данных есть данные, соответствующие запросу.
  3. Проблемы с доступом к данным. Проверьте права доступа к таблицам и столбцам в базе данных.

Для исправления ошибки ORA-01403 можно предпринять следующие действия:

  • Проверьте правильность написания запроса. Убедитесь, что используете правильные имена таблиц и столбцов, а также условия в запросе.
  • Проверьте наличие данных, удовлетворяющих условиям запроса. Если данных нет, то можно изменить условия запроса или добавить записи в базу данных.
  • Проверьте права доступа к таблицам и столбцам в базе данных. Убедитесь, что у вас есть права на чтение или изменение данных.

В случае, если причина ошибки ORA-01403 не является очевидной или вы не можете найти решение самостоятельно, рекомендуется обратиться к специалистам технической поддержки Oracle или к соответствующим форумам, где можно получить помощь и конкретные рекомендации для исправления ошибки.

  • Ошибка ora 29548
  • Ошибка ora 1017
  • Ошибка ora 29273
  • Ошибка ora 29259
  • Ошибка ora 08103 object no longer exists