Presentation is loading. Please wait.

Presentation is loading. Please wait.

Copyright © Ellis Cohen Enforcing State Constraints

Similar presentations


Presentation on theme: "Copyright © Ellis Cohen Enforcing State Constraints"— Presentation transcript:

1 Copyright © Ellis Cohen 2001-2008 Enforcing State Constraints
Theory, Practice & Methodology of Relational Database Design and Programming Copyright © Ellis Cohen Enforcing State Constraints These slides are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License. For more information on how you may use them, please see

2 Overview of Lecture State Constraint Enforcement Approaches
Using Manifest Views Continuous State Constraint Enforcement Operation-Dependent Post-Enforcement Operation-Dependent Pre-Enforcement Using Summary Tables to Increase Performance Enforcing State Constraints by Correction Enforcing Mandatory Parent Participation © Ellis Cohen

3 State Constraint Enforcement Approaches
© Ellis Cohen

4 State Constraint Enforcement Approaches
Continuous Enforcement Ensure that no change to the database violates the constraint by using rejection or correction (or sometimes, just log or notify DBA) Interval-Based Enforcement At (regular) intervals, check that the system is in a consistent state (based on log or by inspecting state). (Try to) correct violations or notify DBA. Administrative Enforcement DBA checks DB (state or log) every so often, or when notified (by users or code) of a potential problem and corrects violations No Enforcement Constraint documents what the code actually does Hope nothing happens … © Ellis Cohen

5 Continuous vs Interval-Based Approaches
Continuous enforcement can be expensive (especially relative to the cost of the operations that can violate it). Interval-based enforcement can be used when continuous enforcement is too expensive, although if a state constraint is not satisfied until it is discovered, there can be unfortunate consequences © Ellis Cohen

6 Enforcement Approaches
Rejection: Provide code which checks whether the constraint is enforced. If not, raise an exception!  State constraints are almost always enforced by rejection (unless an associated transition constraint is also specified) Correction: Provide code which corrects the database state, so that the constraint becomes enforced. © Ellis Cohen

7 Enforcement Example Suppose we want to enforce the conceptual state constraint: Every department that has a clerk must have a dept manager To implement interval-based (or other non-continuous) enforcement, we need to write an enforcement procedure, that can be called at an arbitrary time. © Ellis Cohen

