Database ProgrammingUnit 711 min read
PL/SQL Triggers: Row/Statement, BEFORE/AFTER, and Real-Time Logic
Unit 7 of Database Programming: Explores PL/SQL triggers—automated actions tied to database events—with syntax, execution timing (row vs. statement, before vs. after), practical examples, and debugging tips, including how banks and e-commerce use them for fraud detection and order validation.
TAKEAWAYS:
- Triggers are event-driven PL/SQL blocks that execute automatically when a DML (INSERT/UPDATE/DELETE) or DDL (CREATE/ALTER) event occurs.
- Row-level triggers fire once per row affected; statement-level triggers fire once per statement, enabling batch processing optimizations.
- BEFORE triggers validate data (e.g., check salary before updating), while AFTER triggers enforce post-action logic (e.g., log changes).
- Real-world use: eSewa uses triggers to auto-debit fees when transactions exceed limits; Daraz triggers update inventory after order confirmations.
- Triggers avoid application code redundancy but can complicate debugging if overused.
- Always test triggers with INSERT/UPDATE/DELETE statements to verify timing (BEFORE/AFTER).
1. What Is a Trigger?
A trigger is a stored PL/SQL procedure that executes automatically in response to a database event (e.g., inserting a record). It acts like a guardian for data integrity, enforcing rules without manual intervention.
Key Characteristics
Why Use Triggers?
| Scenario | Trigger Advantage | Example |
|---|---|---|
| Data Validation | Enforce rules (e.g., salary > 0) | BEFORE UPDATE ON employees |
| Audit Logging | Auto-record changes (e.g., who deleted?) | AFTER DELETE ON orders |
| Cascading Actions | Update linked tables (e.g., deduct stock) | AFTER INSERT ON sales |
| Security | Restrict access (e.g., prevent negative balances) | BEFORE UPDATE ON accounts |
2. Trigger Syntax and Structure
A trigger has three mandatory components:
- Trigger Name (e.g.,
chk_salary) - Event (e.g.,
BEFORE UPDATE ON employees) - Trigger Body (PL/SQL code to execute)
Basic Syntax
CREATE [OR REPLACE] TRIGGER trigger_name
[BEFORE | AFTER] [INSERT | UPDATE | DELETE]
ON table_name
[FOR EACH ROW | WHEN (condition)]
DECLARE
-- Variables (optional)
BEGIN
-- PL/SQL logic
EXCEPTION
-- Error handling (optional)
END;
Example: Row-Level Trigger
Scenario: Auto-set a last_updated timestamp when an employee record is modified.
CREATE OR REPLACE TRIGGER set_employee_timestamp
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
:NEW.last_updated := SYSDATE;
END;
:NEWrefers to the new row (after update).:OLDrefers to the old row (before update, only forUPDATE/DELETE).
3. Row-Level vs. Statement-Level Triggers
| Feature | Row-Level Trigger | Statement-Level Trigger |
|---|---|---|
| Execution Frequency | Once per affected row | Once per DML statement |
| Access to Data | :NEW, :OLD pseudo-records |
Uses INSERTING, UPDATING, DELETING tables |
| Use Case | Row-specific logic (e.g., validation) | Batch processing (e.g., audit logs) |
| Performance | Slower (per-row overhead) | Faster (single execution) |
Example: Statement-Level Trigger
Scenario: Log all deletions to an audit_log table.
CREATE OR REPLACE TRIGGER log_deletions
AFTER DELETE ON products
BEGIN
INSERT INTO audit_log (action, table_name, record_id)
VALUES ('DELETE', 'products', :OLD.product_id);
END;
- Uses
INSERTING,UPDATING,DELETINGtables to check if the trigger fired.
4. BEFORE vs. AFTER Triggers
| Trigger Type | Execution Timing | Use Case | Example |
|---|---|---|---|
| BEFORE | Before the DML event | Validation (e.g., check constraints) | BEFORE UPDATE ON accounts |
| AFTER | After the DML event | Post-processing (e.g., logging) | AFTER INSERT ON orders |
Worked Example: BEFORE Trigger for Salary Validation
Scenario: Prevent negative salaries in the employees table.
CREATE OR REPLACE TRIGGER chk_salary_negative
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
IF :NEW.salary < 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Salary cannot be negative!');
END IF;
END;
Test Case:
UPDATE employees SET salary = -5000 WHERE emp_id = 101;
Output:
ORA-20001: Salary cannot be negative!
Worked Example: AFTER Trigger for Inventory Update
Scenario: Auto-deduct stock when an order is placed (simulating Daraz’s inventory system).
CREATE OR REPLACE TRIGGER update_inventory_after_order
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
UPDATE products
SET stock_quantity = stock_quantity - :NEW.quantity
WHERE product_id = :NEW.product_id;
END;
Test Case:
INSERT INTO orders (order_id, product_id, quantity)
VALUES (1001, 501, 3);
Result: Stock for product 501 decreases by 3.
5. Trigger Events and Timing
Triggers can fire on:
- DML Events:
INSERT,UPDATE,DELETE - DDL Events:
CREATE,ALTER,DROP(requiresSYSDATEorDUMPfunctions) - Statement Events:
INSERTING,UPDATING,DELETING(for statement-level triggers)
sequenceDiagram
participant User
participant DB
participant BEFORE_Trigger
participant AFTER_Trigger
User->>DB: INSERT INTO orders (product_id, quantity)
DB->>BEFORE_Trigger: Execute (e.g., validate stock)
BEFORE_Trigger-->>DB: Allow/Reject
DB->>AFTER_Trigger: Execute (e.g., update inventory)
AFTER_Trigger-->>DB: Confirm
DB-->>User: Success/FailureBEFORE/AFTER trigger sequence for an order insertion (e.g., Daraz inventory system).Trigger Execution Flow
sequenceDiagram
participant User
participant DB
participant Trigger
User->>DB: UPDATE employees SET salary = 5000 WHERE emp_id = 101
DB->>Trigger: Execute BEFORE UPDATE trigger (chk_salary_negative)
alt Salary valid
Trigger->>DB: Allow update
else Salary invalid
Trigger->>DB: RAISE_ERROR
end
DB->>Trigger: Execute AFTER UPDATE trigger (set_employee_timestamp)
DB->>User: Confirm update6. Real-World Applications
## In the real world
eSewa Fraud Prevention
- Idea: AFTER INSERT trigger on
transactionstable to check if the transaction amount exceeds the user’s daily limit. - How: If
:NEW.amount > :OLD.daily_limit, the trigger rolls back the transaction and sends an alert. - Example: A user tries to transfer ₹50,000 (daily limit: ₹20,000). The trigger blocks it and notifies support.
- Idea: AFTER INSERT trigger on
Daraz Order Validation
- Idea: BEFORE INSERT trigger on
ordersto ensure stock availability. - How: Before inserting an order, the trigger checks
stock_quantityin theproductstable. If insufficient, it rejects the order. - Example: A customer orders 10 units of a product with only 5 in stock. The trigger prevents the order and suggests alternatives.
- Idea: BEFORE INSERT trigger on
NEPSE Stock Market
- Idea: AFTER UPDATE trigger on
tradesto auto-update theportfoliotable for investors. - How: When a stock price changes, the trigger recalculates the investor’s holdings and updates their portfolio value.
- Example: If a stock’s price drops, the trigger adjusts the investor’s net worth in real time.
- Idea: AFTER UPDATE trigger on
7. Trigger Limitations and Best Practices
Advantages
- Automation: No need for application code to enforce rules.
- Data Integrity: Ensures constraints are met at the database level.
- Audit Trails: Logs changes automatically.
Disadvantages
- Debugging Complexity: Triggers can create "spaghetti code" if overused.
- Performance Overhead: Row-level triggers slow down large DML operations.
- Version Control: Harder to manage than application logic.
Best Practices
- Keep Triggers Simple: Avoid complex logic; move it to stored procedures if needed.
- Use Comments: Document the purpose of each trigger.
- Test Thoroughly: Test with
INSERT,UPDATE, andDELETEstatements. - Avoid Cascading Triggers: Multiple triggers on the same event can cause unexpected behavior.
- Use
PRAGMA AUTONOMOUS_TRANSACTION: For triggers that need to commit independently (e.g., sending emails).
8. Debugging Triggers
Common Issues and Fixes
| Issue | Cause | Solution |
|---|---|---|
| Trigger not firing | Incorrect event (e.g., BEFORE vs. AFTER) |
Verify trigger syntax. |
| Infinite recursion | Trigger calls the same table | Use NOCOMPUTE or refactor logic. |
| Performance lag | Row-level trigger on large tables | Consider statement-level or batch processing. |
| Error: "ORA-04091: trigger fire" | Trigger modifies data it depends on | Use PRAGMA AUTONOMOUS_TRANSACTION. |
Debugging Steps
- Check Trigger Syntax:
SHOW TRIGGERS; - Test Manually:
INSERT INTO employees (emp_id, name, salary) VALUES (102, 'Alice', 45000); - Enable SQL Trace (for advanced debugging):
ALTER SYSTEM SET sql_trace = true;
9. Exam Tip
- Focus on Syntax: Know the exact structure of
CREATE TRIGGERfor row/statement and BEFORE/AFTER. - Compare Row vs. Statement: Understand when to use each (e.g., row for validation, statement for logging).
- Practice Timing: Write triggers that fire before (validation) and after (logging) events.
- Real-World Link: Relate triggers to eSewa fraud checks, Daraz stock updates, or NEPSE portfolio adjustments.
- Common Pitfalls: Avoid infinite recursion; test with edge cases (e.g.,
NULLvalues). - Short Answer Tip: For "differentiate between anonymous and named blocks," mention that triggers are named blocks tied to events, while anonymous blocks are one-time scripts.
In the real world
- eSewa: Uses AFTER INSERT triggers on transactions to auto-debit fees when amounts exceed user limits (e.g., ₹50,000 > ₹20,000 daily cap).
- Daraz: AFTER INSERT triggers on orders deduct stock from
productstable (e.g.,UPDATE products SET stock = stock - :NEW.quantity). - Nepal Rastra Bank (NRB): BEFORE UPDATE triggers validate loan applications (e.g.,
IF :NEW.loan_amount > :OLD.max_limit THEN RAISE_ERROR).
Based on the TU BCA syllabus for Database Programming (CACS484), unit 7.
Discussion
Loading…