2010-07-22 2 views
1

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

У меня есть функция F_GENERATE_REPORT и процедура P_SEND_REPORT_AS_EMAIL. процедура P_SEND_REPORT_AS_EMAIL использует F_GENERATE_REPORT как тело по электронной почте, как UTL_MAIL.SEND (сообщение => F_GENERATE_REPORT (5)), где 5 используется для верхней 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; 

Процедура Отправить Email

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 => '[email protected]', 
       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; 

ответ

5

подпись для 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 (> 32k байтов).

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

+0

+1 APEX_Email выглядит красиво. Мы бы сэкономили много времени, если были доступны, когда мы свернули нашу обертку utl_smpt. –

3

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

Глядя на ссылку больше, я не уверен, что это лучший пример, но я не нашел хорошего примера процедуры, принимающей 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 имеет хорошую ссылку для синтаксиса here.