8 Does enforcement by rejection
CheckDeptMgrClerks PROCEDURE CheckDeptMgrClerks IS BEGIN FOR drec IN ( SELECT deptno FROM Depts d WHERE deptno IN (SELECT deptno FROM Emps WHERE job = 'CLERK') AND deptno NOT IN (SELECT deptno FROM Emps WHERE job = 'DEPTMGR') LOOP RAISE_APPLICATION_ERROR( , 'Dept ' || drec.deptno || ' has clerks, but no dept manager' ); END LOOP; END; Does enforcement by rejection © Ellis Cohen

9 Using Manifest Views © Ellis Cohen

10 Manifest Views Manifest Views simplify enforcing & debugging constraints and debugging data which violate them, due to the following characteristics: Manifest: Just by looking at the contents of the manifest view, it is easy to tell whether the constraint is satisfied. Easy Checking: The constraint can be enforced simply and clearly based on the manifest view. Summarization: The view summarizes the underlying data, keeping as much information as possible. It should not be empty if the assertion is satisfied. Debugging: If the manifest view shows that the constraint is not satisfied, it is possible to obtain useful information about which tuples in the underlying data are responsible for violating the constraint. © Ellis Cohen

11 What's the best manifest view?
Example Constraint Suppose we want to enforce the constraint: Every department that has a clerk must have a department manager What's the best manifest view? © Ellis Cohen

12 Manifest View Definition
Define a view that indicates the # of clerks and the # of managers in each dept DeptMgrClerksView deptno cknt mknt 10 2 1 20 30 3 40 Including depts without employees is optional Why is this a good manifest view? © Ellis Cohen

13 Manifest View Validation
Just by looking at the view contents, it is possible to tell whether the constraint is satisfied. Easy Checking Check each tuple of the view: fails if cknt > 0 and mknt = 0 Summarization Yes, and the view is not empty if the constraint is satisfied Debugging If a tuple in the view fails the check, the problem is with the employees in the corresponding department. © Ellis Cohen

14 Manifest View Definition
CREATE VIEW DeptMgrClerksView AS SELECT deptno, (SELECT count(*) FROM Emps e WHERE d.deptno = e.deptno AND job = 'CLERK') AS cknt, (SELECT count(*) FROM Emps e WHERE d.deptno = e.deptno AND job = 'DEPTMGR') AS mknt FROM Depts d © Ellis Cohen

15 Alternate Manifest View Definition
CREATE VIEW DeptMgrClerksView AS SELECT deptno, count(CASE job WHEN 'CLERK' THEN job ELSE NULL END) AS cknt, count(CASE job WHEN 'DEPTMGR' THEN job ELSE NULL END) AS mknt FROM Emps GROUP BY deptno © Ellis Cohen

16 State Assertion Based on View
EACH DeptMgrClerksView d WHERE d.cknt > 0 SATISFIES d.mknt > 0 © Ellis Cohen

17 CheckDeptMgrClerks w View
PROCEDURE CheckDeptMgrClerks IS BEGIN FOR drec IN ( SELECT deptno FROM DeptMgrClerksView WHERE cknt > 0 AND mknt = 0) LOOP RAISE_APPLICATION_ERROR( , 'Dept ' || drec.deptno || ' has clerks, but no dept manager' ); END LOOP; END; © Ellis Cohen

18 They can also be useful for enforcing transition constraints.
Use Manifest Views Manifest views are strongly recommended with even moderately complex state constraints. They can also be useful for enforcing transition constraints. © Ellis Cohen

19 Continuous State Constraint Enforcement
© Ellis Cohen

20 Interval-Based vs Continuous Approaches
Interval-based enforcement can always be done, although if a state constraint remains violated until it is discovered, there can be unfortunate consequences To prevent these, continuous enforcement may need to be used © Ellis Cohen

21 Continuous State Constraint Enforcement
There are two places to enforce state constraints continuously Application Enforcement: Enforce (operation-dependent) state constraints through code implemented in user actions (in the middle-tier) or stored DB actions (in the data-tier) Database Enforcement: Use built-in database features to automatically enforce state constraints in the data-tier table constraints (check, FK, etc) assertions (not commercially implemented) triggers © Ellis Cohen

22 State & Transition Constraints
State constraints can be thought of as a special kind of transition constraint State constraint: Every dept has at most 1 dept mgr Transition constraint: As a result of any action every dept must have at most 1 dept mgr If we know that any change to the database will leave the state constraint satisfied, then it must ALWAYS be satisfied! © Ellis Cohen

23 State & Transition Assertions
Every dept has at most 1 dept mgr EACH Dept d (SELECT count(*) FROM Emp e WHERE e.deptno = d.deptno AND e.job = 'DEPTMGR') < 2 State assertions correspond to universal transition constraints which only attributes As a result of any action, every dept has at most 1 dept mgr ANY ACTION RESULTS IN EACH Dept& d (SELECT count(*) FROM Emp& e WHERE = AND = 'DEPTMGR') < 2 © Ellis Cohen

24 Application Enforcement of State Constraints
Assuming The employees table can only be changed via user operations To continuously enforce a state constraint, enforce the corresponding transition constraint: Add common code at the end of every action to enforce the constraint, OR better Identify which actions can actually violate the state constraint, and only add the code at the end of those actions (i.e. there's no point in enforcing the constraint in an operation which just changes someone's salary) © Ellis Cohen

25 Which actions could violate this constraint and how?
Enforcement Example Suppose we want to enforce the conceptual state constraint: Every department that has a clerk must have a dept manager Which actions could violate this constraint and how? © Ellis Cohen

26 Relevant Operations Again
Which operations could violate "Every department that has a clerk must have a dept manager" ChangeJob, ChangePosition Turn a peon into a clerk in a dept without a dept manager, or turn a dept manager into a peon in a dept with a clerk ChangePosition Move the dept manager out of a dept which has a clerk DestroyDept, ChangePosition Move a clerk into a dept which doesn’t have a dept mgr AddEmp Add a clerk to a dept w/o a dept mgr TerminateEmp Terminate the dept mgr from a dept which has a clerk © Ellis Cohen

27 Operation-Independent Rejection
TerminateEmp( :empno ) Add a call to an enforcement procedure at the end of every operation which could violate the constraint BEGIN DELETE FROM Emps WHERE empno = :empno; CheckDeptMgrClerks(); EXCEPTION WHEN OTHERS THEN doerr(); END; ChangeJob( :empno, :job ) And also for ChangePosition, DestroyDept & AddEmp BEGIN UPDATE Emps SET job = :job WHERE empno = :empno; CheckDeptMgrClerks(); EXCEPTION WHEN OTHERS THEN doerr(); END; © Ellis Cohen

28 Performance Issues In TerminateEmps, DELETE FROM Emps WHERE empno = :empno is very efficient because of the index on empno With 1M employees, 10 employees per disk block, this can be done with < 10 disk block accesses CheckDeptMgrClerks potentially involves scanning all 1M employees (100K disk blocks), although the performance can be dramatically improved if Emps is indexed on both job and deptno (only the index blocks need to be accessed, not the employees) In any case, the cost of enforcing the state constraint is still far larger than the cost of the DELETE © Ellis Cohen

29 Operation-Independent Enforcement
CheckDeptMgrClerks is operation-independent It can be called from any operation which might violate the constraint It can be called after bulk inserts to the database (e.g. when populating) It can be called by intermittently scheduled code or by the DBA at any time to see if the state constraint is satisfied However, it can be very expensive when used for continuous enforcement, compared to the cost of the operations it is used with (we'll see if we can address this!) © Ellis Cohen

30 Continuous + Interval-Based Approaches
Even if we use a continuous approach (especially if it's application-based), we may still want & need to do interval-based checking We didn't check an action we needed to (due to a mistake, or a change in that action, or because a new action or business rule was added) Errors in the code DBA's might bypass application and update the database directly © Ellis Cohen

31 Operation-Dependent Post-Enforcement
© Ellis Cohen

32 Operation Dependence State constraint enforcement code can be
Operation-Independent Checks whether the constraint holds by examining all data related to the constraint, independent of any data modified by a Dependent operation. Leads to easily reusable code, that can be called at any time, and is best used for interval-based (or other non-continuous) enforcement Operation-Dependent Only checks the data affected by a particular operation to see if it still satisfies the state constraint. Can be significantly more efficient. © Ellis Cohen

33 Operation-Dependent Enforcement
Operation-independent enforcement of state constraints has many advantages Can be used for interval-based and administrative enforcement Only need to write the code once But, operation-independent enforcement is generally too inefficient for continuous enforcement Generally takes orders of magnitude longer to run than the action it must check  Practical continuous enforcement of state constraints generally requires Operation-Dependent enforcement © Ellis Cohen

34 Smart Checking TerminateEmp( :empno )
The only way that TerminateEmp can violate the constraint is by terminating a DEPTMGR! DECLARE empJob Emps.job%TYPE; BEGIN DELETE FROM Emps WHERE empno = :empno RETURNING job INTO empJob; IF empJob = 'DEPTMGR' THEN CheckDeptMgrClerks(); END IF; EXCEPTION WHEN OTHERS THEN doerr(); END; Adding the test provides significant performance savings if we're terminating an employee with a different job © Ellis Cohen

35 Operation-Dependent Analysis
CheckDeptMgrClerks scans through all the employees in all the departments But TerminateEmp only affects a single department – the dept of the employee who was terminated Limiting the scope to a single department reduces the cost of the query. This is especially true if Emps has an index on deptno and Emps is clustered by deptno, or The size of the department is small relative to the # of employees (only need to scan blocks with those employees) Emps is indexed on both jobs and deptno (just use the information in the index) © Ellis Cohen

36 Dept-Dependent Rejection
TerminateEmp( :empno ) DECLARE empJob Emps.job%TYPE; empDeptno Emps.deptno%TYPE; BEGIN DELETE FROM Emps WHERE empno = :empno RETURNING job, deptno INTO empJob, empDeptno; -- only need to check the constraint if the terminated employee is a DEPTMGR IF empJob = 'DEPTMGR' THEN CheckDeptMgrClerksBy( empDeptno ); END IF; EXCEPTION WHEN OTHERS THEN doerr(); END; More efficient than calling CheckDeptMgrClerks() But less safe; base operation code could have modified more data than is being checked © Ellis Cohen

37 Dept-Based Checking Procedure
PROCEDURE CheckDeptMgrClerksBy( aDeptno int ) IS BEGIN FOR drec IN ( SELECT deptno FROM DeptMgrClerksView WHERE cknt > 0 AND mknt = AND deptno = aDeptno ) LOOP RAISE_APPLICATION_ERROR( , 'Dept ' || drec.deptno || ' has clerks, but no dept manager' ); END LOOP; END; Can still use the manifest view! © Ellis Cohen

38 View Expansion SELECT deptno FROM DeptMgrClerksView WHERE cknt > 0 AND mknt = AND deptno = theDeptno CREATE VIEW DeptMgrClerksView AS SELECT deptno, count(CASE job WHEN 'CLERK' THEN job ELSE NULL END) AS cknt, count(CASE job WHEN 'DEPTMGR' THEN job ELSE NULL END) AS mknt FROM Emps GROUP BY deptno With a good query optimizer, this will only involve looking at the employees in dept theDeptno, which can be significantly more efficient if Emps is indexed by deptno Can you write a SELECT statement which correspond to the expanded view? © Ellis Cohen

39 Expanded Code SELECT deptno FROM Emps WHERE deptno = theDeptno GROUP BY deptno HAVING count(CASE job WHEN 'CLERK' THEN job ELSE NULL END) > 0 AND count(CASE job WHEN 'DEPTMGR' THEN job ELSE NULL END) = 0 © Ellis Cohen

40 State Constraint Checking
What else might a procedure (like CheckDeptMgrClerksBy) do that checks state assertions? Send a notification to the DBA (+ correct/reject/neither) Log the violation (+ correct/reject/neither) Note: reject requires use of autonomous transaction for logging Logging allows a separate job that runs at regular times to (try to) correct logged violations (or allows the DBA to look at them) © Ellis Cohen

41 Operation-Dependent Pre-Enforcement
© Ellis Cohen

42 Note: Black-box pre-enforcement with correction is generally awkward
Post-Enforcement Do the modification. Check whether the state constraint is violated, and if so, reject or correct. Pre-Enforcement (Rejection) Check whether the state constraint would be violated if the modification were made. If so, reject. Pre-enforcement by rejection can often be as simple (or even simpler) and provide better performance than post-enforcement. Note: Black-box pre-enforcement with correction is generally awkward © Ellis Cohen

43 What would CheckDeptMgrClerksForAddEmp have to check?
AddEmp Pre-Condition AddEmp( :empno, :ename, :sal, :job, :mgr, :deptno ) BEGIN CheckDeptMgrClerksForAddEmp( :job, :deptno ); ensures that after AddEmp, every dept with a clerk has a dept manager INSERT INTO Emps( empno, ename, sal, job, mgr, deptno ) VALUES( :empno, :ename, :sal, :job, :mgr, :deptno ); EXCEPTION WHEN OTHERS THEN doerr(); END; What would CheckDeptMgrClerksForAddEmp have to check? © Ellis Cohen

44 Pre-Condition Enforcement
PROCEDURE CheckDeptMgrClerksForAddEmp( aJob varchar, aDeptno int ) IS knt int; BEGIN IF aJob != 'CLERK' THEN RETURN; END IF; SELECT count(*) INTO knt FROM Emps WHERE deptno = aDeptno AND job = 'DEPTMGR'; IF knt = 0 THEN RAISE_APPLICATION_ERROR( , 'Cannot add clerk to a dept w no dept mgr' ); END IF; END; © Ellis Cohen

45 Pre-Conditions/Access Constraints vs Pre-Enforcement of State Constraints
Because we are checking the state constraint by pre-enforcement, we might mistakenly just specify it by operation/modification-specific access constraints: A clerk cannot be added to a dept that does not have a dept mgr We could do that, but it is so much better to instead specify the state constraint A dept that has a clerk must have a dept mgr Because Access constraint are only enforced when operations are executed Operation-independent procedures that enforce state constraints can also be used for interval-based and other non-continuous enforcement © Ellis Cohen

46 Using Summary Tables to Increase Performance
© Ellis Cohen

47 Using Summary Tables A summary table
Maintains summary information in a separate table Can be queried efficiently to determine a state constraint has been violated Eliminates the need to use a view or query the underlying table Requires updating the summary table to keep it consistent with data as it is modified. May need to check whether it actually is consistent with the original data © Ellis Cohen

48 DeptMgrClerksSummary
Rather than querying the view DeptMgrClerksView, define a DeptMgrClerksSummary table deptno – a dept number cknt – # of clerks in the dept mknt – # of mgrs in the dept © Ellis Cohen

49 State Constraint Enforcement
PROCEDURE CheckDeptMgrClerks IS BEGIN FOR drec IN ( SELECT deptno FROM DeptMgrClerksSummary WHERE cknt > 0 AND mknt = 0) LOOP RAISE_APPLICATION_ERROR( , 'Dept ' || drec.deptno || ' has clerks, but no dept manager' ); END LOOP; END; Use CheckDeptMgrClerks to determine whether the state constraint is satisfied or not © Ellis Cohen

50 Maintaining the Summary Table
We need procedures that will keep the summary table up-to-date PROCEDURE UpdateNumClerks( aDeptno int, nclerks int ) IS BEGIN UPDATE DeptMgrClerksSummary SET cknt = cknt + nclerks WHERE aDeptno = deptno; END; And similarly for UpdateNumDeptMgrs © Ellis Cohen

51 Updating the Summary Table
The summary table update procedures need to be invoked when the data changes: TerminateEmp( :empno ) What do you think of this approach? DECLARE deldept: int; deljob: Emps.job%TYPE; BEGIN DELETE FROM Emps WHERE empno = :empno RETURNING deptno, job INTO deldept, deljob; CASE deljob WHEN 'CLERK' THEN UpdateNumClerks( deldept, -1 ); WHEN 'DEPTMGR' THEN UpdateNumDeptMgrs( deldept, -1 ); END CASE; CheckDeptMgrClerks(); EXCEPTION WHEN OTHERS THEN doerr(); END; © Ellis Cohen

52 Summary Table Issues Allows efficient checking of state constraints
Adds complexity to code & and is error prone However, triggers can help here; making code simpler and less error prone Need to ensure that summary table remains consistent with underlying table Requires an additional state constraint! But, probably only needs to be checked intermittently © Ellis Cohen

53 Materialized Views A materialized view is an actual persistent table which contains the data to be viewed from underlying tables. Every time the underlying tables are changed, the materialized view must also be changed to keep it consistent (sometimes this is done on a regular schedule instead of on every change) Materialized Views are read only (by default). © Ellis Cohen

54 Use Materialized Views
Can instead use a materialized view CREATE MATERIALIZED VIEW DeptMgrClerksView AS SELECT deptno, count(CASE job WHEN 'CLERK' THEN job ELSE NULL END) AS cknt, count(CASE job WHEN 'DEPTMGR' THEN job ELSE NULL END) AS mknt FROM Emps GROUP BY deptno Automatically maintains summary table Whenever Emps is updated, DeptMgrClerksView is updated as well © Ellis Cohen

55 Materialized View Performance
Materialized views can be expensive By default, every time a change is made to the underlying table, the entire summary table is rebuilt from scratch Materialized Tables can be made more efficient When a modification is made to a table, the database can keep track of the changes made, and may be able to use that to make incremental changes to the summary table (FAST REFRESH) See Oracle Data Warehousing Guide for info on fast refresh of materialized views with aggregates © Ellis Cohen

56 Enforcing State Constraints by Correction
© Ellis Cohen

57 Enforcement by Correction
State constraints (like transition constraints) can be enforced by both rejection and correction. Correction code is generally operation-dependent Every department that has a clerk must have a department manager How might TerminateEmp correct this state constraint by enforcement? © Ellis Cohen

58 Correction Approach When TerminateEmp deletes a DEPTMGR:
Every department that has a clerk must have a dept manager When TerminateEmp deletes a DEPTMGR: promote an employee in the dept to dept mgr move in a dept mgr from another dept move an employee from another dept and promote them to dept mgr delete all clerks move clerks to another dept change the jobs of all the clerks There are many possibilities … © Ellis Cohen

59 State & Transition Constraints
State Constraint e.g. Every department that has a clerk must have a dept manager describes an invariant property, but does not describe how to maintain it – if it is to be enforced, then how We can specify a corresponding Transition Constraint which describes how to enforce a state constraint by correction in specific case e.g. When a department loses its department manager, delete all of its clerks © Ellis Cohen

60 Correct by Deleting Clerks
TerminateEmp( :empno ) DECLARE empJob Emps.job%TYPE; empDeptno Emps.deptno%TYPE; BEGIN DELETE FROM Emps WHERE empno = :empno RETURNING job, deptno INTO empJob, empDeptno; IF empJob = 'DEPTMGR' THEN DELETE FROM Emps WHERE job = 'CLERK' AND deptno = empDeptno; END IF; EXCEPTION WHEN OTHERS THEN doerr(); END; Possibly place in a reusable procedure © Ellis Cohen

61 Use Enforcement Procedure
TerminateEmp( :empno ) Keeps user operation code simple DECLARE empJob Emps.job%TYPE; empDeptno Emps.deptno%TYPE; BEGIN DELETE FROM Emps WHERE empno = :empno RETURNING job, deptno INTO empJob, empDeptno; CorrectDeptMgrClerksOnTerminate( empJob, empDeptno ); EXCEPTION WHEN OTHERS THEN doerr(); END; PROCEDURE CorrectDeptMgrClerksOnTerminate ( aJob varchar, aDeptno int ) IS BEGIN IF aJob = 'DEPTMGR' THEN DELETE FROM Emps WHERE job = 'CLERK' AND deptno = aDeptno; END IF; END; © Ellis Cohen

62 Operation-Independent Correction
It can also be useful to provide an operation-independent correction procedure, which can be called a) from any operation (continuous enforcement) b) interval-based and administrative enforcement This procedure deletes clerks from any dept that has clerks but no manager PROCEDURE CorrectDeptMgrClerks IS BEGIN DELETE FROM Emps WHERE job = 'CLERK' AND deptno IN ( SELECT deptno FROM DeptMgrClerksView WHERE cknt > 0 AND mknt = 0); END; © Ellis Cohen

63 State Constraint Enforcement Approach
To enforce state constraints: 1) Define a corresponding manifest view 2) Define an operation-independent enforcement procedure to enforce the constraint, generally by using the manifest view 3) Each relevant operation calls the enforcement procedure at the end of the operation Those that use rejection, raise an error Those that use correction, make the appropriate correction May also need to collect information at the beginning of the operation, or by RETURNING data from base code operations 4) If more efficiency is needed/desired for some operations, call an operation-dependent enforcement procedure (or just do the correction inline), which generally can use the same manifest view © Ellis Cohen

