触发/约束以限制插入或更新

时间:2014-02-06 14:24:56

标签: sql oracle plsql triggers

我有一张类似

的表格
MyTable (
Student ID, 
Exam)

我想放置一个触发器/约束来描述:

学生ID可以多次出现,而不必是唯一的。但是,该对(学生ID,“法语”)只能出现一次。因此每个学生只能有一个“法国”条目。法语是硬编码的

ID   Exam

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

注意将“德语”字段更新为法语也应该失败

到目前为止,我已经尝试了

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;

但是这会抛出一个Mutate错误。无论如何,这与诚信有关,所以我确定一个约束会更好,但是会对如何实现这一点提出一些建议。

4 个答案:

答案 0 :(得分:3)

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

我想也许用索引最好解决这个问题?类似于:Oracle SQL Constraint where clause

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

答案 1 :(得分: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;

语句触发器的优点是它们不像行触发器那样受“变异表”问题的影响。但是,这有点像kluge,引入了全表扫描,如果表很大可能是性能问题,但至少它是一个解决方案。

分享并享受。

答案 2 :(得分:0)

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

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

您只能将带有Exam ='French'的记录添加到PL / SQL表中,并检查该学生是否已对该数据库进行法语考试。

答案 3 :(得分:0)

这个怎么样?

alter table MyTable add constraint std_exam unique(Student ID,Exam);