关于trigger过滤最大值的问题(54天)

作者: admin 分类: 公众号存档            0 次浏览 发布时间: 2014-04-26 22:03

公众号:杨建荣的学习笔记 · 作者:笔记54天 · 发布:2014-04-26 22:03:08 · 原文链接

今天碰到一个问题,开发有一个比较紧的需要,想问问我数据库这边能不能帮上忙。
如果开发那边来做,需要改代码,如果数据库这边能临时支持,代码就可以多做些测试,然后再打补丁了。
需求的情况大体是这样:有一个表的字段是number(11,4),意味着数据保持4为精度,总共长度支持11位,最大值位9999999.9999
如果超过了那个最大值(比如99999999,有8个9),想在update语句update之前能够把那个值改成9999999就可以了。
听起来好像可以使用trigger来做。简单做了个测试。

新建一个表,字段last_threshold的数据类型为number(11,4)

SQL> create table test_number(last_threshold number(11,4),content varchar2(100));
Table created.
然后插入一些数据,可以看到,我插入的小数点后是5个9,也可以插入。
SQL> insert into test_number values(1.99999,”);
1 row created.

SQL> insert into test_number values(9999999.9999,’a’);
1 row created.

SQL> insert into test_number values(9999999.9998,’b’);
1 row created.

SQL> insert into test_number values(9.999999,’c’);
1 row created.
SQL> commit;
Commit complete.

查看插入的数据情况,看到现实是下面的样子,有些疑惑,全都自作主张做了4舍5入了。
select *from test_number;

LAST_THRESHOLD CONTENT
————– ——————————
2
10000000 a
10000000 b
10 c

设置一下精度
SQL> col last_threshold format 99999999.99999
SQL> /
LAST_THRESHOLD CONTENT
————— ——————————
2.00000
9999999.99990 a
9999999.99980 b
10.00000 c

SQL> col last_threshold format 9999999.9999
SQL> /
LAST_THRESHOLD CONTENT
————– ——————————
2.0000
9999999.9999 a
9999999.9998 b
10.0000 c

想直接创建一个语句级的trigger,可惜失败了。
SQL> CREATE TRIGGER maxvalue_test
before UPDATE of LAST_THRESHOLD
ON test_number
begin
dbms_output.put_line(:old.last_threshold);
dbms_output.put_line(:new.last_threshold);
end;
/ 2 3 4 5 6 7 8
CREATE TRIGGER maxvalue_test
*
ERROR at line 1:
ORA-04082: NEW or OLD references not allowed in table level triggers

重头再来,先写一个trigger来测试一下是不是好使。
SQL> CREATE TRIGGER maxvalue_test
before UPDATE of LAST_THRESHOLD
ON test_number for each row
begin
dbms_output.put_line(:old.last_threshold);
dbms_output.put_line(:new.last_threshold);
end;
/ 2 3 4 5 6 7 8
Trigger created.

SQL> update test_number set last_threshold=9293.9999 where content=’c’;
10
9293.9999
1 row updated.
SQL> rollback;
Rollback complete.

SQL> select *from test_number;

LAST_THRESHOLD CONTENT
————– ——————————
2.0000
9999999.9999 a
9999999.9998 b
10.0000 c

可以看到行级的触发器做了多少的处理。 验证了3条记录。
SQL> update test_number set last_threshold=9999 where content is not null;
9999999.9999
9999
9999999.9998
9999
10
9999

3 rows updated.
SQL> commit;
Commit complete.

SQL> select *from test_number;
LAST_THRESHOLD CONTENT
————– ——————————
2.0000
9999.0000 a
9999.0000 b
9999.0000 c
尝试改成最大值
SQL> update test_number set last_threshold=9999999.9999 where content is null;
2
9999999.9999
1 row updated.
SQL> commit;
Commit complete.

SQL> select *from test_number;
LAST_THRESHOLD CONTENT
————– ——————————
9999999.9999
9999.0000 a
9999.0000 b
9999.0000 c

然后开始正式的测试。
drop trigger maxvalue_test;

CREATE TRIGGER maxvalue_test
before UPDATE of LAST_THRESHOLD
ON test_number for each row
begin
dbms_output.put_line(‘old: ‘||:old.last_threshold);
dbms_output.put_line(‘new: ‘||:new.last_threshold);
if (:new.last_threshold>9999999)
then
:new.last_threshold:=9999999;
dbms_output.put_line(‘change to: ‘||:new.last_threshold);
end if;
end;
/

但是测试的时候发现还是不行。
SQL> update test_number set last_threshold=99999999.9999 where content is null;
update test_number set last_threshold=99999999.9999 where content is null
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column

drop trigger maxvalue_test;

那改成合理范围的值呢。比如改成100.
CREATE TRIGGER maxvalue_test
before UPDATE of LAST_THRESHOLD
ON test_number for each row
begin
dbms_output.put_line(‘old: ‘||:old.last_threshold);
dbms_output.put_line(‘new: ‘||:new.last_threshold);
if (:new.last_threshold<9999999)
then
:new.last_threshold:=100;
dbms_output.put_line(‘change to: ‘||:new.last_threshold);
end if;
end;
/

SQL> update test_number set last_threshold=999999.9 where content is null;
old: 999999.9999
new: 999999.9
change to: 100

1 row updated.

SQL> commit;
Commit complete.

SQL> select *from test_number;
LAST_THRESHOLD CONTENT
————– ——————————
100.0000
9999.0000 a
9999.0000 b
9999.0000 c

可以看到trigger的数据校验一定是在数据类型在合理范围之内。不过反过来一想也是合情合理。

admin

杨建荣,《Oracle DBA工作笔记》《MySQL DBA工作笔记》作者,dbaplus社群发起人之一,腾讯云TVP,现任竞技世界系统部经理,拥有十多年数据库开发和运维经验,目前专注于开源技术、运维自动化和性能调优

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注