64 Enforcing Mandatory Parent Participation
© Ellis Cohen

65 Enforce by Rejection Suppose we want to ensure that every department has an employee: PROCEDURE CheckDeptKnts IS BEGIN FOR drec IN ( SELECT deptno FROM DeptKntsView WHERE eknt = 0 ) LOOP RAISE_APPLICATION_ERROR( , 'Dept ' || drec.deptno || ' has no employees' ); END LOOP; END; CREATE VIEW DeptKntsView AS SELECT deptno, count(empno) AS eknt FROM Depts NATURAL LEFT JOIN Emps GROUP BY deptno © Ellis Cohen

66 CreateDept( :deptno, :dname )
Creating a Department Obviously, CreateDept affects this constraint, so let's enforce it there CreateDept( :deptno, :dname ) BEGIN INSERT INTO Depts VALUES ( :deptno, :dname ); CheckDeptKnts(); EXCEPTION WHEN OTHERS doerr(); END; Oops! This will always fail, since we've just created an empty department without employees! © Ellis Cohen

67 CreateDept( :deptno, :dname, :empno )
Provide an Employee CreateDept( :deptno, :dname, :empno ) BEGIN INSERT INTO Depts VALUES ( :deptno, :dname ); UPDATE Emps SET deptno = :deptno WHERE empno = :empno; EXCEPTION WHEN OTHERS THEN doerr(); END; Change CreateDept so that the # of an existing employee is passed as a parameter, and as part of creating the department, that employee is moved into the department! © Ellis Cohen

68 CreateDept( :deptno, :dname )
Enforce by Correction CreateDept( :deptno, :dname ) BEGIN INSERT INTO Depts VALUES ( :deptno, :dname ); -- enforce by correction find an employee to move to the department EnforceDeptKntsFor( :deptno ); EXCEPTION WHEN OTHERS THEN doerr(); END; © Ellis Cohen

69 Enforcement Procedure
PROCEDURE EnforceDeptKntsFor( aDeptno int ) IS pickEmpno int; BEGIN -- find some employee in a dept with > 1 person SELECT min(empno) INTO pickEmpno FROM Emps WHERE deptno IN (SELECT deptno FROM Emps GROUP BY deptno HAVING count(*) > 1); -- move that employee to the new dept UPDATE Emps SET deptno = aDeptno WHERE empno = pickEmpno; END; © Ellis Cohen


Download ppt "Copyright © Ellis Cohen Enforcing State Constraints"

Similar presentations


Ads by Google