Oracle SQL Developer - 在外键上添加约束

时间:2014-04-21 17:11:15

标签: sql database oracle constraints

我是Oracle SQL的新手,我很难添加约束。我正在尝试在我的桌子上添加约束来强制执行特定的业务规则,这些规则只允许学生每班只上4门课程和最多25名学生。

请告诉我您需要哪些其他信息以帮助回答此问题。我不知所措......

CREATE TABLE GRADES
(STU_ID       int NOT NULL ENABLE,
 CRSE_ID        CHAR(9) NOT NULL ENABLE,
 STU_CRSE_GRADE VARCHAR2(20) 
 check(STU_CRSE_GRADE='A' or 
       STU_CRSE_GRADE='B' or 
       STU_CRSE_GRADE='C' or 
       STU_CRSE_GRADE ='D' or 
       STU_CRSE_GRADE= 'F'),
 CONSTRAINT GRADES_PK PRIMARY KEY (STU_ID, CRSE_ID),
 constraint fk_Grades Foreign key(Stu_ID)
   REFERENCES Students,
 constraint fk_Grades_Crse_ID foreign key(Crse_ID)
   REFERENCES Courses
);

没问题!见下表:

CREATE TABLE Students
(Stu_ID int Constraint pk_Stu_ID Primary Key,
Stu_name VARCHAR(255) NOT NULL, Stu_Add varchar(255),
Stu_Maj CHAR(6)
);

CREATE TABLE Instructors
(Instr_ID char(3) Constraint pk_Instr_ID Primary Key,
Instr_Name VARCHAR(255) NOT NULL, Instr_Office varchar(8)
);

CREATE TABLE Courses
(Crse_ID char(9) Constraint pk_Crse_ID Primary Key,
Crse_Title VARCHAR(255) NOT NULL,
Student’s name: Lai Xia
Instr_ID CHAR(3) not null,
constraint fk_Courses_Instr_ID Foreign key(Instr_ID) REFERENCES Instructors
);

2 个答案:

答案 0 :(得分:2)

外键单独只能表示一对多的关系。如果你想限制"很多"部分到特定数字,您需要:

  1. 在应用程序代码或触发器中执行此操作。
  2. 或者将数据库的其余部分重新设计为" help" FK实现这一目标。

  3. (1)易于实施但容易出错:您必须小心使用锁定以避免并发环境中的竞争条件:

    • 假设两个并发交易试图将同一个学生连接到不同的课程。
    • 第一笔交易计算当前与学生相关的课程,并发现其中有3个。一切都很好。
    • 第二个交易也是如此,也只看到3个课程(因为第一个交易尚未提交)。
    • 因此,这两笔交易都认为他们不会超过允许的数量而且 很乐意继续插入他们的学生课程连接。
    • 最终结果:学生连接5门课程,违反了只能连接4门的规则。

    为避免这种情况,您可能需要序列化这些操作,可能是将学生锁定SELECT ... FOR UPDATE


    可以通过更改密钥设计,然后限制密钥可以具有的值来实现(2)。例如,强制学生最多可以完成4门课程,可以这样做:

    CREATE TABLE STUDENT (
        STUDENT_ID INT PRIMARY KEY
    );
    
    CREATE TABLE COURSE (
        COURSE_ID INT PRIMARY KEY
    );
    
    CREATE TABLE STUDENT_COURSE (
        STUDENT_ID INT REFERENCES STUDENT,
        COURSE_ID INT REFERENCES COURSE,
        COURSE_NO INT NOT NULL CHECK (COURSE_NO IN (1, 2, 3, 4)),
        PRIMARY KEY (STUDENT_ID, COURSE_ID),
        UNIQUE (STUDENT_ID, COURSE_NO)
    );
    

    CHECK和UNIQUE约束的组合意味着DBMS本身将拒绝将同一个学生连接到4个以上的课程。

    这样做会成功:

    INSERT INTO STUDENT_COURSE VALUES (11, 111, 1);
    INSERT INTO STUDENT_COURSE VALUES (11, 222, 2);
    INSERT INTO STUDENT_COURSE VALUES (11, 333, 3);
    INSERT INTO STUDENT_COURSE VALUES (11, 444, 4);
    

    但这样做显然不会(CHECK约束违规):

    INSERT INTO STUDENT_COURSE VALUES (11, 555, 5);
    
    顺便说一句,当学生已经连接到某些课程而你想找到剩余的免费插槽时,你可以这样做:

    SELECT NEW_NO
    FROM (
        SELECT
            COURSE_NO + 1 NEW_NO,
            LEAD (COURSE_NO) OVER (ORDER BY COURSE_NO) NEXT_NO
        FROM STUDENT_COURSE
        WHERE STUDENT_ID = 11
    )
    WHERE NEW_NO <> NEXT_NO OR NEXT_NO IS NULL;
    

    [SQL Fiddle]

答案 1 :(得分:0)

看起来你已经了解了oracle中的基本约束(比如check和foreign key)。对于更复杂的风格,您可以使用触发器。 触发器在一组事件上执行(当您尝试在表中插入,更新或删除记录时)。

我认为学生只需要4门课程,这意味着每个学生在成绩表中只能有4个记录。在触发器中你可以做到这一点。 因此,您在插入或更新之前(也有之后)创建一个触发器,在触发器中,您可以检查插入行的学生已有多少记录,并接受或拒绝特定的插入/更新操作。

你可以在课程中为25名学生编写类似的触发器。它将是grates表中相同插入/更新的另一个触发器。

对于确切的语法,首先尝试documnentation,触发很有趣:)

此外,稍后您可以考虑将存储过程编写为在数据库中实现业务逻辑的更高级方法。祝你好运!