PL/SQL 下SQL结果集以html形式发送邮件

简介:       在运维的过程中,有时候需要定时将SQL查询的数据结果集以html表格形式发送邮件,因此需要将SQL查询得到的结果集拼接成html代码。对于这种情形通常有二种方式来完成。

      在运维的过程中,有时候需要定时将SQL查询的数据结果集以html表格形式发送邮件,因此需要将SQL查询得到的结果集拼接成html代码。对于这种情形通常有二种方式来完成。一是直接使用cron job来定时轮询并借助os级别的邮件程序来完成。其查询结果集可以直接在SQL*Plus下通过设置html标签自动实现html表格形式。一种方式是在Oracle中使用scheduler job来定时轮询。这种方式需要我们手动拼接html代码。本文即是对第二种情形展开描述。

      关于PL/SQL下如何发送邮件可参考: PL/SQL 下邮件发送程序
      OS 下发送邮件可参考:不可或缺的 sendEmail

 

1、代码描述

--下面的代码段主要主要是用于发送数据库A部分数据同步到数据库B是出现的错误信息
--表syn_data_err_log_tbl主要是记录错误日志,也就是说只要表中出现了新的记录或者旧记录且mailed列标志为N,即表示需要发送邮件
--下面逐一描述代码段信息,该代码段可以封装到package.
 PROCEDURE email_on_syn_data_err_log (err_num   OUT NUMBER,
                                        err_msg   OUT VARCHAR2)
   AS
      v_msg_txt        VARCHAR2 (32767);
      v_sub            VARCHAR2 (100);
      v_html_header    VARCHAR (4000);
      v_html_content   VARCHAR (32767);
      v_count          NUMBER;
      v_log_seq        NUMBER (12);
      v_loop_count     NUMBER := 0;

      CURSOR cur_errlog    --使用cursor来生成表格标题部分
      IS
           SELECT '<tr >
                            <td style="vertical-align:top;padding: 5px;"> '
                  || TO_CHAR (sd.log_seq)
                  || '</td>
                            <td style="vertical-align:top;padding: 5px;"> '
                  || sd.process
                  || '</td>'
                  || '<td  style="vertical-align:top;padding: 5px;"> '
                  || sd.rec_id
                  || '</td> '
                  || '<td style="padding: 5px;"> '
                  || REPLACE (REPLACE (sd.err_msg, '<', ';'), '>', ';')
                  || '</td>'
                  || '<td  style="vertical-align:top;padding: 5px;">'
                  || TO_CHAR (sd.log_time, 'yyyy-mm-dd hh24:mi:ss')
                  || '</td>
                            </tr>',
                  sd.log_seq
             FROM syn_data_err_log_tbl sd
            WHERE sd.mailed = 'N'
         ORDER BY sd.log_seq;
   BEGIN
      err_num := common_pkg.c_suc_general;

      SELECT COUNT (*)     
        INTO v_count        -->统计当次需要发送的总记录数
        FROM syn_data_err_log_tbl sd
       WHERE sd.mailed = 'N';

      IF v_count > 0        --> 表示有记录需要发送邮件
      THEN
         SELECT 'Job process failed on ' || instance_name || '/' || host_name
           INTO v_sub       -->生成邮件的subject  
           FROM v$instance;

         v_html_header :=             -->定义表格的header部分信息
            '<html><header><style>
                    #log-table {
                    margin: 0;
                    padding: 0;
                    width: 90%;
                    border-collapse: collapse;
                    font: 12px "Lucida Grande", Helvetica, Sans-Serif;
                    border:1px solid #CCC;
                    }
                    #log-table td {
                    padding: 5px;
                    border:1px solid #CCC;
                    }
                    #log-table th {
                    padding: 5px;
                    background: black;
                    color: white;
                    text-align: left;
                    }
                    #log-table tr:nth-child(even) td {
                    background: #eee;
                    }
                    </style></header><body>
                             <table id="log-table"  style="width: 100%;border-collapse: collapse;font-size:12px;">';
         v_html_header :=              -->下面是拼接每一个字段的信息
            v_html_header
            || '<tr style="background: black;">
                     <th  style="color: white;width:100px;padding: 5px;">Log sequence</th>
                     <th  style="color: white;width:100px;padding: 5px;">Process</th>
                     <th  style="color: white;width:100px;padding: 5px;">Rec ID</th>
                     <th  style="color: white;width:100px;padding: 5px;">Error message</th>
                     <th  style="color: white;padding: 5px;">Log time</th></tr>';

         OPEN cur_errlog;     -->打开游标

         LOOP
            FETCH cur_errlog   
            INTO v_msg_txt, v_log_seq;

            EXIT WHEN cur_errlog%NOTFOUND;
            v_loop_count := v_loop_count + 1;
            v_html_content := v_html_content || v_msg_txt;   --->注意这里,不断地把从原表中的err_msg拿出来进行拼接通过v_msg_txt

            --Maximun record = 50 --
            IF v_loop_count > 50              --->这里的判断就是用于控制表格总共显示多少行
            THEN                              --->主要是用于如果由于需要拼接的行太多导致超过字符长度32767,因此从50行处截断
               v_html_content :=
                  v_html_header || v_html_content || '</table></body></html>';  --->这里添加html尾部
               SENDMAIL_PKG.sendmail (
                  bo_system_pkg.get_sys_para_value ('EMAIL_SENDER_HC_EMAIL'),   --->调用函数获得邮件的接收者,此处可以直接写接收者
                  v_sub,
                  v_html_content,
                  err_num,
                  err_msg);
               v_msg_txt := '';             --->注,此处对三个本地变量置空
               v_html_content := '';
               v_loop_count := 0;               

               UPDATE syn_data_err_log_tbl sd     --->根据log_seq字段对已经发送过的记录标记为Y
                  SET mailed = 'Y'
                WHERE sd.mailed = 'N' AND log_seq <= v_log_seq;
            -- COMMIT;
            ELSIF v_count = cur_errlog%ROWCOUNT   --->当v_count与游标取得记录数相等时,拼接表格尾部html代码,发送邮件以及更新mailed列
            THEN
               v_html_content :=
                  v_html_header || v_html_content || '</table></body></html>';
               SENDMAIL_PKG.sendmail (
                  bo_system_pkg.get_sys_para_value ('EMAIL_SENDER_HC_EMAIL'),
                  v_sub,
                  v_html_content,
                  err_num,
                  err_msg);
               v_msg_txt := '';
               v_html_content := '';

               UPDATE syn_data_err_log_tbl sd
                  SET mailed = 'Y'
                WHERE sd.mailed = 'N' AND log_seq <= v_log_seq;
            END IF;
         END LOOP;

         COMMIT;

         CLOSE cur_errlog;
      END IF;
   EXCEPTION
      WHEN NO_DATA_FOUND
      THEN
         err_num := common_pkg.c_fail_data_not_found;
      WHEN OTHERS
      THEN
         err_num := common_pkg.c_fail_user_define;
         err_msg := 'Fail in process SENDMAIL_PKG.email_on_syn_data_err_log. ';
   END; 

