关于trigger过滤最大值的问题

今天碰到一个问题,开发有一个比较紧的需要,想问问我数据库这边能不能帮上忙。
如果开发那边来做,需要改代码,如果数据库这边能临时支持,代码就可以多做些测试,然后再打补丁了。
需求的情况大体是这样:有一个表的字段是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的数据校验一定是在数据类型在合理范围之内。不过反过来一想也是合情合理。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/23718752/viewspace-1149566/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/23718752/viewspace-1149566/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值