O'Reilly Databases

oreilly.comSafari Books Online.Conferences.

We've expanded our coverage and improved our search! Search for all things Database across O'Reilly!

Search Search Tips

advertisement
AddThis Social Bookmark Button

Listen Print Subscribe to Databases Subscribe to Newsletters

Substituting and Converting Object Types in a Hierarchy
Pages: 1, 2, 3, 4

How to Turn Off Substitutability

Why would I want to constrain or limit substitutability? I may want my table to contain objects of a specific type within my hierarchy, not any subtypes. To accommodate this need, Oracle lets you turn off all substitutability on a column or attribute, including embedded attributes and collections nested to any level. You do this by using the following clause:



NOT SUBSTITUTABLE AT ALL LEVELS 

Suppose that I create another table to define meals I serve on a given day. Here's the table:

CREATE TABLE meal (
   served_on DATE,
   appetizer food_t,
   main_course food_t,
   dessert dessert_t
   )
   COLUMN appetizer NOT SUBSTITUTABLE AT ALL LEVELS
   ;

I use the NOT SUBSTITUTABLE clause to indicate that you can't use a subtype of food when providing a value for the appetizer column. I don't want anyone sneaking in a dessert for the appetizer.

Now consider the code in Example 1. I try to insert two different meals. In the first INSERT, I supply an object of type food_t for appetizer, which is fine. In my second insert, I try to pass off a dessert as an appetizer. The result, when executed, is the following error:

ERROR at line 1:
ORA-00932: inconsistent datatypes

Example 1. An attempt to define two meals.

BEGIN
   INSERT INTO meal VALUES (
      SYSDATE,
      food_t ('Shrimp cocktail', 'PROTEIN', 'Ocean'),
      food_t ('Eggs benedict', 'PROTEIN', 'Farm'),
      dessert_t ('Strawberries and cream', 'FRUIT', 'Backyard', 'N', 2001));
        
   INSERT INTO meal VALUES (
      SYSDATE + 1,
      dessert_t ('Strawberries and cream', 'FRUIT', 'Backyard', 'N', 2001),
      food_t ('Eggs benedict', 'PROTEIN', 'Farm'),
      cake_t ('Apple Pie', 'FRUIT', 'Baker''s Square', 'N', 2001, 8, NULL));
END;

I can also apply the NOT SUBSITUTABLE clause to an entire object table. Example 2 demonstrates this capability. I create a table of food_t objects called brunches. I can then successfully insert an object of type food_t, but get the same "inconsistent datatypes" error when I try to put a dessert into this table.

Example 2. Constraining substitutability in an object table.

SQL> CREATE TABLE brunches OF food_t NOT SUBSTITUTABLE AT ALL LEVELS; 

Table created.

SQL> 
SQL> INSERT INTO brunches VALUES (
  2     food_t ('Eggs benedict', 'PROTEIN', 'Farm'));

1 row created.

SQL> INSERT INTO brunches VALUES (
  2     dessert_t ('Strawberries and cream', 'FRUIT', 'Backyard', 'N', 2001));  
   dessert_t ('Strawberries and cream', 'FRUIT', 'Backyard', 'N', 2001))
   *
ERROR at line 2:
ORA-00932: inconsistent datatypes

There are two things to remember about constraining substitutability:

  • There's no mechanism to turn off substitutability for REF columns.
  • A column must be a top-level column for the clause NOT SUBSTITUTABLE AT ALL LEVELS to be applied to it. You can't apply the clause to an object-type attribute.

Constraining Substitutability to a Specific Subtype

So I can turn off all levels of substitutability, but what if I want to turn off all substitutability except for a particular subtype? Suppose, for example, that I want to create a PL/SQL collection of desserts that can contain only cakes. Or I want to set a rule in my meals table that all desserts must be cakes. Oracle offers the IS OF clause for just this purpose. Here's a re-definition of the meals table that offers two different kinds of substitutability constraints:

CREATE TABLE meal (
   served_on DATE,
   appetizer food_t,
   main_course food_t,
   dessert dessert_t
   )
   COLUMN appetizer NOT SUBSTITUTABLE AT ALL LEVELS,
   COLUMN dessert IS OF (ONLY cake_t)
   ;

And now I'll only be able to add meals in which the dessert is defined as a cake. So the following INSERT is rejected:

SQL> BEGIN
  2    -- This will no longer work.
  3    INSERT INTO meal VALUES (
  4    SYSDATE,
  5    food_t ('Shrimp cocktail', 
  6       'PROTEIN', 'Ocean'),
  7    food_t ('Eggs benedict', 
  8       'PROTEIN', 'Farm'),
  9    dessert_t ('Strawberries and cream', 
 10       'FRUIT', 'Backyard', 'N', 2001));
 11  END;
 12  /
BEGIN
*
ERROR at line 1:
ORA-00932: inconsistent datatypes

You can only use the IS OF type operator to constrain row and column objects to a single subtype, but not several. You must also use the ONLY keyword, even though that's the only choice available now. You can use either IS OF type or NOT SUBSTITUTABLE AT ALL LEVELS to constrain an object column, but you can't use both for that same column. Clearly, as shown previously, you can apply those constraints to different columns.

Pages: 1, 2, 3, 4

Next Pagearrow




Tagged Articles

Be the first to post this article to del.icio.us

Sponsored Resources

  • Inside Lightroom

Related to this Article

Understanding Oracle Clinical Understanding Oracle Clinical
by Joan M. Johnson
June 2009
$9.99 USD

New Features in Oracle 9i New Features in Oracle 9i
by Howard J. Rogers
June 2009
$5.95 USD

Advertisement
O'Reilly Media

©2009, O'Reilly Media, Inc.
(707) 827-7000 / (800) 998-9938
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
About O'Reilly
Academic Solutions
Authors
Contacts
Customer Service
Jobs
Newsletters
O'Reilly Labs
Press Room
Privacy Policy
RSS Feeds
Terms of Service
User Groups
Writing for O'Reilly
Content Archive
Business Technology
Computer Technology
Google
Microsoft
Mobile
Network
Operating System
Digital Photography
Programming
Software
Web
Web Design
More O'Reilly Sites
O'Reilly Radar
Ignite
Tools of Change for Publishing
Digital Media
Inside iPhone
makezine.com
craftzine.com
hackszine.com
perl.com
xml.com

Partner Sites
InsideRIA
java.net
O'Reilly Insights on Forbes.com