2、调用示例及邮件样式  

gx_admin@SYBO2SZ> DECLARE 
  2    ERR_NUM NUMBER;
  3    ERR_MSG VARCHAR2(32767);
  4  
  5  BEGIN 
  6    ERR_NUM := NULL;
  7    ERR_MSG := NULL;
  8  
  9    GX_ADMIN.SENDMAIL_PKG.EMAIL_ON_SYN_DATA_ERR_LOG ( ERR_NUM, ERR_MSG );
 10    COMMIT; 
 11  END;
 12  /

PL/SQL procedure successfully completed.


 

Oracle&nbsp;牛鹏社    Oracle DBsupport

更多参考

使用 DBMS_PROFILER 定位 PL/SQL 瓶颈代码

使用PL/SQL Developer剖析PL/SQL代码

对比 PL/SQL profiler 剖析结果

PL/SQL Profiler 剖析报告生成html

DML Error Logging 特性 

PL/SQL --> 游标

PL/SQL --> 隐式游标(SQL%FOUND)

批量SQL之 FORALL 语句

批量SQL之 BULK COLLECT 子句

PL/SQL 集合的初始化与赋值

PL/SQL 联合数组与嵌套表
PL/SQL 变长数组
PL/SQL --> PL/SQL记录

SQL tuning 步骤

高效SQL语句必杀技

父游标、子游标及共享游标

绑定变量及其优缺点

