我有两个表:
CREATE TABLE users (
user_id INT(7) NOT NULL,
restricted_type VARCHAR(64) NOT NULL
)
CREATE TABLE type_restrictions (
name VARCHAR(64) NOT NULL,
restriction INT NOT NULL
)
我要检查插入情况,使用restriction
的用户不超过restricted_type = type_restriction.name
。
此时,我正在使用此查询插入数据:
INSERT INTO users (user_id, restricted_type) SELECT <id>, <type> FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM type_restrictions T
WHERE T.name = <type> AND T.restriction < (
SELECT COUNT(*)
FROM users U
WHERE U.user_id = <id> AND U.restricted_type = <type>)
)
但是通过两个或多个并行查询,使用restricted_type
的用户可能会比使用该类型的实际限制更多。
有什么办法可以使这种约束起作用? (此外,如果有帮助,我每次查询总是只插入一行)
答案 0 :(得分:1)
您不能在约束中使用select ...
。您无法从普通触发器中插入的表中进行选择。你可以做什么?物化视图(可能不确定,我不确定)或复合触发器。这是我的(工作中的)尝试:
create or replace trigger trg_users_restrict
for insert on users compound trigger
type tt is table of number index by varchar2(5);
vt tt;
i varchar2(5);
v_max int;
before statement is
begin
for r in (select restricted_type, count(1) cnt from users group by restricted_type)
loop
vt(r.restricted_type) := r.cnt;
end loop;
end before statement;
after each row is
begin
begin
vt(:new.restricted_type) := vt(:new.restricted_type) + 1;
exception when no_data_found then
vt(:new.restricted_type) := 1;
end;
end after each row;
after statement is
begin
i := vt.first;
while i is not null loop
select nvl(max(restriction), 0) into v_max
from type_restrictions where name = i;
if vt(i) > v_max then
raise_application_error( -20001,
'maximum number exceeded for restriction type ' || i );
end if;
i := vt.next(i);
end loop;
end after statement;
end trg_users_restrict;
在before statement
中,我将users
表中的数据分组为集合。在after each row
中,我为新插入的行在collection中增加了适当的值。在after statement
中,我检查集合中的数据是否超出表type_restrictions
中的允许范围。
当两个会话插入并发数据时,最后提交的数据会导致异常。