Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 All Powder Board and Ski Oracle 9i Workbook Chapter 7: Integrity and Transactions Jerry Post Copyright © 2003.

Similar presentations


Presentation on theme: "1 All Powder Board and Ski Oracle 9i Workbook Chapter 7: Integrity and Transactions Jerry Post Copyright © 2003."— Presentation transcript:

1 1 All Powder Board and Ski Oracle 9i Workbook Chapter 7: Integrity and Transactions Jerry Post Copyright © 2003

2 2 Compute Sales Tax Sales Tax From Figure 6.29

3 3 Create Oracle Package and Function The slash is required to separate the commands Package definition Package body Function definition

4 4 Test the Function in SQL Dual is a tiny system table used for testing because it has one column and one row Package name Function name Correct result: 7 percent of 500

5 5 Add Event Code to the Sales Form Choose the PRE-TEXT- ITEM event Call the new function

6 6 Debugging Double click to set breakpoint Debug/Debug Module Debug/Step Into See form and variable values with Debug/Debug Windows

7 7 Inventory Database Triggers Sale(SaleID, CustomerID, EmployeeID, SaleDate, …) SaleItem(SaleID, SKU, QuantitySold, SalePrice) Inventory(SKU, QuantityOnHand, …) If a new item is sold, subtract QuantitySold from QuantityOnHand Complications: changes to the data A SaleItem is revoked, the SaleItem row deleted The QuantitySold is changed The SKU is changed Sample values: SaleID=3000SKU=500000 or 500010 CustomerID=582EmployeeID=5

8 8 Database Event Triggers DELETE BEFOREINSERTAFTER UPDATE CREATE OR REPLACE TRIGGER NewSaleQOH AFTER INSERT ON SaleItem FOR EACH ROW BEGIN UPDATE INVENTORY SET QuantityOnHand = QuantityOnHand - :NEW.QuantitySold WHERE SKU = :NEW.SKU; END; New/inserted value

9 9 Setup Example INSERT INTO Sale (SaleID, CustomerID, EmployeeID) VALUES (3000, 582, 5); SELECT SKU, QuantityOnHand FROM Inventory WHERE SKU=500000; INSERT INTO SaleItem (SaleID, SKU, QuantitySold, SalePrice) VALUES (3000, 500000, 1, 100); Check the QuantityOnHand before and after the INSERT

10 10 Potential Problem: Delete Row DELETE FROM SaleItem WHERE SaleID=3000 And SKU=500000; Check the QuantityOnHand before and after the DELETE The value does not change! CREATE OR REPLACE TRIGGER DelSaleQOH AFTER DELETE ON SaleItem FOR EACH ROW BEGIN UPDATE INVENTORY SET QuantityOnHand = QuantityOnHand + :OLD.QuantitySold WHERE SKU = :OLD.SKU; END; Restore the deleted quantity

11 11 Problems What if the clerk entered the wrong value and should have entered 1 instead of 2 units? Test it, and the code subtracts 1 from the QOH, leaving 7. You need to add the original 2 units back. QuantityOnHand = QuantityOnHand – QuantitySold + OldQuantity

12 12 Problem: Change the Quantity CREATE or REPLACE TRIGGER ChangeSaleQOH AFTER UPDATE ON SaleItem FOR EACH ROW BEGIN UPDATE Inventory SET QuantityOnHand = QuantityOnHand + :OLD.QuantitySold - :NEW.QuantitySold WHERE SKU = :OLD.SKU; END; UPDATE SaleITem SET QuantitySold = 2 WHERE SaleID=3000 And SKU=500000; Test it Test it again Add back the old quantity (1) and subtract the new value (2)

13 13 Problem: Change the SKU UPDATE SaleITem SET QuantitySold = 3, SKU = 500010 WHERE SaleID=3000 And SKU=500000; Test it by changing both QuantitySold and SKU SELECT SKU, QuantityOnHand FROM Inventory WHERE SKU=500000 Or SKU=500010; SELECT SKU, QuantityOnHand FROM Inventory WHERE SKU=500000 Or SKU=500010;

14 14 Trigger to Handle SKU Changes CREATE or REPLACE TRIGGER ChangeSaleQOH AFTER UPDATE ON SaleItem FOR EACH ROW BEGIN IF (:OLD.SKU = :NEW.SKU) THEN UPDATE Inventory SET QuantityOnHand = QuantityOnHand + :OLD.QuantitySold - :NEW.QuantitySold WHERE SKU = :OLD.SKU; ELSE UPDATE Inventory SET QuantityOnHand = QuantityOnHand + :OLD.QuantitySold WHERE SKU = :OLD.SKU; UPDATE Inventory SET QuantityOnHand = QuantityOnHand - :NEW.QuantitySold WHERE SKU = :NEW.SKU; END IF; END; Test it again

15 15 Transactions for Discounts New table

16 16 Rental Form Button to open discount form

17 17 Rental Discount Form RentID and Amount are determined by the Rental form Date default value is set to $$DATETIME$$ This is an unbound form built from design view with no Data Block source

18 18 Rental Form Code: Discount Button :global.RentID := :Rental.RentID; :global.Amount := :Rental.SubCharges; Call_Form('D:\Students\AllPowder\GiveRentDiscount'); Save the RentID and total repair charges into global variables that can be retrieved by the discount form when it starts. Rental Form, Button to open Discount form Trigger event: WHEN-BUTTON-PRESS

