CREATE TABLE CUSTOMER( CustomerID int Name char(25) Street char(30) City char(35) State char(2) ZipPostalCode char(9) Country char(50) AreaCode char(3) PhoneNumber char(8) Email char(100) CONSTRAINT CustomerPK NOT NULL IDENTITY (1000,1), NOT NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, Null, PRIMARY KEY (CustomerID) ); CREATE TABLE ARTIST( ArtistID int Name char(25) Nationality char(30) Birthdate numeric (4) DeceasedDate numeric(4) CONSTRAINT CONSTRAINT CONSTRAINT CONSTRAINT CONSTRAINT CONSTRAINT NOT NULL IDENTITY (1,1), NOT NULL, NULL, NULL, NULL, ArtistPK PRIMARY KEY (ArtistID), ArtistAK1 UNIQUE (Name), NationalityValues CHECK (Nationality IN ('Canadian', 'English', 'French', 'German', 'Mexican', 'Russian', 'Spanish', 'US')), BirthValuesCheck CHECK (Birthdate < DeceasedDate), ValidBirthYear CHECK (Birthdate LIKE '[1-2][0-9][0-9][0-9]'), ValidDeathYear CHECK (DeceasedDate LIKE '[1-2][0-9][0-9][0-9]') ); CREATE TABLE CUSTOMER_ARTIST_INT( ArtistID int NOT NULL, CustomerID int NOT NULL, CONSTRAINT CONSTRAINT CONSTRAINT CustomerArtistPK PRIMARY KEY (ArtistID, CustomerID), Customer_Artist_Int_ArtistFK FOREIGN KEY (ArtistID) REFERENCES ARTIST (ArtistID) ON UPDATE CASCADE ON DELETE CASCADE, Customer_Artist_Int_CustomerFK FOREIGN KEY (CustomerID) REFERENCES CUSTOMER (CustomerID) ON UPDATE CASCADE ON DELETE CASCADE ); CREATE TABLE WORK ( WorkID int NOT NULL IDENTITY (500,1), Title char(25) NOT NULL, Description varchar(1000) NULL, Copy char(8) NOT NULL, ArtistID int NOT NULL, CONSTRAINT WorkPK CONSTRAINT WorkAK1 PRIMARY KEY (WorkID), UNIQUE (Title, Copy), CONSTRAINT ArtistFK FOREIGN KEY(ArtistID) REFERENCES ARTIST (ArtistID) ); CREATE TABLE TRANSACTION ( TransactionID int NOT NULL IDENTITY (100,10), DateAcquired date NOT NULL, AcquisitionPrice numeric(8,2) NULL, PurchaseDate date NULL, SalesPrice numeric(8,2) NULL, AskingPrice numeric(8,2) NULL, CustomerID int NULL, WorkID int NOT NULL, CONSTRAINT CONSTRAINT CONSTRAINT CONSTRAINT CONSTRAINT TransactionPK PRIMARY KEY (TransactionID), SalesPriceRange CHECK ((SalesPrice > 1000) AND (SalesPrice <=200000)), ValidTransDate CHECK (DateAcquired <= PurchaseDate), TransactionWorkFK FOREIGN KEY(WorkID) REFERENCES WORK (WorkID), TransactionCustomerFK FOREIGN KEY(CustomerID) REFERENCES CUSTOMER (CustomerID) ); SQL for Creating the Database Design in Figure 7-3(b) Figure 7-4 CREATE TRIGGER TRANSACTION_SalesPriceCheck AFTER UPDATE ON TRANSACTION BEGIN IF :new.SalesPrice < .9 * :old.AskingPrice THEN /* Sales Price is too low, reset it */ UPDATE TRANSACTION SET SalesPrice = :old.AskingPrice, AskingPrice = :old.AskingPrice; /* Note: /* the above update will cause a recursive call on this trigger. The recursion will stop the second time through because SalesPrice will be = AskingPrice. */ Also should send a message to the user saying what’s been done */ END IF; END; Example AFTER UPDATE Trigger for Checking Valid Values Figure 7-14 CREATE TRIGGER TRANSACTION_AskingPriceInitialValue AFTER INSERT ON TRANSACTION DECLARE rowcount as int; sumNetPrice as numeric (10,2); avgNetPrice as numeric (8,2); BEGIN /* First find if work has been here before */ SELECT FROM WHERE Count(*) INTO rowcount TRANSACTION T :new.WorkID = T.WorkID; IF rowcount = 1 Then /* This is first time work has been in gallery */ :new.AskingPrice = 2 * :new.AcquisitionPrice; ELSE IF rowcount > 1 Then /* Work has been here before */ SELECT FROM WHERE GROUP BY Sum(NetPrice) into sumNetPrice ArtistWorkNet AW AW.WorkID = :new.WorkID AW.WorkID; avgNetPrice = sumNetPrice / (rowcount – 1); /* Now choose larger */ IF avgNetPrice > 2 * :new.AcquisitionPrice Then :new.AskingPrice = avgNetPrice; ELSE :new.AskingPrice = 2 * :new.AcquisitionPrice; END IF; ELSE /* Error, rowcount cannot be less than 1 – Do something */ END IF; END IF; END; Example AFTER INSERT Trigger for Computing a Default Value Figure 7-15 CREATE TRIGGER CustomerInterest_CustomerName Update INSTEAD OF UPDATE ON CustomerInterests DECLARE rowcount int; SELECT FROM WHERE Count(*) INTO rowcount CUSTOMER C C.Name = :old.Customer; BEGIN IF rowcount > 1 THEN /* Non-unique name, cannot update */ /* Send message to user that there are duplicates and cannot update because do not know which to change. */ ELSE /* If get here, then only one customer with this name. Make the name change. */ UPDATE SET WHERE CUSTOMER CUSTOMER.Name = :new.Customer CUSTOMER.Name = :old.Customer; END; Example INSTEAD OF Trigger for Updating a View Figure 7-16 CREATE TRIGGER WORK_TRANSACTION_Check AFTER INSERT ON WORK DECLARE rowcount as int; BEGIN /* First look for a related TRANSACTION row */ SELECT FROM WHERE Count(*) INTO rowcount TRANSACTION T :new.WorkID = T.WorkID; IF rowcount = 0 Then /* remove just added WORK */ DELETE FROM WORK WHERE WORK.WorkID = :new.WorkID /* need some way to notify what has occurred here */ END IF; END; Example AFTER INSERT Trigger for Enforcing a Required Child Constraint Figure 7-17 CREATE TRIGGER WORK_Deletion INSTEAD OF DELETE ON WORK DECLARE rowcount as int; nullCount as int; BEGIN /* First check related TRANSACTION row counts*/ SELECT FROM WHERE Count(*) INTO rowcount TRANSACTION T :old.WorkID = T.WorkID; IF rowcount = 0 Then /* this should never occur -- error */ /* write to error log and do nothing */ ELSE IF rowcount = 1 THEN /* Check for null CustomerID */ SELECT Count(*) into nullCount FROM TRANSACTION T WHERE :old.WorkID = T.WorkID AND T.CustomerID IS NULL; IF nullCount = 1 THEN /* Deletions must go in this order */ DELETE FROM TRANSACTION T WHERE :old.WorkID = T.WorkID; DELETE FROM WORK W WHERE :old.WorkID = W.WorkID; END IF; END IF; END IF; END; Example INSTEAD OF DELETE Trigger for Enforcing a Deletion Rule Figure 7-18