1 All Powder Board and Ski Oracle 9i Workbook Chapter 7: Integrity and Transactions Jerry Post...
-
Upload
jemima-phillips -
Category
Documents
-
view
221 -
download
4
Transcript of 1 All Powder Board and Ski Oracle 9i Workbook Chapter 7: Integrity and Transactions Jerry Post...
1
All Powder Board and Ski
Oracle 9i WorkbookChapter 7: Integrity and TransactionsJerry PostCopyright © 2003
2
Compute Sales Tax
Sales Tax
From Figure 6.29
3
Create Oracle Package and Function
The slash is required to separate the commands
Package definition
Package body
Function definition
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
Add Event Code to the Sales Form
Choose the PRE-TEXT-ITEM event
Call the new function
6
Debugging
Double click to set breakpoint
Debug/Debug ModuleDebug/Step Into
See form and variable values with Debug/Debug Windows
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 QuantityOnHandComplications: changes to the data
A SaleItem is revoked, the SaleItem row deletedThe QuantitySold is changedThe SKU is changed
Sample values:SaleID=3000 SKU=500000 or 500010CustomerID=582 EmployeeID=5
8
Database Event Triggers
DELETE
BEFORE INSERT AFTER
UPDATE
CREATE OR REPLACE TRIGGER NewSaleQOHAFTER INSERT ON SaleItemFOR EACH ROW
BEGINUPDATE INVENTORY SET QuantityOnHand = QuantityOnHand - :NEW.QuantitySold WHERE SKU = :NEW.SKU;
END;
New/inserted value
9
Setup Example
INSERT INTO Sale (SaleID, CustomerID, EmployeeID)VALUES (3000, 582, 5);
SELECT SKU, QuantityOnHandFROM InventoryWHERE SKU=500000;
INSERT INTO SaleItem (SaleID, SKU, QuantitySold, SalePrice)VALUES (3000, 500000, 1, 100);
Check the QuantityOnHand before and after the INSERT
10
Potential Problem: Delete Row
DELETE FROM SaleItemWHERE SaleID=3000 And SKU=500000;
Check the QuantityOnHand before and after the DELETEThe value does not change!
CREATE OR REPLACE TRIGGER DelSaleQOHAFTER DELETE ON SaleItemFOR EACH ROW
BEGINUPDATE INVENTORY SET QuantityOnHand = QuantityOnHand + :OLD.QuantitySold WHERE SKU = :OLD.SKU;
END;
Restore the deleted quantity
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
Problem: Change the Quantity
CREATE or REPLACE TRIGGER ChangeSaleQOHAFTER UPDATE ON SaleItemFOR EACH ROW
BEGINUPDATE Inventory SET QuantityOnHand = QuantityOnHand
+ :OLD.QuantitySold - :NEW.QuantitySoldWHERE SKU = :OLD.SKU;
END;
UPDATE SaleITemSET QuantitySold = 2WHERE SaleID=3000 And SKU=500000;
Test it
Test it again
Add back the old quantity (1) and subtract the new value (2)
13
Problem: Change the SKU
UPDATE SaleITemSET QuantitySold = 3, SKU = 500010WHERE SaleID=3000 And SKU=500000;
Test it by changing both QuantitySold and SKU
SELECT SKU, QuantityOnHandFROM InventoryWHERE SKU=500000 Or SKU=500010;
SELECT SKU, QuantityOnHandFROM InventoryWHERE SKU=500000 Or SKU=500010;
14
Trigger to Handle SKU Changes
CREATE or REPLACE TRIGGER ChangeSaleQOHAFTER UPDATE ON SaleItemFOR EACH ROW
BEGINIF (:OLD.SKU = :NEW.SKU) THEN
UPDATE Inventory SET QuantityOnHand = QuantityOnHand
+ :OLD.QuantitySold - :NEW.QuantitySoldWHERE SKU = :OLD.SKU;
ELSEUPDATE InventorySET QuantityOnHand = QuantityOnHand + :OLD.QuantitySoldWHERE SKU = :OLD.SKU;UPDATE InventorySET QuantityOnHand = QuantityOnHand - :NEW.QuantitySoldWHERE SKU = :NEW.SKU;
END IF;END; Test it again
15
Transactions for Discounts
New table
16
Rental Form
Button to open discount form
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
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
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
Transaction Code
BEGINUPDATE RentItem SET RepairCharges=0 WHERE RentID = :RentalID;
INSERT INTO RentalDiscount(RentID, DiscountDate, DiscountAmount, Reason)
VALUES (:RentalID, :TransDate, :Amount, :Reason);Commit;:txtMessage := 'Changes recorded.';
EXCEPTIONWHEN OTHERS THENRollback;
END;
WHEN-BUTTON-PRESSED
If something goes wrong, cancel the first update
21
Query for Cursor: Weekly Sales
CREATE VIEW WeeklySales ASSELECT TO_CHAR(SaleDate, 'ww') AS SalesWeek,
Sum(SalePrice*QuantitySold) AS ValueFROM Sale INNER JOIN SaleItem ON Sale.SaleID=SaleItem.SaleIDWHERE SaleDate Is Not NullGROUP BY TO_CHAR(SaleDate, 'ww');
22
Set up Package to Compute Average
CREATE OR REPLACE PACKAGE SalesAnalysis ASFUNCTION AvgPercentWeeklyChange return REAL;
END SalesAnalysis;/CREATE or REPLACE PACKAGE BODY SalesAnalysis AS
FUNCTION AvgPercentWeeklyChange return REAL ISCURSOR c1 IS
SELECT SalesWeek, Value FROM WeeklySales;Avg1 REAL;N Integer;PriorValue WeeklySales.Value%TYPE;
Define the SELECT statement for the cursor to trace throughCreate variable to hold the
value from the previous row with the same data type as the column in the table
23
Code to Compute Average Change
BEGINAvg1 := 0;N := 0;PriorValue := -1;FOR recSales in c1 LOOP
IF PriorValue > 0 THENAvg1 := 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
A Sequence for the Sale Table
CREATE SEQUENCE seq_SaleINCREMENT BY 1START WITH 10000NOMAXVALUENOCYCLECACHE 10;
Start at a high number to avoid collisions with existing data
25
Trigger to Generate Key
CREATE OR REPLACE TRIGGER GenKeyForSaleBEFORE INSERT ON SaleFOR EACH ROW
BEGINSELECT 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 value Use it as the new SaleID
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
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
Generate Sale Form
IDs and SKU would be scanned, but to test code, set default values
29
Concurrency and Lock Test Form
30
PL/SQL to Change ZIP Code
BEGINUPDATE CustomerSET ZIP = :ZIPCodeWHERE CustomerID = :CustomerID;Commit;
END;
31
Customer List Form
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
Stronger Lock on the Test Form
DECLAREconcurrency_hit EXCEPTION;PRAGMA EXCEPTION_INIT(concurrency_hit, -8177);
BEGINSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
UPDATE CustomerSET ZIP = :ZIPCodeWHERE CustomerID = :CustomerID;Commit;
EXCEPTIONWHEN 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
Serializable Isolation Level
The change is not made and the error is trapped because the row is locked