19 19 Discount Form Triggers :RentalID := :global.RentID; :Amount := :global.Amount; Form: WHEN-NEW-FORM-INSTANCE UPDATE RentItem SET RepairCharges=0 WHERE RentID = :RentalID; INSERT INTO RentalDiscount(RentID, DiscountDate, DiscountAmount, Reason) VALUES (:RentalID, :TransDate, :Amount, :Reason); Commit; :txtMessage := 'Changes recorded.'; Button: WHEN-BUTTON-PRESSED

20 20 Transaction Code BEGIN UPDATE RentItem SET RepairCharges=0 WHERE RentID = :RentalID; INSERT INTO RentalDiscount(RentID, DiscountDate, DiscountAmount, Reason) VALUES (:RentalID, :TransDate, :Amount, :Reason); Commit; :txtMessage := 'Changes recorded.'; EXCEPTION WHEN OTHERS THEN Rollback; END; WHEN- BUTTON- PRESSED If something goes wrong, cancel the first update

21 21 Query for Cursor: Weekly Sales CREATE VIEW WeeklySales AS SELECT TO_CHAR(SaleDate, 'ww') AS SalesWeek, Sum(SalePrice*QuantitySold) AS Value FROM Sale INNER JOIN SaleItem ON Sale.SaleID=SaleItem.SaleID WHERE SaleDate Is Not Null GROUP BY TO_CHAR(SaleDate, 'ww');

22 22 Set up Package to Compute Average CREATE OR REPLACE PACKAGE SalesAnalysis AS FUNCTION AvgPercentWeeklyChange return REAL; END SalesAnalysis; / CREATE or REPLACE PACKAGE BODY SalesAnalysis AS FUNCTION AvgPercentWeeklyChange return REAL IS CURSOR c1 IS SELECT SalesWeek, Value FROM WeeklySales; Avg1 REAL; N Integer; PriorValue WeeklySales.Value%TYPE; Define the SELECT statement for the cursor to trace through Create variable to hold the value from the previous row with the same data type as the column in the table

23 23 Code to Compute Average Change BEGIN Avg1 := 0; N := 0; PriorValue := -1; FOR recSales in c1 LOOP IF PriorValue > 0 THEN Avg1 := Avg1 + (recSales.Value - PriorValue)/PriorValue; N := N + 1; END IF; PriorValue := recSales.Value; END LOOP; RETURN (Avg1/N); END AvgPercentWeeklyChange; END SalesAnalysis; / Skip the first week because there is no prior value Compute the percent change and keep a running total Save the current row value and move to the next row

24 24 A Sequence for the Sale Table CREATE SEQUENCE seq_Sale INCREMENT BY 1 START WITH 10000 NOMAXVALUE NOCYCLE CACHE 10; Start at a high number to avoid collisions with existing data

25 25 Trigger to Generate Key CREATE OR REPLACE TRIGGER GenKeyForSale BEFORE INSERT ON Sale FOR EACH ROW BEGIN SELECT seq_Sale.NEXTVAL INTO :NEW.SaleID FROM dual; END; / Automatically generate and use a new key value for SaleID whenever a row is added to the Sale table Generate next valueUse it as the new SaleID

26 26 Test the Key Generator INSERT INTO Sale (CustomerID, EmployeeID) VALUES (582, 5); SELECT seq_Sale.CURRVAL FROM dual; SELECT * FROM Sale WHERE SaleID=10000; Insert a row into Sale without specifying a SaleID See what key value was generated Retrieve the sales data to ensure the row was created

27 27 Keys: Create Sales and Items (barcode) Customer ID card is scanned Create new sale Scan an item Save sale item, update QOH and totals Repeat until done (payment key) Get SaleID Save SaleID, SKU, Quantity

28 28 Generate Sale Form IDs and SKU would be scanned, but to test code, set default values

29 29 Concurrency and Lock Test Form

30 30 PL/SQL to Change ZIP Code BEGIN UPDATE Customer SET ZIP = :ZIPCode WHERE CustomerID = :CustomerID; Commit; END;

31 31 Customer List Form

32 32 Read Consistent Lock on the Form Open both forms and use the testing form to change the ZIP code for CustomerID=1 Error message that value was changed Return here and try to change the ZIP code

33 33 Stronger Lock on the Test Form DECLARE concurrency_hit EXCEPTION; PRAGMA EXCEPTION_INIT(concurrency_hit, -8177); BEGIN SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; UPDATE Customer SET ZIP = :ZIPCode WHERE CustomerID = :CustomerID; Commit; EXCEPTION WHEN concurrency_hit THEN message ('Data has been changed by another process.'); WHEN OTHERS THEN message ('Unknown error.'); END; Name the concurrency error Set strongest isolation level Catch error raised by this update interrupting another one Notify user who can decide to try again or exit

34 34 Serializable Isolation Level The change is not made and the error is trapped because the row is locked


Download ppt "1 All Powder Board and Ski Oracle 9i Workbook Chapter 7: Integrity and Transactions Jerry Post Copyright © 2003."

Similar presentations


Ads by Google