{"id":968,"date":"2005-07-22T12:00:00","date_gmt":"2005-07-22T12:00:00","guid":{"rendered":"http:\/\/orcldoug.com\/blog\/?p=968"},"modified":"2005-07-22T12:00:00","modified_gmt":"2005-07-22T12:00:00","slug":"deferred-constraint-checking","status":"publish","type":"post","link":"http:\/\/orcldoug.com\/blog\/2005\/07\/22\/deferred-constraint-checking\/","title":{"rendered":"Deferred Constraint Checking"},"content":{"rendered":"<p>In my previous blog entry I highlighted a few of the reasons that integrity constraint checking should not be deferred, stated by Date in his recent book (and by him and others in other papers). At the time and while looking at an entry over on <a href=\"http:\/\/marist89.blogspot.com\/2005_06_01_marist89_archive.html\">Jeff Hunter&#8217;s Blog<\/a> I felt that functions might be a particular problem. My mind also went back to a chat with Carl Dudley and others after a Scottish SIG meeting when Carl had mumbled something about functions that had stuck somewhere in the back of my mind.<\/p>\n<p>So I thought I\ufffdd put together a simple example based on EMP and DEPT to illustrate some of the problems you could run into with deferred constraint checking. Here\ufffds the data (unmodified from a standard SCOTT installation on 10.1.0.4)<\/p>\n<pre>SQL&gt; SELECT empno, deptno, ename, sal <br\/>2 FROM emp <br\/>3 ORDER BY deptno, empno; <br\/><p><\/p><br\/>EMPNO      DEPTNO     ENAME      SAL<br\/>---------- ---------- ---------- ---------- <br\/>7782               10 CLARK            2450 <br\/>7839               10 KING             5000<br\/>7934               10 MILLER           1300<br\/>7369               20 SMITH             800<br\/>7566               20 JONES            2975<br\/>7788               20 SCOTT            3000<br\/>7876               20 ADAMS            1100 <br\/>7902               20 FORD             3000 <br\/>7499               30 ALLEN            1600 <br\/>7521               30 WARD             1250 <br\/>7654               30 MARTIN           1250 <br\/>7698               30 BLAKE            2850 <br\/>7844               30 TURNER           1500 <br\/>7900               30 JAMES             950<br\/><p><\/p><br\/>14 rows selected<br\/><p><\/p><br\/>SQL&gt; SELECT deptno, dname <br\/>2 from dept; <br\/><p><\/p><br\/><br\/><p><\/p><br\/>DEPTNO     DNAME<br\/>---------- -------------- <br\/>10         ACCOUNTING <br\/>20         RESEARCH <br\/>30         SALES <br\/>40         OPERATIONS<\/pre>\n<p>So next I\ufffdll create a simple function to test. The function just calculates the average salary for employees in the department specified by the p_dname parameter<\/p>\n<pre>SQL&gt; CREATE OR REPLACE FUNCTION func_avg_salary (p_dname dept.dname%TYPE) <br\/>2 RETURN NUMBER <br\/>3 IS <br\/>4 n_avg_salary NUMBER; <br\/>5 BEGIN <br\/>6 SELECT AVG(emp.sal) INTO n_avg_salary <br\/>7 FROM emp, dept <br\/>8 WHERE emp.DEPTNO = dept.DEPTNO <br\/>9 AND dept.dname = p_dname; <br\/>10 <br\/>11 RETURN n_avg_salary; <br\/>12 END; <br\/>13 \/<br\/><p><\/p><br\/><br\/>Function created.<\/pre>\n<p>Note that anything this function does during this test could easily be more efficiently replaced by single SQL statements (avoiding PL\/SQL altogether) but I mean to illustrate the problem at a simple level. I hope you can use your imagination to dream up much more worrying examples, involving more complex functions against a more complex model. It\ufffds also worth thinking about whether a function might communicate outside of this transaction, for example by sending results out to file or via an email?<\/p>\n<p>Now I want to make sure that I have a deferred constraint to work with<\/p>\n<pre>SQL&gt; column table_name format a16<br\/>SQL&gt; column constraint_name format a16<br\/>SQL&gt; column column_name format a16<br\/>SQL&gt; SELECT c.table_name, c.constraint_name, c.constraint_type, <br\/>2 col.column_name, col.position <br\/>3 FROM user_constraints c, user_cons_columns col <br\/>4 WHERE c.constraint_name = col.constraint_name<br\/><p><\/p><br\/>SQL&gt; \/<br\/>TABLE_NAME       CONSTRAINT_NAME  C COLUMN_NAME      POSITION<br\/>---------------- ---------------- - ---------------- ----------<br\/>DEPT             PK_DEPT          P DEPTNO                    1<br\/>EMP              PK_EMP           P EMPNO                     1<br\/>EMP              FK_DEPTNO        R DEPTNO                    1<br\/><p><\/p><br\/>SQL&gt; ALTER TABLE emp DROP CONSTRAINT fk_deptno;<br\/><p><\/p><br\/>Table altered.<br\/><p><\/p><br\/>SQL&gt; ALTER TABLE emp ADD CONSTRAINT fk_deptno FOREIGN KEY (deptno) REFERENCES dept <br\/>2 INITIALLY IMMEDIATE DEFERRABLE;<br\/><p><\/p><br\/>Table altered.<\/pre>\n<p>Now that I have the deferrable foreign key constraint, I\ufffdm going to defer the checking until the end of the transaction.<\/p>\n<pre>SQL&gt; SET CONSTRAINT FK_DEPTNO DEFERRED;<br\/><p><\/p><br\/>Constraint set.<\/pre>\n<p>That will let me insert some employees who work for the non-existent department 90.<\/p>\n<pre>SQL&gt; insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) <br\/>2 values (8000, 'BURNS', 'DBA', 7902, SYSDATE, 9000, 0, 90);<br\/><p><\/p><br\/>1 row created.<br\/><p><\/p><br\/>SQL&gt; insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) <br\/>2 values (8001, 'JONES', 'DBA', 7902, SYSDATE, 5000, 0, 90);<br\/><p><\/p><br\/>1 row created.<\/pre>\n<p>So now I *know* that I have inconsistent data. Or do I? (as <a href=\"http:\/\/www.palmersguide.com\/jamesburke\/burke_biography.html\">James Burke<\/a> may have said). In this case I do because I\ufffdm working with a very small number of statements; I checked which departments existed before I ran them; and I\ufffdve just deferred the checking of the foreign key constraint. If I don\ufffdt know what I\ufffdve just done, that\ufffds what I would probably classify as \ufffddoing something stupid\ufffd. However, let\ufffds use the function anyway.<\/p>\n<pre>SQL&gt; COLUMN avg_sal FORMAT 999,990.90<br\/>SQL&gt; select dname, loc, ROUND(func_avg_salary(dname), 2) avg_sal <br\/>2 from dept;<br\/><p><\/p><br\/>DNAME          LOC               AVG_SAL<br\/>-------------- ------------- -----------<br\/>ACCOUNTING     NEW YORK         2,916.67<br\/>RESEARCH       DALLAS           2,175.00<br\/>SALES          CHICAGO          1,566.67<br\/>OPERATIONS     BOSTON<\/pre>\n<p>The results are correct really. For all of the departments that exist in the DEPT table, the function displays the average employee salary for that department. Of course, the two new employees that I just inserted are discounted because their department is non-existent. Whether this matters or not depends on the results you were expecting!<\/p>\n<p>Again, this is all pretty obvious, but I think the important thing here is that whoever wrote the function originally (some time in the distant past) was almost definitely expecting every employee to work for an existing department. That\ufffds the whole point of having implemented the relational model and the constraints in the first place isn\ufffdt it? The author of the function could consider the possibility that there is invalid data in the database, but that\ufffds going to require more work from the developer when the RDBMS should be guaranteeing this. Even if the developer of every function does check for any possible data anomalies \ufffd a big job across an application that seems a little pointless to me \ufffd am I going to have to check the code of every function to make sure that it performs these checks?<\/p>\n<p>All of which is not to say that I think deferred constraint checking is a terribly bad thing \ufffd I\ufffdm still quite a fan for those nightmarish initial data population exercises (if you\ufffdve ever been hit by that, you\ufffdll know what I mean). However, there are dangers and I\ufffdve moved from a position of thinking that constraint checking could be deferred comfortably to thinking that it should only be used with care.<\/p>\n<p>For those who haven\ufffdt used deferred constraint checking before, here\ufffds what happens when I try to commit the invalid data<\/p>\n<pre>SQL&gt; commit;<br\/>commit<br\/>*<br\/>ERROR at line 1:<br\/>ORA-02091: transaction rolled back<br\/>ORA-02291: integrity constraint (SCOTT.FK_DEPTNO) violated - parent key not found<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In my previous blog entry I highlighted a few of the reasons that integrity constraint checking should not be deferred, stated by Date in his recent book (and by him and others in other papers). At the time and while looking at an entry over on Jeff Hunter&#8217;s Blog I felt that functions might be&hellip; <a class=\"more-link\" href=\"http:\/\/orcldoug.com\/blog\/2005\/07\/22\/deferred-constraint-checking\/\">Continue reading <span class=\"screen-reader-text\">Deferred Constraint Checking<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-968","post","type-post","status-publish","format-standard","hentry","category-uncategorized","entry"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":969,"url":"http:\/\/orcldoug.com\/blog\/2005\/06\/30\/the-multiple-assignment-operator-and-deferred-constraints\/","url_meta":{"origin":968,"position":0},"title":"The Multiple Assignment Operator and Deferred Constraints","date":"June 30, 2005","format":false,"excerpt":"I attended a day long seminar in Edinburgh last year with Chris Date lecturing and it was a rare treat. Thanks again to Peter Robson for organising this.Although I'm not the most academically-inclined techie, which I'm always honest about, I found what Chris had to say enlightening and mostly entertaining.\u2026","rel":"","context":"Similar post","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":933,"url":"http:\/\/orcldoug.com\/blog\/2005\/10\/17\/ansi-join-syntax\/","url_meta":{"origin":968,"position":1},"title":"ANSI Join Syntax","date":"October 17, 2005","format":false,"excerpt":"A couple of days ago one of my colleagues raised the question - 'ANSI join syntax, does anyone actually use that?' I have pretty strong views on this and so a brief dynamic conversation followed (and that isn't a euphemism for 'stand-up row', I should add!) So, what about ANSI\u2026","rel":"","context":"With 20 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1555,"url":"http:\/\/orcldoug.com\/blog\/2009\/12\/18\/bug-hunting\/","url_meta":{"origin":968,"position":2},"title":"Bug Hunting","date":"December 18, 2009","format":false,"excerpt":"It's early days but I think I became the joint father of a bug report this week. This is bug number 9219636. SQL> CREATE TYPE INTEGER_ARRAY_T AS TABLE OF INTEGER \u00a0 2\u00a0 \/ Type created. SQL> SQL> CREATE TABLE V_SESSION_VALID ( \u00a0 2\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SID NUMBER , \u00a0 3\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SESSION_ID NUMBER\u2026","rel":"","context":"With 8 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":938,"url":"http:\/\/orcldoug.com\/blog\/2005\/09\/29\/html-db\/","url_meta":{"origin":968,"position":3},"title":"HTML DB","date":"September 29, 2005","format":false,"excerpt":"Today I had one of those minor buzzes of excitement when I started to play around with Oracle's hosted HTML DB environment.Without wanting to go into my current feelings about work, you could say things are a little quiet. I'm trying to find things to do but I've joined just\u2026","rel":"","context":"With 2 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1060,"url":"http:\/\/orcldoug.com\/blog\/2006\/08\/19\/template-issues\/","url_meta":{"origin":968,"position":4},"title":"Template Issues","date":"August 19, 2006","format":false,"excerpt":"THE FINAL UPDATE - 21st August 2006Template Issues? I don't think so! More like user error \ud83d\ude09 It turns out that all of my template\/RSS\/blog problems were self-inflicted because I'd stupidly renamed my templates\/default folder to something else. What I hadn't realised was that, a bit like the DEFAULT profile\u2026","rel":"","context":"With 6 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":930,"url":"http:\/\/orcldoug.com\/blog\/2005\/10\/21\/ukoug-agenda\/","url_meta":{"origin":968,"position":5},"title":"UKOUG Agenda","date":"October 21, 2005","format":false,"excerpt":"What's good enough for Niall is good enough for me ... Here's my agenda for the UKOUG conferenceSunday - Oak Table day. Like Niall, I won't be there at the start, but even half a day of this standard will add a lot to the conference for me. Then onto\u2026","rel":"","context":"Similar post","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/posts\/968","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/comments?post=968"}],"version-history":[{"count":0,"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/posts\/968\/revisions"}],"wp:attachment":[{"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/media?parent=968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/categories?post=968"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/orcldoug.com\/blog\/wp-json\/wp\/v2\/tags?post=968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}