2014-02-06 26 views
0

我有一个表,它看起来像触发/约束限制插入或更新

MyTable (
Student ID, 
Exam) 

我想将触发/约束描述:

学生证可以出现很多次,不必须是独一无二的。但是,这对(学生证,“法国”)只能出现一次。所以每个学生只能有一个“法国”条目。法国是硬编码

 
ID Exam 

0001 German 
0001 History 
0001 French 
0001 French <-- This insert should fail. 

Attemting更新“德国”字段法国人也应该会失败

到目前为止,我已经试过

CREATE OR REPLACE TRIGGER MyTrigger BEFORE INSERT OR UPDATE ON MyTable 
FOR EACH ROW 
DECLARE 
    rowsCount INTEGER; 
BEGIN 
    select count(*) 
    INTO rowsCount 
    from MyTable sc 
    where SC.SC_TYPE = 'FRENCH' and :new.StudentID = sc.StudentID; 
IF rowsCount > 1  
THEN 
    raise_application_error('-20098','You cannot have more than one French record per student.'); 
END IF; 
end; 

这虽然抛出一个变异的错误。无论如何,这与完整性有关,所以我相信一个限制会更好,但是会对如何实现这一点提供一些建议。

+0

那么对'French'的限制是特定的,他们应该被允许与'German'有多行? –

回答

3

是的,法国人每个学生只能出现一次,但其他一切都可以出现多次。

我在想也许这是最好的解决索引?类似:Oracle SQL Constraint where clause

CREATE UNIQUE INDEX MyIndex ON MyTable(
    CASE WHEN Exam= 'French' 
     THEN StudentID 
     ELSE NULL 
    END 
); 
+0

这也行不通。如果任何学生多次进行相同的考试,则第二次插入将失败。即使您将索引更改为'(StudentID,CASE WHEN EXAM ='French'THEN StudentID ELSE NULL END)',它仍然会在第二次针对给定学生插入非“法语”语言时失败,至少在Oracle 11.1。 [SQLFiddle here](http://sqlfiddle.com/#!4/f8cdd9/1) –

+1

只有索引定义中的case语句应该没问题。如果你从sqlfiddle中的索引中删除student_id列,那么一切都很好。 –

1

由于限制的特殊性质的(只有法国限制)我不觉得做这个可以用约束来实现(虽然我很乐意去学习其他)。你可以解决它的方法之一是使用语句触发器:

CREATE OR REPLACE TRIGGER NO_DUPLICATE_FRENCH_TRIGGER 
    BEFORE INSERT OR UPDATE 
    ON MY_TABLE 
    -- NOTE: NO 'FOR EACH ROW', which means this is fired once for each 
    -- statement executed, rather than once for each row modified. 
DECLARE 
    nMax_count NUMBER; 
BEGIN 
    SELECT MAX(COUNT_VAL) 
    INTO nMax_count 
    FROM (SELECT STUDENTID, COUNT(*) AS COUNT_VAL 
      FROM MY_TABLE 
      WHERE EXAM = 'FRENCH' 
      GROUP BY STUDENTID); 

    IF nMax_count > 1 THEN 
    RAISE SOME_EXCEPTION; 
    END IF; 
END NO_DUPLICATE_FRENCH_TRIGGER; 

声明触发器的优点在于,他们不受制于“变异表”问题,因为是行触发器。然而,这是一个大问题,引入了全表扫描,如果表很大可能是性能问题,但至少它是一个解决方案。

分享和享受。

0

我建议你创建3个触发器和一个包来处理这个验证。

  • 1包含一个PL/SQL表和将由您的触发器调用的过程。
  • 1语句触发前清除PL/SQL表。
  • 1在每行触发器之前(或之后)触发器将要插入/更新的记录添加到PL/SQL表中。
  • 1语句触发后,根据您填充的PL/SQL表执行验证。

您可以添加到PL/SQL表中只有考试='法国'的记录,并检查学生是否已经对数据库进行了法语考试。

0

这个怎么样?

alter table MyTable添加约束条件std_exam unique(Student ID,Exam);