在oracle中将另一个表中的字段用作具有类型CONSTRAINT的最大行数

在oracle中将另一个表中的字段用作具有类型CONSTRAINT的最大行数,oracle,Oracle,我有两张桌子: CREATE TABLE users ( user_id INT(7) NOT NULL, restricted_type VARCHAR(64) NOT NULL ) 我想在insert上检查一下,使用restricted\u type=type\u restriction.name的限制用户不超过个 此时,我正在使用此查询插入数据: INSERT INTO users (user_id, restricted_type) SELECT <

我有两张桌子:

CREATE TABLE users (
   user_id          INT(7) NOT NULL,
   restricted_type  VARCHAR(64) NOT NULL
)
我想在insert上检查一下,使用restricted\u type=type\u 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>)
       )
但是,如果有两个或多个并行查询,那么最终可能会有更多用户使用受限类型而不是此类型的实际限制

有没有办法让这种约束起作用?另外,我总是在每个查询中只插入一行,如果有帮助的话,您不能使用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语句中,我将users表中的数据分组到集合中。在每行之后,我在集合中为新插入的行增加适当的值。在after语句中,我检查集合中的数据是否超出表类型限制中允许的范围


当两个会话插入concurent数据时,这将导致异常。

您可以尝试将该逻辑放入触发器中,如果一行违反该规则,则会引发错误。我已尝试将逻辑完全放入插入触发器之前不存在的位置,但问题仍然存在。。对于两个或多个并行事务,我有时会违反限制,但触发器对此保持沉默。我会再试一次,以防万一。
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;