On the Old, the New —— 用sql语句生成语句的例子
转自:http://www.oracle.com/technology/oramag/oracle/07-may/o37plsql.html
TECHNOLOGY: PL/SQL Practices
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语句生成语句的例子相关推荐
- mysql种default约束的语句_sql语句大全之SQL DEFAULT 约束
SQL DEFAULT约束 DEFAULT 约束用于向列中插入默认值. 如果没有规定其他的值,那么会将默认值添加到所有的新纪录. SQL DEFAULT Constraint on CREATE TA ...
- SQL update select语句
SQL update select语句 最常用的update语法是: UPDATE <table_name> SET <column_name1> = <value> ...
- MySQL补充部分-SQL逻辑查询语句执行顺序
一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...
- SQL基础---SQL SELECT DISTINCT 语句
SQL SELECT DISTINCT 语句 本章讲解 SELECT DISTINCT 语句. SQL SELECT DISTINCT 语句 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希 ...
- mysql五补充部分:SQL逻辑查询语句执行顺序
mysql五补充部分:SQL逻辑查询语句执行顺序一 SELECT语句关键字的定义顺序 二 SELECT语句关键字的执行顺序 三 准备表和数据 四 准备SQL逻辑查询测试语句 五 执行顺序分析 一 SE ...
- [sqlserver脚本]查看指定SQL语句生成了哪些执行计划
参考SQL技术内幕写了一段脚本,可以通过这段脚本查看执行指定SQL语句后,系统生成了哪些执行计划.使用时注意以下几点: 修改use MyTest,换成自己的数据库名字. 将 exec sp_page_ ...
- mysql+sql+子查询语句_SQL子查询
子查询或内部查询或嵌套查询在另一个SQL查询的查询和嵌入式WHERE子句中. 子查询用于返回将被用于在主查询作为条件的数据,以进一步限制要检索的数据. 子查询可以在SELECT,INSERT,UPDA ...
- 将EXCEL中的列拼接成SQL insert插入语句
工作中经常需要将EXCEL文件中的数据导入到各种数据库,但是对于不熟悉数据库的人来说,如果直接使用命令执行导入,这无疑是一个难题,也是一个风险.这里我们直接在EXCEL文件中拼接成标准的SQL ins ...
- SQL ALTER TABLE 语句
SQL ALTER TABLE 语句 ALTER TABLE 语句 ALTER TABLE 语句用于在已有的表中添加.删除或修改列. SQL ALTER TABLE 语法 如需在表中添加列,请使用下面 ...
最新文章
- Eclipse生成jar文件
- 大叔也说Xamarin~Android篇~Activity之间传递数组
- Java常见的系统路径与获取方法
- Objective-C 学习笔记
- 设计专业作品展示舞台,灵感源泉
- 使用PDF-XChange Editor为PDF文件添加签名(图片+签名)
- Codeforces 781B. Innokenty and a Football League
- vega56刷64_Vega56刷64的BIOS教程
- 斗地主服务器维护中,天天斗地主游戏问题解决方法
- 【国产MCU移植】看看有没有你需要的,一起来查漏补缺吧!(附已报名的硬件)...
- USPS国际快递查询单号
- oracle查询同一天生日的,关于date生日判断的问题
- 阳历和阴历的互转函数
- 机器学习 | 牛顿冷却定律
- 等了两年半!计算机专硕重大改革!不再只是电子信息了!
- ASP.NET MVC 支付宝当面付(沙箱环境)-即扫二维码支付1(填坑)
- C++11多线程 内存序(std::memory_order_consume)
- 配置基于IPv6的单节点Ceph
- pipeline设计模式
- [好久没有看到这么真切的文章了]在怀疑的时代依然需要信仰