转自:http://www.oracle.com/technology/oramag/oracle/07-may/o37plsql.html

TECHNOLOGY: PL/SQL Practices

<script type="text/javascript"> addthis_url = location.href; addthis_title = document.title; addthis_pub = 'oraclecom'; </script> <script src="http://s7.addthis.com/js/addthis_widget.php?v=12" type="text/javascript"></script>

On the Old, the New, and ORA-22160
By Steven Feuerstein

Best practices for managing old and new information and preventing FORALL errors

I want to audit updates to a table, including the before and after values of each column in my table. To do this, I would love to pass :NEW and :OLD as arguments to procedures, but that doesn't seem to work. I'd really like to avoid hard-coding column names, because then I run into compilation issues when columns are added, dropped, or renamed. Is this possible? This is how I am currently doing things:

CREATE TABLE load_a (
a1 VARCHAR2 (10), a2 VARCHAR2 (10) )
/

CREATE OR REPLACE TRIGGER ins_load_a
AFTER UPDATE
ON scott.load_a
FOR EACH ROW
DECLARE
a_rec   scott.load_a%ROWTYPE;
BEGIN
a_rec.a1 := :OLD.a1;
a_rec.a2 := :OLD.a2;
save_old_values (a_rec);
END;
/

The bad news is that up through Oracle Database 10g , you cannot pass :OLD and :NEW as arguments to procedures. The good news is that at least you don't have to write all the code needed to accomplish your goal.

Let's take a step back: you want to pass the old and new values available inside a trigger to a stored procedure to process the data (write the information to a log table, execute validation logic, and so on). You cannot pass :OLD and :NEW as records; instead, you must copy the individual fields of those pseudorecords to a real record that can be passed to the procedure.

It certainly is tedious and time-consuming to write that code yourself, especially for tables with many columns. Fortunately, it is quite easy to generate the code you desire.

I offer you the gen_audit_trigger_text procedure shown in Listing 1 to help you achieve your goal. I ran this program for the employees table and, after some formatting, had the resulting code shown in Listing 2.

Code Listing 1: gen_audit_trigger_text

CREATE OR REPLACE PROCEDURE gen_audit_trigger_text (
table_in IN VARCHAR2
, owner_in IN VARCHAR2 := USER
, program_name_in IN VARCHAR2 := 'process_data'
)
IS
c_rowtype           CONSTANT VARCHAR2 (100)     := table_in || '%ROWTYPE';
l_columns            DBMS_SQL.varchar2s;

PROCEDURE gen_copy_proc (old_or_new_in IN VARCHAR2)
IS
BEGIN
DBMS_OUTPUT.put_line (   'FUNCTION copy_'
|| old_or_new_in
|| ' RETURN '
|| c_rowtype
|| ' IS l_return '
|| c_rowtype
|| '; BEGIN '
);

FOR indx IN 1 .. l_columns.COUNT
LOOP
DBMS_OUTPUT.put_line (   '   l_return.'
|| l_columns (indx)
|| ' := '
|| ':'
|| old_or_new_in
|| '.'
|| l_columns (indx)
|| ';'
);
END LOOP;

DBMS_OUTPUT.put_line ('RETURN l_return;');
DBMS_OUTPUT.put_line ('END copy_' || old_or_new_in || ';');
END gen_copy_proc;
BEGIN
SELECT LOWER (column_name) column_name
BULK COLLECT INTO l_columns
FROM all_tab_columns
WHERE owner = UPPER (owner_in) AND table_name = UPPER (table_in);

DBMS_OUTPUT.put_line ('DECLARE');
DBMS_OUTPUT.put_line ('   my_Old ' || table_in || '%ROWTYPE;');
DBMS_OUTPUT.put_line ('   my_New ' || table_in || '%ROWTYPE;');
gen_copy_proc ('old');
gen_copy_proc ('new');
DBMS_OUTPUT.put_line ('BEGIN');
DBMS_OUTPUT.put_line ('   my_Old := copy_Old ();');
DBMS_OUTPUT.put_line ('   my_New := copy_New ();');
DBMS_OUTPUT.put_line ('   ' || program_name_in || '(my_Old, my_new);');
DBMS_OUTPUT.put_line ('END;');
END gen_audit_trigger_text;
/

Code Listing 2: Result of gen_audit_trigger_text procedure on employees table

DECLARE
my_old    employees%ROWTYPE;
my_new   employees%ROWTYPE;

FUNCTION copy_old
RETURN employees%ROWTYPE
IS
l_return employees%ROWTYPE;
BEGIN
l_return.employee_id := :OLD.employee_id;
l_return.first_name := :OLD.first_name;
l_return.last_name := :OLD.last_name;
l_return.email := :OLD.email;
l_return.phone_number := :OLD.phone_number;
l_return.hire_date := :OLD.hire_date;
l_return.job_id := :OLD.job_id;
l_return.salary := :OLD.salary;
l_return.commission_pct := :OLD.commission_pct;
l_return.manager_id := :OLD.manager_id;
l_return.department_id := :OLD.department_id;
RETURN l_return;
END copy_old;

