Skip to content

DBAzine.com

Sections
Personal tools
You are here: Home » Of Interest » Articles of Interest » Another Use for Views
Seeking new owner for this high-traffic DBAzine.com site.
Tap into the potential of this DBA community to expand your business! Interested? Contact us today.
Who Are You?
I am a:
Mainframe True Believer
Distributed Fast-tracker

[ Results | Polls ]
Votes : 3558
 

Another Use for Views

by Joe Celko

Craig Mullins did an excellent article called “A View Review” on the various uses for VIEWS which applies to SQL, in general, as well as DB2. But he missed another use that has become possible in SQL products as they add more Standard SQL features. Consider a schema for a chain of stores that has three tables, thus:

CREATE TABLE Stores
(store_nbr INTEGER NOT NULL PRIMARY KEY,
store_name CHAR(35) NOT NULL,
..);

 

CREATE TABLE Personnel
(ssn CHAR(9) NOT NULL PRIMARY KEY,
last_name CHAR(15) NOT NULL,
first_name CHAR(15) NOT NULL,
..);

The first two explain themselves. The third table shows the relationship between stores and personnel, namely who is assigned to what job at which store and when this happened. Thus:

CREATE TABLE JobAssignments
(store_nbr INTEGER NOT NULL
   	 REFERENCES Stores (store_nbr)
   	 ON UPDATE CASCADE
   	 ON DELETE CASCADE,
 ssn CHAR(9) NOT NULL PRIMARY KEY
        REFERENCES Personnel( ssn)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
 start_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
 end_date TIMESTAMP CHECK (start_date <= end_date),
 job_type INTEGER DEFAULT 0 NOT NULL
        CHECK (job_type BETWEEN 0 AND 99),
 PRIMARY KEY (store_nbr, ssn, start_date));

Let's invent some job_type codes, such as 0 = “unassigned", 1 = “stockboy”, etc., until we get to 99 = "Store Manager” and we have a rule that each store has at most one manager. In Full Standard SQL you could write a constraint like this:

CHECK (1 <= ALL (SELECT    COUNT(*)
   			     FROM JobAssignments
   			WHERE job_type = 99
   			GROUP BY store_nbr))

This is actually a bit subtler than it looks. If you change the <= to =, then the stores must have exactly one manager if it has any employees at all.

But most SQL product still do not allow CHECK() constraints which apply to the table as a whole, nor do they support the scheme level CREATE ASSERTION statement.

So, how to do this? You might use a trigger, which will involve proprietary, procedural code. In spite of the SQL/PSM Standard, most vendors implement very different trigger models and use their proprietary 4GL language in the body of the trigger.

We need a set TRIGGERs that validates the state of the table after each INSERT and UPDATE operation. If we DELETE an employee, this will not create more than one manager per store. The skeleton for these triggers would be something like this.

CREATE TRIGGER CheckManagers
AFTER UPDATE ON JobAssignments -- same for INSERT
IF 1 <= ALL (SELECT COUNT(*)
                        FROM JobAssignments
                   WHERE job_type = 99
                   GROUP BY store_nbr)
THEN ROLLBACK;
ELSE COMMIT;
END IF;

But being a fanatic, I want a pure SQL solution that is declarative within the limits of most current SQL products.

Let’s create two tables. This first table is a Personnel table for the store managers only and it is keyed on their Social Security Numbers. Notice the use of DEFAULT and CHECK() on their job_type to assure that this is really a "managers only" table.

CREATE TABLE Job_99_Assignments
(store_nbr INTEGER NOT NULL PRIMARY KEY
        REFERENCES Stores (store_nbr)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
ssn CHAR(9) NOT NULL 
        REFERENCES Personnel (ssn)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
start_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
end_date TIMESTAMP CHECK (start_date <= end_date),
job_type INTEGER DEFAULT 99 NOT NULL
         CHECK (job_type = 99));

This second table is a Personnel table for employees who are not store managers and it is also keyed on Social Security Numbers. Notice the use of DEFAULT for a starting position of "unassigned" and CHECK() on their job_type to assure that this is really a "No managers allowed" table.

CREATE TABLE Job_not99_Assignments
(store_nbr INTEGER NOT NULL
        REFERENCES Stores (store_nbr)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
ssn CHAR(9) NOT NULL PRIMARY KEY
        REFERENCES Personnel (ssn)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
start_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
end_date TIMESTAMP CHECK (start_date <= end_date),
job_type INTEGER DEFAULT 0 NOT NULL
        CHECK (job_type BETWEEN 0 AND 98) -- no 99 code
);

From these two tables, build this UNION_ed view of all the job assignments in the entire company and show that to developers.

CREATE VIEW JobAssignments (store_nbr, ssn, start_date, end_date, job_type)
AS
(SELECT store_nbr, ssn, start_date, end_date, job_type
   FROM Job_not99_Assignments
  UNION ALL
 SELECT store_nbr, ssn, start_date, end_date, job_type
   FROM Job_99_Assignments) 

The key and job_type constraints in each table working together will guarantee at most one manager per store. The next step is to add INSTEAD OF triggers to the VIEW or write stored procedures, so that the users can insert, update and delete from it easily. Click here to see a simple SQL-99 stored procedure, without error handling or input validation.

Likewise, a procedure to terminate an employee:

CREATE PROCEDURE FireEmployee (IN new_ssn CHAR(9))
LANGUAGE SQL
IF new_job_typ <> 99
THEN DELETE FROM Job_not99_Assignments
      WHERE ssn = new_ssn;
ELSE DELETE FROM Job_99_Assignments
      WHERE ssn = new_ssn;
END IF; 

If a developer attempts to change the Job_Assignments VIEW directly with an INSERT, UPDATE or DELETE, they will get an error message telling them that the VIEW is not updatable because it contains a UNION operation. That is a good thing, in one way, because we can force them to use only the stored procedures.

Again, this is an exercise in programming a solution within certain limits. The TRIGGER is probably going give better performance than the VIEW. Just as Craig's original article showed how to use VIEWs to replace simple column-level CHECK() constraints, this shows how to use them to replace more complex table-level CHECK() constraints.

--

Joe Celko was a member of the ANSI X3H2 Database Standards Committee and helped write the SQL-92 standards. He is the author of over 450 magazine columns and four books, the best known of which is SQL for Smarties (Morgan-Kaufmann Publishers, 1999) and the new book, Trees and Hierarchies in SQL for Smarties (Morgan-Kaufmann Publishers, 2003). For articles, puzzles, resources, and more, go to http://www.celko.com.


Contributors : Joe Celko
Last modified 2005-04-12 06:21 AM
Transaction Management
Reduce downtime and increase repeat sales by improving end-user experience.
Free White Paper
Database Recovery
Feeling the increased demands on data protection and storage requirements?
Download Free Report!
 
 

Powered by Plone