3

我正在尝试定义三个数据库表 - USERNAME、USER_SESSIONS 和 TOOLBOX_DIRS_REGISTERED。我可以毫无问题地定义前两个,但最后一个让我有点悲伤。理想情况下,我想如下面的代码块所示定义它,但是我相信子查询不能在检查约束中使用?

下面的代码块显示了我想如何定义表 TOOLBOX_DIRS_REGISTERED。代码块的开头还包含一些注释,试图解释我对表定义使用的某些约束的想法。

-- Constraint : USERNAME_FK
-- ========================
--
-- USERNAME must contain a username which has been added to the table USERNAME.
--
-- Constraint : USER_SESSION_ID_FK
-- ===============================
--
-- USER_SESSION_ID must contain a user session ID which has been added to the table 
-- USER_SESSION.
--
-- Constraint : check_user_session_id
-- ==================================
--
-- In addition to the above constraint, USER_SESSION_ID must also belong to the 
-- username which is contained within USERNAME.

create table
TOOLBOX_DIRS_REGISTERED
(
 DIRNAME         varchar2(100) not null,
 USERNAME        varchar2(32)  not null,
 USER_SESSION_ID varchar2(32)  not null,
 AUTO_REGISTER   char          not null,
 constraint
   TOOLBOX_DIRS_REGISTERED_PK
   primary key (DIRNAME),
 constraint
   USERNAME_FK
   foreign key (USERNAME)
   references USERS(USERNAME),
 constraint
   USER_SESSION_ID_FK
   foreign key (USER_SESSION_ID)
   references USER_SESSIONS(USER_SESSION_ID),
 constraint
   check_user_session_id
   check
   (
    USERNAME in
    (
     select USERNAME from USER_SESSIONS
     where USER_SESSIONS(USER_SESSION_ID) = USER_SESSION_ID
    )
   )
);

有谁知道解决这个问题的方法,即在检查约束“check_user_session_id”的定义中使用子查询?我在 Stackoverflow 上读到,在这种特殊情况下,可以使用物化视图代替子查询。问题是,如果我使用物化视图,那么我想确保它在执行检查约束时是最新的。所以我所做的是实现物化视图以及在物化视图上调用 dbms_mview.refresh 的触发器。这一切都很好,除了 Oracle 抱怨它不能在触发器中提交。啊!它给我的确切信息是;

ERROR at line 2:
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2760
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2740
ORA-06512: at "SYSTEM.SIMULAB_MVIEW", line 19
ORA-06512: at "SYSTEM.TRIG_TOOLBOX_DIRS_REGISTERED", line 3
ORA-04088: error during execution of trigger 'SYSTEM.TRIG_TOOLBOX_DIRS_REGISTERED'

我假设 Oracle 在刷新物化视图后尝试自动执行提交,这就是它所抱怨的?

我的触发器定义如下;

create or replace trigger TRIG_TOOLBOX_DIRS_REGISTERED
  before insert or update on
    TOOLBOX_DIRS_REGISTERED
  begin

    -- Invoke the PL/SQL Package procedure simulab_mview.refresh_mview

    simulab_mview.refresh_mview;

  end;

而 PL/SQL 包 simulab_mview 定义如下;

create or replace
package
simulab_mview
as

    procedure
    refresh_mview;

end;
/

create or replace package body
simulab_mview
as

    procedure
    refresh_mview
    as

    begin

        -- I have a strong suspicion that dbms_mview.refresh might cause a commit to 
        -- be executed. This would make sense, as the RDBMS would need to execute a 
        -- commit so that other clients could see the result of the refresh.

        dbms_mview.refresh('mat_view', 'C');

    end;

end;
/

有人对此有任何想法吗?有没有更简单的方法来做我想做的事,我不应该使用物化视图,不应该使用触发器吗?

对此的任何帮助甚至想法都将不胜感激。如果有人确实能够就此事提供任何帮助或想法,那么我要提前感谢他们的帮助。

祝你今天过得愉快。

4

2 回答 2

2

根据关于 CHECK 约束的 Oracle 11.2 文档

检查约束的限制

检查约束受以下限制:

• 检查约束条件不能包含以下结构:

  ◦Subqueries and scalar subquery expressions

如果您想同时验证 TOOLBOX_DIRS_REGISTERED 和 USER_SESSIONS 之间的 USER_SESSION_ID 和 USERNAME,我建议您在 USER_SESSIONS(USER_SESSION_ID, USERNAME) 上创建一个唯一键,然后在 TOOLBOX_DIRS_REGISTERED(USER_SESSION_ID, USERNAME) 上创建一个外键到 USER_SESSIONS(USER_SESSION_ID, USERNAME) .

分享和享受。

于 2012-08-06T12:14:20.080 回答
1

如果我正确理解这一点,我认为您不想toolbox_dirs_registered同时引用表格usersuser_sessions表格。那不是标准化的。仅参考该user_sessions表,并且您已经参考了该users表。

以下片段未经测试,有很多剪切和粘贴,但我认为它给出了这个想法:

CREATE TABLE users(
   user_id  NUMBER
  ,username VARCHAR2(32)
  ,CONSTRAINT users_pk PRIMARY KEY(user_id)
);

CREATE UNIQUE INDEX users_username_uk ON users(username);


CREATE TABLE user_sessions(
   user_session_id NUMBER
  ,user_id         NUMBER
  ,session_id      NUMBER
  ,CONSTRAINT user_sessions_pk PRIMARY KEY(user_session_id)
  ,CONSTRAINT user_session_user_id_fk FOREIGN KEY(user_id) REFERENCES users(user_id)
);

CREATE UNIQUE INDEX user_sessions_user_session_uk ON user_sessions(user_id, session_id);


CREATE TABLE toolbox_dirs_registered(
   dirname         VARCHAR2(100) NOT NULL
  ,user_session_id NUMBER(32)
  ,auto_register   CHAR(1)
  ,CONSTRAINT toolbox_dirs_registered_pk PRIMARY KEY(dirname)
  ,CONSTRAINT tdr_user_session_id_fk FOREIGN KEY(user_session_id) REFERENCES user_sessions(user_session_id)
);
于 2012-08-06T02:09:00.070 回答