2017-08-24 65 views
1

我使用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  | 

EMPLOYEE

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

項目

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

而且我有一個檢查約束來請檢查是否組合表PROJECT_EMPLOYEE(P_ID, E_ID. Month)是獨一無二的。

現在我不希望有人可以將數據插入表PROJECT_EMPLOYEE,如果一個員工在一個月內的產能總和大於表EMPLOYEE的該特定員工的maxCapacity。

例如在上面的示例中:我不應該爲201701員工1和2插入任何行。

是否可以使用檢查約束來解決此問題?

+1

檢查約束處理個別字段值。您必須創建觸發器或存儲過程來檢查總和,並在超出限制時引發錯誤。這樣的觸發雖然會非常昂貴。 –

+1

從商業角度來看,這樣的檢查也是錯誤的。 * data *沒有問題。這是*商業*和*應用程序*必須處理非常真實的,非常常見的情況,即員工的工作比他所認爲的要多。通過拒絕記錄*事實*,您正在做出商業決定。 –

+0

@PanagiotisKanavos你會推薦在客戶端檢查嗎? – flxplzk

回答

1

A 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; 
/
0

有一天,甲骨文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); 

然而,這可能是由於不良的完整刷新執行。我不認爲可以通過聚合實現快速刷新(儘管這種限制將版本更改爲版本)。