检查Oracle对与其他表值的比较的约束

时间:2017-08-24 07:47:41

标签: sql oracle

我正在使用ORACLE 11.2 DB并有3个表:

PROJECT_EMPLOYEE

 |ID (PK) | P_ID |E_ID  |Month   |Capacity|
 |--------|------|------|--------|--------|
 |1       |1     |1     |201701  |0.4     |
 |1       |1     |2     |201701  |0.6     |
 |1       |2     |1     |201701  |0.4     |

员工

 |ID (PK)   | maxCapacity   |
 |----------|---------------|
 |1         | 0.8           |
 |2         | 0.6           |

PROJECT

|ID (PK)   |other columns| 
|----------|-------------|
|1         |some data    | 
|2         |some data    | 

此外,我有一个Check Constraint来检查表(P_ID, E_ID. Month)的组合PROJECT_EMPLOYEE是否唯一。

现在我不希望有人可以将数据插入到表PROJECT_EMPLOYEE中,如果一个月内员工的容量总和大于表EMPLOYEE的特定员工的maxCapacity。

e.g。在上面的例子中:我不能为员工1和2输入201701的任何行。

用检查约束解决这个问题是否可行?

2 个答案:

答案 0 :(得分:1)

CHECK约束只能检查同一行中的值 - 它无法执行聚合 - 因此您无法提出要求。

相反,您应该创建一个过程来处理业务逻辑并撤消对表执行直接插入/更新的权限,以确保使用这些过程:

CREATE PACKAGE PROJECTS_PKG
IS
  PROCEDURE add_Project_Employee(
    project_id  IN  PROJECT_EMPLOYEE.P_ID%TYPE,
    employee_id IN  PROJECT_EMPLOYEE.E_ID%TYPE,
    month       IN  PROJECT_EMPLOYEE.Month%TYPE,
    capacity    IN  PROJECT_EMPLOYEE.Capacity%TYPE,
    status      OUT VARCHAR2
  );
END;
/

CREATE PACKAGE BODY PROJECTS_PKG
IS
  PROCEDURE add_Project_Employee(
    i_project_id  IN  PROJECT_EMPLOYEE.P_ID%TYPE,
    i_employee_id IN  PROJECT_EMPLOYEE.E_ID%TYPE,
    i_month       IN  PROJECT_EMPLOYEE.Month%TYPE,
    i_capacity    IN  PROJECT_EMPLOYEE.Capacity%TYPE,
    o_error       OUT VARCHAR2
  )
  IS
    v_current_capacity PROJECT_EMPLOYEE.Capacity%TYPE;
    v_max_capacity EMPLOYEE.maxCapacity%TYPE;
  BEGIN
    SELECT SUM( capacity )
    INTO   v_current_capacity
    FROM   project_employee
    WHERE  e_id  = i_employee_id
    AND    month = i_month;

    SELECT maxCapacity
    INTO   v_max_capacity
    FROM   employees
    WHERE  e_id = i_employee_id;

    IF v_current_capacity + i_capacity > v_max_capacity THEN
      o_error := 'Max capacity exceeded';
      RETURN;
    END IF;

    INSERT INTO PROJECT_EMPLOYEES(
      ID,
      P_ID,
      E_ID,
      Month,
      Capacity,
    ) VALUES (
      PROJECT_EMPLOYEES_SEQ.NEXTVAL,
      i_project_id,
      i_employee_id,
      i_month,
      i_capacity
    );

    o_error := NULL;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      NULL; -- Handle errors
  END;
END;
/

答案 1 :(得分:0)

有一天,Oracle may support SQL assertions可以做到这一点。

现在it can be done using a materialized view and a constraint就像这样:

create materialized view mv1
build immediate
refresh complete on commit as
select e.maxCapacity, pe.e_id, pe.month, sum(pe.capacity) sumc
  from project_employee pe
       join employee e on e.id = pe.e_id
 group by e.maxCapacity, pe.e_id, pe.month;

alter table mv1
add constraint mv1_chk check (sumc <= maxcapacity);

然而,由于完全刷新,这可能表现不佳。我不认为可以通过聚合快速刷新来完成(尽管这些限制会将版本更改为版本)。