Professional Documents
Culture Documents
13. What SQL:1999 statements and procedures support explicit database connections?
Ans: SQL:1999 specifies the CONNECT statement and other related statements for
statement level interfaces and the Connect() procedure and related procedures in the CLI.
14. What differences must be resolved to process the results of an SQL statement in a
computer program?
Ans: To process the results of SQL statements, database programming languages must
resolve differences in data types and processing orientation.
16. What statements and procedures does SQL:1999 provide for cursor processing?
Ans: For statement level interfaces, SQL:1999 provides statements to declare cursors,
open and close cursors, position cursors, and retrieve values from cursors. The SQL:1999
CLI provides procedures with similar functionality to the statement level interface.
18. Explain case sensitivity in PL/SQL. Why are most parts of PL/SQL case insensitive?
Ans: User identifiers and reserved words are not case sensitive. String constants are case
sensitive. Case sensitivity can lead to subtle errors in code. Thus, many languages are
case insensitive for user identifiers and reserved words.
24. Why should a DBMS manage procedures rather than a programming language
environment?
Ans: A DBMS can compile the programming language code along with the SQL
statements in a stored procedure. A DBMS can detect when the SQL statements in a
procedure need to be recompiled due to changes in database definitions. A DBMS can
store procedures on a server rather than replicating procedures on every client. A DBMS
provides security for stored procedures. A DBMS allows stored procedures to extend the
functionality of standard SQL functions.
31. What is the difference between a static and a dynamic cursor in PL/SQL?
Ans: PL/SQL supports static cursors in which the SQL statement is known at compile-
time as well as dynamic cursors in which the SQL statement is not determined until run-
time.
35. Why separate the interface from the implementation in a PL/SQL package?
Ans: A package separates a public interface from a private implementation to support
reduced software maintenance efforts. Change s to a private implementation do not affect
the usage of a package through its interface.
41. Why do most trigger implementations differ from the SQL:1999 specification?
Ans: Because the SQL:1999 trigger specification was defined in response to vendor
implementations, most trigger implementations vary from the SQL:1999 specification.
Most DBMSs support the spirit of the SQL:1999 trigger specification in trigger
granularity, timing, and applicable events but do not adhere strictly to the SQL:1999
trigger syntax.
47. What is an overlapping trigger? What is the execution order of overlapping triggers?
Ans: Two triggers with the same timing, granularity, and applicable table overlap if an
SQL statement may cause both triggers to fire. For overlapping triggers, Oracle specifies
that the execution order is arbitrary. For SQL:1999, the execution order depends on the
time in which the trigger is defined. Overlapping triggers are executed in the order in
which the triggers were created. You should not depend on a specific firing order for
overlapping triggers.
48. What situations lead to recursive execution of the trigger execution procedure?
Ans: Data manipulation statements in a trigger and actions on referenced rows cause
recursive execution.
49. List at least two ways to reduce the complexity of a collection of triggers.
Ans: Four ways to control complexity are listed below:
Do not use data manipulation statements in BEFORE triggers.
Limit data manipulation statements in AFTER triggers.
For triggers that fire on UPDATE statements, always list the columns to which the trigger
applies.
Ensure that overlapping triggers do not depend on a specific order to fire.
50. What situations lead to recursive execution of the trigger execution procedure?
Ans: In trigger actions, Oracle prohibits SQL statements on the table in which the trigger
is defined or on related tables affected by DELETE CASCADE actions. The underlying
trigger table and the related tables are known as mutating tables. If a trigger executes an
SQL statement on a mutating table, a run-time error occurs.
PROBLEM SOLUTIONS
Each problem uses the revised order entry database shown in Chapter 10. For your
reference, Figure 11.P1 in the problem narrative in the textbook shows a relationship
window for the revised order entry database. More details about the revised database can
be found in Chapter 10 problems.
The problems provide practice with PL/SQL coding and development of procedures,
functions, packages, and triggers. In addition, some problems involve anonymous blocks
and scripts to test the procedures, functions, packages, and triggers.
The test scripts assume that the revised Order Entry Database of Chapter 10 is populated
according to the text files in the textbook’s website.
1. Write a PL/SQL anonymous block to calculate the number of days in a non- leap
year. Your code should loop through the months of the year (1 to 12) using a FOR
LOOP. You should use an IF-THEN-ELSIF statement to determine the number of
days to add for the month. You can group months together that have the same
number of days. Display the number of days after the loop terminates.
Ans:
SET SERVEROUTPUT ON;
-- Anonymous block to compute the number of days in a non leap year
DECLARE
NumDays INTEGER := 0;
Idx INTEGER;
BEGIN
-- Use a loop to iterate through the months
FOR Idx IN 1 .. 12 LOOP
IF Idx = 1 OR Idx = 3 OR Idx = 5 OR Idx = 7 OR Idx = 8 OR Idx = 10
OR Idx = 12 THEN
NumDays := NumDays + 31;
ELSIF Idx = 4 OR Idx = 6 OR Idx = 9 OR Idx = 11 THEN
NumDays := NumDays + 30;
ELSE
NumDays := NumDays + 28;
END IF;
END LOOP;
-- Display the results
Dbms_Output.Put_Line('Number of days in a non leap year is '
|| To_Char(NumDays) || '.');
END;
/
Ans: Note that the CASE statement is not supported in Oracle 8i (any version). The
solution will not compile in Oracle 8i.
SET SERVEROUTPUT ON;
-- Anonymous block to compute the number of days in a leap year
DECLARE
NumDays INTEGER := 0;
Idx INTEGER;
BEGIN
-- Use a loop to iterate through the months
FOR Idx IN 1 .. 12 LOOP
CASE Idx
WHEN 1 THEN NumDays := NumDays + 31;
WHEN 2 THEN NumDays := NumDays + 29;
WHEN 3 THEN NumDays := NumDays + 31;
WHEN 4 THEN NumDays := NumDays + 30;
WHEN 5 THEN NumDays := NumDays + 31;
WHEN 6 THEN NumDays := NumDays + 30;
WHEN 7 THEN NumDays := NumDays + 31;
WHEN 8 THEN NumDays := NumDays + 31;
WHEN 9 THEN NumDays := NumDays + 30;
WHEN 10 THEN NumDays := NumDays + 31;
WHEN 11 THEN NumDays := NumDays + 30;
WHEN 12 THEN NumDays := NumDays + 31;
END CASE;
END LOOP;
-- Display the results
Dbms_Output.Put_Line('Number of days in a leap year is '
|| To_Char(NumDays) || '.');
END;
/
-- Oracle 8i solution without using ELSIF instead of CASE
DECLARE
NumDays INTEGER := 0;
Idx INTEGER;
BEGIN
-- Use a loop to iterate through the months
FOR Idx IN 1 .. 12 LOOP
IF Idx = 1 OR Idx = 3 OR Idx = 5 OR Idx = 7 OR Idx = 8 OR Idx = 10
OR Idx = 12 THEN
NumDays := NumDays + 31;
ELSIF Idx = 4 OR Idx = 6 OR Idx = 9 OR Idx = 11 THEN
NumDays := NumDays + 30;
ELSE
NumDays := NumDays + 29;
END IF;
END LOOP;
-- Display the results
Dbms_Output.Put_Line('Number of days in a no n leap year is '
|| To_Char(NumDays) || '.');
END;
/
Ans:
4. Write a PL/SQL anonymous block to display the price of product number P0036577.
Use an anchored variable declaration and a SELECT INTO statement to determine
the price. If the price is less than $100, display a message that the product is a good
buy. If the price is between $100 and $300, display a message that the product is
competitively priced. If the price is greater then $300, display a message that the
product is feature laden.
Ans:
5. Write a PL/SQL procedure to insert a new row into the Product table using input
parameters for the product number, product name, product price, next ship date,
quantity on hand, and supplier number. For a successful insert, display an
appropriate message. If an error occurs in the INSERT statement, raise an exception
with an appropriate error message.
Ans:
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Cannot add product row');
END;
/
Ans:
END;
/
7. Write testing scripts for the procedures in problems 5 and 6. For the procedure in
problem 6, your script should test for a primary key violation and a foreign key
violation.
Ans:
-- Problem 6 tests
SELECT COUNT(*) FROM Product;
DECLARE
Result BOOLEAN;
-- This test should succeed.
BEGIN
pr_InsertProductProb6
('P9995688','Battery Back-up System',100,12,
to_date('1-Feb-2004'),'S5095332', Result);
IF Result THEN
dbms_output.put_line('Added a row to the Product table');
ELSE
dbms_output.put_line('Row not added to the Product table');
END IF;
END;
/
SELECT COUNT(*) FROM Product;
ROLLBACK;
-- This test should fail because the primary key is duplicate.
DECLARE
Result BOOLEAN;
-- This test should succeed.
BEGIN
pr_InsertProductProb6
('P9995676','Battery Back-up System',100,12,
to_date('1-Feb-2004'),'S5095332', Result);
IF Result THEN
dbms_output.put_line('Added a row to the Product table');
END IF;
IF Result THEN
dbms_output.put_line('Added a row to the Product table');
ELSE
dbms_output.put_line('Row not added to the Product table');
END IF;
END;
SELECT COUNT(*) FROM Product;
ROLLBACK;
/
8. Write a PL/SQL function to determine if the most recent order for a given customer
number was sent to the customer’s billing address. The function should return
TRUE if each order address column (street, city, state, and zip) is equal to the
corresponding customer address column. If any address column is not equal, return
false. The most recent order has the largest order date. Return NULL if the
customer does not exist or there are no orders for the customer.
Ans:
BEGIN
EXCEPTION
WHEN no_data_found THEN
RETURN(NULL);
END;
/
Ans: There should be 3 test cases for a match, a non match, and a non existing customer.
10. Create a procedure to compute the commission amount for a given order number.
The commission amount is the commission rate of the employee taking the order
times the amount of the order. The amount of an order is the sum of the product of
the quantity of a product ordered times the product price. If the order does not have
a related employee (a Web order), the commission is zero. The procedure should
have an output variable for the commission amount. The output variable should be
null if an order does not exist.
Ans:
CREATE OR REPLACE PROCEDURE pr_ComputeCommission
(anOrdNo IN OrderTbl.OrdNo%type,
aCommission OUT NUMBER) IS
-- Computes commission for the specified order.
-- If the order does not exist, aCommission is null.
-- If the order does not have an employee, aCommission is 0.
NoEmployee EXCEPTION;
TmpEmpNo OrderTbl.EmpNo%TYPE;
TmpOrdDate OrderTbl.OrdDate%TYPE;
BEGIN
EXCEPTION
WHEN NoEmployee THEN
aCommission := 0;
END;
/
11. Create a testing script for the PL/SQL procedure in problem 10.
Ans:
12. Create a function to check the quantity on hand of a product. The input parameters
are a product number and a quantity ordered. Return FALSE if the quantity on hand
is less than the quantity ordered. Return TRUE is the quantity on hand is greater
than or equal to the quantity ordered. Return NULL if the product does not exist.
Ans:
SELECT ProdQOH
INTO aQOH
FROM Product
WHERE Product.ProdNo = aProdNo;
EXCEPTION
WHEN no_data_found THEN
RETURN(NULL);
END;
/
13. Create a procedure to insert an order line. Use the function from problem 12 to
check for adequate stock. If there is not sufficient stock, the output parameter should
be FALSE. Raise an exception if there is an insertion error such as duplicate
primary key.
Ans:
END;
/
14. Create testing scripts for the function in problem 12 and the procedure in problem
13.
Ans:
-- Failed insert
DECLARE
aResult BOOLEAN;
BEGIN
pr_InsertOrdLine('P0036566','O1116324',13,aResult);
IF aResult THEN
dbms_output.put_line('OrdLine insert successful');
ELSE
dbms_output.put_line(' OrdLine insert not successful');
END IF;
END;
/
ROLLBACK;
15. Write a function to compute the median of the customer balance column. The
median is the middle value in a list of numbers. If the list size is even, the median is
the average of the two middle values. For example, if there are 18 customer
balances, the median is the average of the ninth and tenth balances. You should use
an implicit cursor in your function. You may want to use the Oracle SQL functions
Trunc and Mod in writing your function. Write a test script for your function. Note
that this function does not have any parameters. Do not use parentheses in the
function declaration or in the function invocation when a function does not have
parameters.
Ans:
BEGIN
SELECT COUNT(*) INTO CustCount FROM Customer;
-- Determine middle value
IF Mod(CustCount,2) = 0 THEN
MidVal := CustCount/2;
ELSE
MidVal := Trunc(CustCount/2,0) + 1;
END IF;
-- Loop through implicit cursor
FOR CustRec IN
( SELECT CustBal
FROM Customer
ORDER BY CustBal ) LOOP
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END;
/
-- Test Script
-- Even number of customers: 16
SELECT COUNT(*) FROM Customer;
SELECT CustBal FROM Customer ORDER BY CustBal;
BEGIN
dbms_output.put_line('Median is '||to_char(fn_DetermineMedianBal));
END;
/
16. Revise the function in problem 15 with an explicit cursor using the CURSOR, the
OPEN, the FETCH, and the CLOSE statements. Write a test script for your revised
function.
Ans:
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END;
/
17. Create a package containing the function in problem 15, the procedure in problem
13, the procedure in problem 10, the function in problem 8, and the procedure in
problem 6. The function in problem 12 should be private to the package. You do
not need to completely test each public object. One execution per public object is
fine because you previously tested the procedures and functions outside the package.
Ans:
PROCEDURE pr_InsertProductProb6
(aProdNo IN Product.ProdNo%type,
aProdName IN Product.ProdName%type,
aProdPrice IN Product.ProdPrice%type,
aProdQOH IN Product.ProdQOH%type,
aProdNextShipDate IN Product.ProdNextShipDate%type,
aSuppNo IN Product.SuppNo%TYPE, aResult OUT BOOLEAN) IS
BEGIN
INSERT INTO Product
(ProdNo, ProdName, ProdPrice, ProdQOH, ProdNextShipDate, SuppNo)
VALUES
(aProdNo,aProdName,aProdPrice,aProdQOH,aProdNextShipDate,aSuppNo);
aResult := TRUE;
EXCEPTION
WHEN Dup_Val_On_Index THEN
raise_application_error(-20001, 'Primary key not unique');
WHEN OTHERS THEN
raise_application_error(-20001, 'Cannot add product row');
END pr_InsertProductProb6;
FUNCTION fn_ShipToBillToMatch
(aCustNo IN Customer.CustNo%type) RETURN BOOLEAN IS
-- Returns TRUE if all address columns match.
-- Returns FALSE if at least one address column does not match.
-- Returns NULL if no customer or no order for the customer.
aCustStreet Customer.CustStreet%type;
aCustCity Customer.CustCity%type;
aCustState Customer.CustState%type;
aCustZip Customer.CustZip%type;
anOrdStreet OrderTbl.OrdStreet%type;
anOrdCity OrderTbl.OrdCity%type;
anOrdState OrderTbl.OrdState%type;
anOrdZip OrderTbl.OrdZip%type;
BEGIN
SELECT OrdStreet, OrdCity, OrdState, OrdZip,
CustStreet, CustCity, CustState, CustZip
INTO anOrdStreet, anOrdCity, anOrdState, anOrdZip,
aCustStreet, aCustCity, aCustState, aCustZip
FROM OrderTbl, Customer
WHERE OrderTbl.CustNo = aCustNo
AND OrderTbl.CustNo = Customer.CustNo
AND OrdDate =
( SELECT MAX(OrdDate)
FROM OrderTbl
WHERE CustNo = aCustNo );
IF anOrdStreet = aCustStreet AND anOrdCity = aCustCity AND
anOrdState = aCustState AND anOrdZip = aCustZip THEN
RETURN(TRUE);
ELSE
RETURN(FALSE);
END IF;
EXCEPTION
WHEN no_data_found THEN
RETURN(NULL);
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END fn_ShipToBillToMatch;
PROCEDURE pr_ComputeCommission
(anOrdNo IN OrderTbl.OrdNo%type,
aCommission OUT NUMBER) IS
-- Computes commission for the specified order.
-- If the order does not exist, aCommission is null.
-- If the order does not have an employee, aCommission is 0.
NoEmployee EXCEPTION;
TmpEmpNo OrderTbl.EmpNo%TYPE;
TmpOrdDate OrderTbl.OrdDate%TYPE;
BEGIN
SELECT OrdDate, EmpNo
INTO tmpOrdDate, tmpEmpNo
FROM OrderTbl
WHERE OrdNo = anOrdNo;
IF tmpEmpNo IS NULL THEN
RAISE NoEmployee;
END IF;
SELECT SUM(EmpCommRate * OrdLine.Qty * ProdPrice) AS Commission
INTO aCommission
FROM Employee, OrderTbl, OrdLine, Product
WHERE OrderTbl.OrdNo = anOrdNo
AND OrderTbl.OrdNo = OrdLine.OrdNo
AND OrdLine.ProdNo = Product.ProdNo
AND OrderTbl.EmpNo = Employee.EmpNo;
EXCEPTION
WHEN NoEmployee THEN
aCommission := 0;
WHEN No_Data_Found THEN
aCommission := NULL;
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END pr_ComputeCommission;
PROCEDURE pr_InsertOrdLine
(aProdNo IN OrdLine.ProdNo%type,
anOrdNo IN OrdLine.OrdNo%type,
aQty IN OrdLine.Qty%type,
aResult OUT BOOLEAN) IS
-- aResult is false if insufficient stock
-- Otherwise aResult is true and insert occurs
OutofStock EXCEPTION;
BEGIN
-- Check for adequate stock
IF NOT(fn_CheckQOH(aProdNo, aQty)) THEN
RAISE OutofStock;
END IF;
INSERT INTO OrdLine
(ProdNo, OrdNo, Qty)
VALUES
(aProdNo,anOrdNo,aQty);
aResult := TRUE;
EXCEPTION
WHEN OutofStock THEN
aResult := FALSE;
WHEN Dup_Val_On_Index THEN
raise_application_error(-20001, 'Primary key not unique');
WHEN OTHERS THEN
raise_application_error(-20001, 'Cannot add ordline row');
END pr_InsertOrdLine;
FUNCTION fn_DetermineMedianBal
RETURN INTEGER IS
-- Determines the median customer balance.
-- Uses an implicit cursor.
CustCount INTEGER;
MidVal INTEGER;
Idx INTEGER := 1;
MedianVal Customer.CustBal%TYPE;
BEGIN
SELECT COUNT(*) INTO CustCount FROM Customer;
-- Determine middle value
IF Mod(CustCount,2) = 0 THEN
MidVal := CustCount/2;
ELSE
MidVal := Trunc(CustCount/2,0) + 1;
END IF;
-- Loop through implicit cursor
FOR CustRec IN
( SELECT CustBal
FROM Customer
ORDER BY CustBal ) LOOP
IF Idx = MidVal THEN
-- Increment the class rank when the grade changes
MedianVal := CustRec.CustBal;
IF Mod(CustCount,2) <> 0 THEN
RETURN(MedianVal);
END IF;
END IF;
IF Idx = MidVal+1 THEN
MedianVal := (MedianVal + CustRec.CustBal)/2;
RETURN(MedianVal);
END IF;
Idx := Idx + 1;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END fn_DetermineMedianBal;
END pck_OrdEntry;
-- Test fn_ShipToBillToMatch
BEGIN
-- This test should return TRUE.
IF pck_OrdEntry.fn_ShipToBillToMatch('C0954327') THEN
dbms_output.put_line('Most recent order sent to the
billing address');
ELSE
dbms_output.put_line('Most recent order not sent to the
billing address');
END IF;
END;
/
-- Test pr_ComputeCommission
-- Order with an employee. Order has only 1 order line.
DECLARE
tmpCommission DECIMAL(10,2);
BEGIN
pck_OrdEntry.pr_ComputeCommission('O1116324',tmpCommission);
dbms_output.put_line('Commission is '|| to_char(tmpCommission));
END;
/
-- Test pr_InsertOrdLine
-- Successful insert
DECLARE
aResult BOOLEAN;
BEGIN
pck_OrdEntry.pr_InsertOrdLine('P0036566','O1116324',12,aResult);
IF aResult THEN
dbms_output.put_line('OrdLine insert successful');
ELSE
dbms_output.put_line(' OrdLine insert not successful');
END IF;
END;
/
ROLLBACK;
-- Test fn_DetermineMedianBal
SELECT COUNT(*) FROM Customer;
SELECT CustBal FROM Customer ORDER BY CustBal;
BEGIN
dbms_output.put_line('Median is '||
to_char(pck_OrdEntry.fn_DetermineMedianBal));
END;
/
18. Write an AFTER ROW trigger to fire for every action on the Customer table. In the
trigger, display the new and old customer values every time that the trigger fires.
Write a script to test the trigger.
Ans:
dbms_output.put_line('Deleted Table');
dbms_output.put_line('CustNo: ' || :OLD.CustNo);
dbms_output.put_line('First Name: '
|| :OLD.CustFirstName);
dbms_output.put_line('Last Name: '
|| :OLD.CustLastName);
dbms_output.put_line('Street: '
|| :OLD.CustStreet);
dbms_output.put_line('City: '
|| :OLD.CustCity);
dbms_output.put_line('State: '
|| :OLD.CustState);
dbms_output.put_line('Zip: '
|| :OLD.CustZip);
dbms_output.put_line('Balance: ' || To_Char(:OLD.CustBal));
END;
/
UPDATE Customer
SET CustBal = 500
WHERE CustNo = '99883457';
ROLLBACK;
19. Write a trigger for a transition constraint on the Employee table. The trigger should
prevent updates that in crease or decrease the commission rate by more than 10
percent. Write a script to test your trigger.
Ans:
ROLLBACK;
20. Write a trigger to remove the prefix http:// in the column Supplier.SuppURL on
insert and update operations. Your trigger should work regardless of the case of the
prefix http://. You need to use Oracle SQL functions for string manipulation. You
should study Oracle SQL fuctions such as SubStr, Lower and LTrim. Write a script
to test your trigger.
Ans: Should be BEFORE ROW trigger because updates are made to new values.
21. Write a trigger to ensure that there is adequate stock when inserting a new OrdLine
row or updating the quantity of an OrdLine row. On insert operations, the ProdQOH
of the related row should be greater than or equal to the quantity in the new row. On
update operations, the ProdQOH should be greater than or equal to the difference in
the quantity (new quantity minus old quantity.)
Ans:
-- This trigger checks for qoh for both insertion of an order line
-- and update of ordline.qty.
CREATE OR REPLACE TRIGGER tr_OrdlineQty_IUB
BEFORE INSERT OR UPDATE OF Qty ON OrdLine
FOR EACH ROW
DECLARE my_qoh Product.ProdQOH%TYPE;
out_of_stock exception;
ExMessage VARCHAR(200);
BEGIN
SELECT ProdQOH
INTO my_qoh
FROM Product
WHERE Product.ProdNo = :NEW.ProdNo;
22. Write a trigger to propagate updates to the Product table after an operation on the
OrdLine table. For insertions, the trigger should decrease the quantity on hand by
order quantity. For updates, the trigger should decrease the quantity on hand by the
difference between the new order quantity minus the old order quantity. For
deletions, the trigger should increase the quantity on hand by the old order quantity.
Ans:
ROLLBACK;
24. Write a trigger to propagate updates to the Product table after insert operations on
the PurchLine table. The quantity on hand should increase by the purchase quantity.
Write a script to test the trigger.
25. Write a trigger to propagate updates to the Product table after update operations on
the PurchLine table. The quantity on hand should increase by the difference
between the new purchase quantity and the old purchase quantity. Write a script to
test the trigger.
ROLLBACK;
26. Write a trigger to propagate updates to the Product table after delete operations on
the PurchLine table. The quantity on hand should increase by the old purchase
quantity. Write a script to test the trigger.
27. Write a trigger to propagate updates to the Product table updates to the to the
ProdNo column of the PurchLine table. The quantity on hand of the old product
should decrease while the quantity on hand of the new product should increase.
Write a script to test the trigger.
28. Suppose that you have an UPDATE statement that changes both the ProdNo column
and the PurchQty column of the PurchLine table. What triggers (that you wrote in
previous problems) fire for such an UPDATE statement? If more tha n one trigger
fires, why do the triggers overlap and what is the firing order? Modify the
overlapping triggers and prepare a test script so that you can determine the firing
order. Does the Oracle trigger execution procedure guarantee the firing order?
Ans: The triggers in problems 25 and 27 overlap because they have the same timing,
granularity, and applicable table and an UPDATE statement involving both columns
causes both triggers to fire. The firing order is arbitrary because the triggers overlap. To
see the firing order, display statements have been added to the triggers to see the triggers
that fire for the UPDATE statement below. When running the UPDATE statement on
Oracle 8.1.7, the ProdNo trigger executes before the PurchQty trigger.
29. For the UPDATE statement in problem 28, do the triggers that you created in
previous problems work correctly? Write a script to test your triggers for such an
UPDATE statement. If the triggers do not work correctly, rewrite them so that they
work correctly for an UPDATE statement on both columns as well as UPDATE
statements on the individual columns. Write a script to test the revised triggers.
Hint: you need to specify the column in the UPDATING keyword in the trigger
body. For example, you can specify UPDATING(‘PurchQty’) to check if the
PurchQty is being updated.
Ans: The triggers do not work correctly. The qoh of the new product number is updated
twice. The PurchQty trigger should not fire when an UPDATE statement modifies both
columns. To handle all three cases (UPDATE statements modifying just one column and
UPDATE statements modifying both columns), the two triggers are combined. The
combined trigger determines whether one or both columns are updated.
ROLLBACK;
30. Can you devise another solution to the problem of UPDATE statements that change
both ProdNo and PurchQty? Is it reasonable to support such UPDATE statements in
online applications?