ORACLE Числовая или Значение Ошибка - PullRequest
1 голос
/ 22 июля 2010

Я пытаюсь создать отчет о запросах с наибольшим количеством операций чтения с диска. Сгенерированный отчет будет отправлен по электронной почте. Я написал некоторый код, как показано ниже. Когда я включаю 15 лучших запросов, он работает нормально, но если я увеличиваю количество, я получаю «ошибку числа или значения». Я предполагаю, что это происходит, потому что я превышаю лимит некоторых типов данных но не смог идентифицировать это. Кто-нибудь видит проблему? И как я могу отправить огромный отчет без такой ошибки?

У меня есть функция F_GENERATE_REPORT и процедура P_SEND_REPORT_AS_EMAIL. Процедура P_SEND_REPORT_AS_EMAIL использует F_GENERATE_REPORT в качестве тела письма, например UTL_MAIL.SEND (message => F_GENERATE_REPORT (5)), где 5 используется для TOP 5.

Ошибка в строке UTL_MAIL.SEND () в процедуре P_SEND_REPORT_AS_EMAIL

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

clgenerated_html_markup - это CLOB.

FOR cur_for_query IN (SELECT * 
                        FROM (SELECT buffer_gets,rows_processed,executions,
                                     fetches,hash_value,sql_text, disk_reads,
                                     rank() over(ORDER BY disk_reads DESC) AS rank FROM v$sqlarea)
                       WHERE rank <= nquery_count)
LOOP
   --dbms_output.put_line(counter);
   --counter := counter + 1;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEROWOPEN || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA(cur_for_query.rank,null,null,null,null,null,'class=tdData') || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA(cur_for_query.sql_text,null,null,null,null,null,'class=tdSQLText') || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA(TO_CHAR(NVL(cur_for_query.disk_reads,'')),'CENTER',null,null,null,null,'class=tdData') || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA(TO_CHAR(NVL(cur_for_query.buffer_gets,'')),'CENTER',null,null,null,null,'class=tdData') || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA(TO_CHAR(NVL(cur_for_query.executions,'')),'CENTER',null,null,null,null,'class=tdData') || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA(TO_CHAR(NVL(cur_for_query.fetches,'')),'CENTER',null,null,null,null,'class=tdData') || CHR(10) ;
   --clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA('','CENTER',null,null,null,null,'class=tdData') || CHR(10) ;
   --clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEDATA('','CENTER',null,null,null,null,'class=tdData') || CHR(10) ;
   clgenerated_html_markup := clgenerated_html_markup || HTF.TABLEROWCLOSE || CHR(10) ;
END LOOP;

Процедура отправки электронного письма

PROCEDURE P_SEND_REPORT_AS_EMAIL
(
 vreceipent VARCHAR2,
 vsubject VARCHAR2,
 nquery_count NUMBER DEFAULT 5 
 )

 IS
 BEGIN

 -- INPUT VALIDATION
 IF vreceipent IS NULL THEN
             RAISE_APPLICATION_ERROR(value_can_not_be_null,'DBA_EXHAUSTIVE_QUERY_PKG::P_SEND_REPORT_AS_EMAIL::Receipent Email Address Can Not Be Null.');
 END IF;
 -- END OF INPUT VALIDATION


 UTL_MAIL.SEND(sender => 'mehmet.altiparmak@domain.com',
               recipients => vreceipent,
               subject => NVL(vsubject,''),
               message => F_GENERATE_REPORT(nquery_count),
               mime_type => 'text/html; charset=us-ascii');

EXCEPTION 
WHEN OTHERS THEN
   -- TODO LOG ERROR HERE
 RAISE;

 END P_SEND_REPORT_AS_EMAIL;

Ответы [ 2 ]

5 голосов
/ 22 июля 2010

подпись для UTL_MAIL.SEND:

UTL_MAIL.SEND (
   sender      IN    VARCHAR2 CHARACTER SET ANY_CS,
   recipients  IN    VARCHAR2 CHARACTER SET ANY_CS,
   cc          IN    VARCHAR2 CHARACTER SET ANY_CS DEFAULT NULL,
   bcc         IN    VARCHAR2 CHARACTER SET ANY_CS DEFAULT NULL,
   subject     IN    VARCHAR2 CHARACTER SET ANY_CS DEFAULT NULL,
** message     IN    VARCHAR2 CHARACTER SET ANY_CS, **
   mime_type   IN    VARCHAR2 DEFAULT 'text/plain; charset=us-ascii',
   priority    IN    PLS_INTEGER DEFAULT NULL);

Как видите, вы вызываете эту процедуру с параметром message с CLOB вместо VARCHAR2. До 32 Кбайт включается неявное преобразование, и все в порядке. Я подозреваю, что ошибка, которую вы получаете, когда вы пытаетесь передать процедуру с CLOB, который не конвертируется в VARCHAR2 (> 32 Кбайт).

Самый простой способ отправки электронных писем с сообщениями CLOB в Oracle - через APEX_EMAIL (установлен по умолчанию в новейших версиях БД, если не установлен, вы можете загрузить APEX из Oracle). В старых версиях вам понадобится обходной путь. Например, Том Кайт описывает, как использовать java для отправки больших писем в Oracle 8i на AskTom. В качестве альтернативы, вы также можете написать свою собственную процедуру PLSQL или провести некоторое исследование в сети, вы обнаружите, что можно использовать UTL_TCP для связи с почтовым сервером (и отправки данных в формате по вашему выбору).

3 голосов
/ 22 июля 2010

Максимальный размер Varchar2 в PL / SQL составляет 32 КБ. Поскольку clgenerated_html_markup использует clob, у вас все хорошо, но когда вы вызываете UTL_MAIL.SEND, он пытается преобразовать его в Varchar2 и не может. Вам придется переключиться на почтовый инструмент более низкого уровня, такой как UTL_SMTP, как показано здесь .

Глядя на ссылку больше, я не уверен, что это лучший пример, но я не нашел хорошего примера процедуры, принимающей clob в качестве сообщения для отправки с использованием UTL_SMTP. Концепция похожа, но ваш заголовок должен выглядеть примерно так:

   PROCEDURE SendSMTP(
      pTo       Varchar2    Default null,
      pSubject  Varchar2    Default null,
      pBody     Clob        Default empty_clob,
      pFrom     Varchar2    Default null,
      pCC       Varchar2    Default null,
      pBCC      Varchar2    Default null,
      pMimeType Varchar2    Default cDefaultMimeType,
      pSMTPHost Varchar2    Default cDefaultMailServer,
      pSMTPPort pls_integer Default cDefaultPort)

Psoug.org имеет хороший справочник по синтаксису здесь .

...