我正在使用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的任何行。
用检查约束解决这个问题是否可行?
答案 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);
然而,由于完全刷新,这可能表现不佳。我不认为可以通过聚合快速刷新来完成(尽管这些限制会将版本更改为版本)。