dbms_xplan之display_cursor函数的使用

dbms_xplan之display函数的使用

执行计划中各字段各模块描述

使用 EXPLAIN PLAN 获取SQL语句执行计划

目录
相关文章
|
8月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL隐式游标:数据的“自动导游”与“轻松之旅”
【4月更文挑战第19天】Oracle PL/SQL中的隐式游标是自动管理的数据导航工具,简化编程工作,尤其适用于简单查询和DML操作。它自动处理数据访问,提供高效、简洁的代码,但不适用于复杂场景。显式游标在需要精细控制时更有优势。了解并适时使用隐式游标,能提升数据处理效率,让开发更加轻松。
|
2月前
|
SQL 数据采集 监控
局域网监控电脑屏幕软件:PL/SQL 实现的数据库关联监控
在当今网络环境中,基于PL/SQL的局域网监控系统对于企业和机构的信息安全至关重要。该系统包括屏幕数据采集、数据处理与分析、数据库关联与存储三个核心模块,能够提供全面而准确的监控信息,帮助管理者有效监督局域网内的电脑使用情况。
40 2
|
3月前
|
SQL 存储 移动开发
HTML5 Web SQL 数据库详解
Web SQL 数据库是 HTML5 中的一种本地存储技术,允许在浏览器中使用 SQL 语言操作本地数据,支持离线访问和事务处理,适用于缓存数据和小型应用。然而,其存储容量有限且仅部分现代浏览器支持,标准已不再积极维护,未来可能被 IndexedDB 和 localStorage 等技术取代。使用时需谨慎考虑兼容性和发展前景。
|
5月前
|
SQL Oracle 关系型数据库
SQL与PL/SQL:数据库编程语言的比较
【8月更文挑战第31天】
103 0
|
7月前
|
SQL 数据库 Perl
PL/SQL中执行按钮变为灰色后如何恢复【已解决】
PL/SQL中执行按钮变为灰色后如何恢复【已解决】
556 0
|
8月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
8月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标自定义异常:数据探险家的“专属警示灯”
【4月更文挑战第19天】Oracle PL/SQL中的游标自定义异常是处理数据异常的有效工具,犹如数据探险家的警示灯。通过声明异常名(如`LOW_SALARY_EXCEPTION`)并在满足特定条件(如薪资低于阈值)时使用`RAISE`抛出异常,能灵活应对复杂业务规则。示例代码展示了如何在游标操作中定义和捕获自定义异常,提升代码可读性和维护性,确保在面对数据挑战时能及时响应。掌握自定义异常,让数据管理更从容。
|
8月前
|
SQL Oracle 安全
Oracle的PL/SQL游标异常处理:从“惊涛骇浪”到“风平浪静”
【4月更文挑战第19天】Oracle PL/SQL游标异常处理确保了在数据操作中遇到的问题得以优雅解决,如`NO_DATA_FOUND`或`TOO_MANY_ROWS`等异常。通过使用`EXCEPTION`块捕获并处理这些异常,开发者可以防止程序因游标问题而崩溃。例如,当查询无结果时,可以显示定制的错误信息而不是让程序终止。掌握游标异常处理是成为娴熟的Oracle数据管理员的关键,能保证在复杂的数据环境中稳健运行。
|
8月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL中FOR语句循环游标的奇幻之旅
【4月更文挑战第19天】在Oracle PL/SQL中,FOR语句与游标结合,提供了一种简化数据遍历的高效方法。传统游标处理涉及多个步骤,而FOR循环游标自动处理细节,使代码更简洁、易读。通过示例展示了如何使用FOR循环游标遍历员工表并打印姓名和薪资,对比传统方式,FOR语句不仅简化代码,还因内部优化提升了执行效率。推荐开发者利用这一功能提高工作效率。
|
8月前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL显式游标:数据的“私人导游”与“定制之旅”
【4月更文挑战第19天】Oracle PL/SQL中的显式游标提供灵活精确的数据访问,与隐式游标不同,需手动定义、打开、获取和关闭。通过DECLARE定义游标及SQL查询,OPEN启动查询,FETCH逐行获取数据,CLOSE释放资源。显式游标适用于复杂数据处理,但应注意SQL效率、游标管理及异常处理。它是数据海洋的私人导游,助力实现业务逻辑和数据探险。