FUNCTION copy_new
RETURN employees%ROWTYPE
IS
l_return employees%ROWTYPE;
BEGIN
l_return.employee_id := :NEW.employee_id;
l_return.first_name := :NEW.first_name;
l_return.last_name := :NEW.last_name;
l_return.email := :NEW.email;
l_return.phone_number := :NEW.phone_number;
l_return.hire_date := :NEW.hire_date;
l_return.job_id := :NEW.job_id;
l_return.salary := :NEW.salary;
l_return.commission_pct := :NEW.commission_pct;
l_return.manager_id := :NEW.manager_id;
l_return.department_id := :NEW.department_id;
RETURN l_return;
END copy_new;
BEGIN
my_old := copy_old ();
my_new := copy_new ();
process_data (my_old, my_new);
END;

On the Old, the New —— 用sql语句生成语句的例子相关推荐

  1. mysql种default约束的语句_sql语句大全之SQL DEFAULT 约束

    SQL DEFAULT约束 DEFAULT 约束用于向列中插入默认值. 如果没有规定其他的值,那么会将默认值添加到所有的新纪录. SQL DEFAULT Constraint on CREATE TA ...

  2. SQL update select语句

    SQL update select语句 最常用的update语法是: UPDATE <table_name> SET <column_name1> = <value> ...

  3. MySQL补充部分-SQL逻辑查询语句执行顺序

    一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...

  4. SQL基础---SQL SELECT DISTINCT 语句

    SQL SELECT DISTINCT 语句 本章讲解 SELECT DISTINCT 语句. SQL SELECT DISTINCT 语句 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希 ...

  5. mysql五补充部分:SQL逻辑查询语句执行顺序

    mysql五补充部分:SQL逻辑查询语句执行顺序一 SELECT语句关键字的定义顺序 二 SELECT语句关键字的执行顺序 三 准备表和数据 四 准备SQL逻辑查询测试语句 五 执行顺序分析 一 SE ...

  6. [sqlserver脚本]查看指定SQL语句生成了哪些执行计划

    参考SQL技术内幕写了一段脚本,可以通过这段脚本查看执行指定SQL语句后,系统生成了哪些执行计划.使用时注意以下几点: 修改use MyTest,换成自己的数据库名字. 将 exec sp_page_ ...

  7. mysql+sql+子查询语句_SQL子查询

    子查询或内部查询或嵌套查询在另一个SQL查询的查询和嵌入式WHERE子句中. 子查询用于返回将被用于在主查询作为条件的数据,以进一步限制要检索的数据. 子查询可以在SELECT,INSERT,UPDA ...

  8. 将EXCEL中的列拼接成SQL insert插入语句

    工作中经常需要将EXCEL文件中的数据导入到各种数据库,但是对于不熟悉数据库的人来说,如果直接使用命令执行导入,这无疑是一个难题,也是一个风险.这里我们直接在EXCEL文件中拼接成标准的SQL ins ...

  9. SQL ALTER TABLE 语句

    SQL ALTER TABLE 语句 ALTER TABLE 语句 ALTER TABLE 语句用于在已有的表中添加.删除或修改列. SQL ALTER TABLE 语法 如需在表中添加列,请使用下面 ...

最新文章

  1. Eclipse生成jar文件
  2. 大叔也说Xamarin~Android篇~Activity之间传递数组
  3. Java常见的系统路径与获取方法
  4. Objective-C 学习笔记
  5. 设计专业作品展示舞台,灵感源泉
  6. 使用PDF-XChange Editor为PDF文件添加签名(图片+签名)
  7. Codeforces 781B. Innokenty and a Football League
  8. vega56刷64_Vega56刷64的BIOS教程
  9. 斗地主服务器维护中,天天斗地主游戏问题解决方法
  10. 【国产MCU移植】看看有没有你需要的,一起来查漏补缺吧!(附已报名的硬件)...
  11. USPS国际快递查询单号
  12. oracle查询同一天生日的,关于date生日判断的问题
  13. 阳历和阴历的互转函数
  14. 机器学习 | 牛顿冷却定律
  15. 等了两年半!计算机专硕重大改革!不再只是电子信息了!
  16. ASP.NET MVC 支付宝当面付(沙箱环境)-即扫二维码支付1(填坑)
  17. C++11多线程 内存序(std::memory_order_consume)
  18. 配置基于IPv6的单节点Ceph
  19. pipeline设计模式
  20. [好久没有看到这么真切的文章了]在怀疑的时代依然需要信仰

热门文章

  1. C#制作图片压缩工具
  2. 【HTTP协议】超详细的HTTP协议详解
  3. ThinkPHP的访问模式分为四种模式
  4. 4.12—002—周五
  5. 《Node.js核心技术教程》读书笔记---思维导图版
  6. SpringMVC4集成ehcache
  7. HDOJ 5373 The shortest problem 【数论】
  8. 第九章 泛型结构和接口
  9. POJ 2391 Ombrophobic Bovines 网络流 建模
  10. javascript设计模式之观察者模式