我正在使用oracle数据库开展一个小型学校项目。我创建了一些表,其中两个是Mobile(Mobile_Number,Status_Flag)Status_Flag显示一个号码是否有效,还有另一个表Owner_Mobile(Owner_Id FK,Mobile_ID FK)。现在我应该编写一个Constraint,如果对应的Status_Flag为指定数字的N,则禁止插入操作。我尝试使用子查询来创建它,但这是不可能的。
当然,约束应该应用于OWNER_MOBILE表。例如,如果我说:INSERT INTO OWNER_MOBILE(25541,042536),则约束应检查Mobile表并查看Mobile 042536是否处于活动状态。如果该数字未激活,则insert语句应生成错误
答案 0 :(得分:0)
您可以使用触发器或其他PL / SQL API,但您应该考虑ACID事务原则。让我们考虑一下当flag value = 0时应该阻止插入的情况:
SQL> create table mobile (mobile_id int primary key, flag int)
2 /
SQL> create table owner_mobile(owner_id int,
2 mobile_id int references mobile(mobile_id))
3 /
SQL> insert into mobile values (1,1)
2 /
SQL> commit
2 /
SQL> create or replace trigger
2 tr_owner_mobile
3 before insert on owner_mobile
4 for each row
5 declare
6 l_flag mobile.flag%type;
7 begin
8 select flag into l_flag
9 from mobile where mobile_id = :new.mobile_id;
10
11 if l_flag = 0 then
12 raise_application_error(-20000, 'Unavalable mobile');
13 end if;
14 end;
15 /
在上面的代码中,我只选择flag并依赖于检索到的值 - 我不关心ACID。
在第一个事务中,我更新标志值但不提交:
SQL> update mobile set flag = 0 where mobile_id = 1;
在第二个交易中,我插入owner_mobile并获得成功:
SQL> insert into owner_mobile values(1,1);
1 row inserted.
接下来,我提交第一个交易,然后提交第二个交易。那我得到了什么:
SQL> select * from mobile;
MOBILE_ID FLAG
---------- ----------
1 0
SQL> select * from owner_mobile;
OWNER_ID MOBILE_ID
---------- ----------
1 1
似乎这不是我的期望。
我可以使用select for update来防止行为不一致:
SQL> update mobile set flag = 1;
1 row updated.
SQL> delete from owner_mobile;
1 row deleted.
SQL> commit;
SQL> create or replace trigger
2 tr_owner_mobile
3 before insert on owner_mobile
4 for each row
5 declare
6 l_flag mobile.flag%type;
7 begin
8 select flag into l_flag
9 from mobile where mobile_id = :new.mobile_id
10 for update;
11
12 if l_flag = 0 then
13 raise_application_error(-20000, 'Unavalable mobile');
14 end if;
15 end;
16 /
现在也这样做:
SQL> update mobile set flag = 0 where mobile_id = 1;
1 row updated.
第二个事务正在等待,因为父行已被锁定:
SQL> insert into owner_mobile values(1,1);
在第一次交易中提交后,我进入第二次交易:
SQL> insert into owner_mobile values(1,1);
insert into owner_mobile values(1,1)
*
error in line 1:
ORA-20000: Unavalable mobile
ORA-06512: at "SCOTT.TR_OWNER_MOBILE", line 9
ORA-04088: error in trigger 'SCOTT.TR_OWNER_MOBILE'
因此,无论您如何实现要求,都必须考虑事务隔离。