Solution a) Compute male and female students by semester and section
sql
SELECT subj.Sem,
SUM(CASE WHEN s.Gender = 'M' THEN 1 ELSE 0 END) AS Male_Count,
SUM(CASE WHEN s.Gender = 'F' THEN 1 ELSE 0 END) AS Female_Count
FROM STUDENT s
JOIN MARKS m ON s.RegNo = m.RegNo
JOIN SUBJECT subj ON m.Subcode = subj.Subcode
GROUP BY subj.Sem
ORDER BY subj.Sem;
Solution b) Calculate Finalmark and update table
sql
UPDATE MARKS m
SET Finalmark = (
SELECT (x + y) / 2
FROM (
SELECT RegNo, Subcode,
GREATEST(
GREATEST(Test1, Test2),
GREATEST(Test2, Test3),
GREATEST(Test1, Test3)
) AS x,
CASE
WHEN Test1 <= Test2 AND Test1 <= Test3 THEN (Test2 + Test3) / 2
WHEN Test2 <= Test1 AND Test2 <= Test3 THEN (Test1 + Test3) / 2
ELSE (Test1 + Test2) / 2
END AS y
FROM MARKS
) t
WHERE t.RegNo = m.RegNo AND t.Subcode = m.Subcode
);
Solution c) Categorize students based on Finalmark
sql
SELECT m.RegNo, s.StudName, m.Subcode, m.Finalmark,
CASE
WHEN m.Finalmark BETWEEN 81 AND 100 THEN 'Outstanding'
WHEN m.Finalmark BETWEEN 51 AND 80 THEN 'Average'
WHEN m.Finalmark < 51 THEN 'Weak'
END AS CAT
FROM MARKS m
JOIN STUDENT s ON m.RegNo = s.RegNo
ORDER BY m.RegNo, m.Subcode;
Solution d) Create a view of Test3 marks
sql
CREATE OR REPLACE VIEW Student_Test3_Marks AS
SELECT s.RegNo, s.StudName, sub.Subcode, sub.Title, m.Test3
FROM STUDENT s
JOIN MARKS m ON s.RegNo = m.RegNo
JOIN SUBJECT sub ON m.Subcode = sub.Subcode
WHERE s.RegNo = 'S001'; -- Replace with parameter in actual implementation
Solution e) Procedure for the College Database
sql
CREATE OR REPLACE PROCEDURE get_student_performance(p_regno VARCHAR2) IS
v_student_name STUDENT.StudName%TYPE;
v_total_credits NUMBER := 0;
v_weighted_sum NUMBER := 0;
v_gpa NUMBER;
BEGIN
-- Get student name
SELECT StudName INTO v_student_name
FROM STUDENT
WHERE RegNo = p_regno;
DBMS_OUTPUT.PUT_LINE('Performance Report for: ' || v_student_name || ' (' || p_regno || ')'
DBMS_OUTPUT.PUT_LINE('--------------------------------------------');
-- Display course performance
FOR course_rec IN (
SELECT sub.Subcode, sub.Title, sub.Credits, m.Finalmark,
CASE
WHEN m.Finalmark BETWEEN 81 AND 100 THEN 'Outstanding'
WHEN m.Finalmark BETWEEN 51 AND 80 THEN 'Average'
WHEN m.Finalmark < 51 THEN 'Weak'
END AS Category
FROM MARKS m
JOIN SUBJECT sub ON m.Subcode = sub.Subcode
WHERE m.RegNo = p_regno
ORDER BY sub.Sem, sub.Subcode
) LOOP
DBMS_OUTPUT.PUT_LINE(course_rec.Subcode || ' - ' || course_rec.Title);
DBMS_OUTPUT.PUT_LINE(' Marks: ' || course_rec.Finalmark ||
', Category: ' || course_rec.Category);
-- Calculate weighted sum for GPA
v_weighted_sum := v_weighted_sum + (course_rec.Finalmark/20) * course_rec.Credits;
v_total_credits := v_total_credits + course_rec.Credits;
END LOOP;
-- Calculate GPA (on a 5.0 scale)
IF v_total_credits > 0 THEN
v_gpa := v_weighted_sum / v_total_credits;
DBMS_OUTPUT.PUT_LINE('--------------------------------------------');
DBMS_OUTPUT.PUT_LINE('Overall GPA: ' || TO_CHAR(v_gpa, '9.99'));
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Student with ID ' || p_regno || ' not found.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
/
-- Execute the procedure
EXEC get_student_performance('S001');
8. Bank Table
Table Creation
sql
CREATE TABLE Bank (
S_No NUMBER PRIMARY KEY,
Cust_Name VARCHAR2(100) NOT NULL,
Acc_No VARCHAR2(20) UNIQUE NOT NULL,
Balance NUMBER(12,2) DEFAULT 0,
Branch VARCHAR2(50)
);
-- Insert sample data
INSERT INTO Bank VALUES (1, 'John Smith', 'AC001', 5000.00, 'Main Branch');
INSERT INTO Bank VALUES (2, 'Jane Doe', 'AC002', 7500.50, 'North Branch');
INSERT INTO Bank VALUES (3, 'Robert Johnson', 'AC003', 12000.75, 'Main Branch');
INSERT INTO Bank VALUES (4, 'Emily Davis', 'AC004', 950.25, 'South Branch');
INSERT INTO Bank VALUES (5, 'Michael Wilson', 'AC005', 3500.00, 'West Branch');
Solution a) Select with where clause
sql
SELECT * FROM Bank WHERE Branch = 'Main Branch';
Solution b) Select with comparison operator
sql
SELECT Cust_Name, Acc_No, Balance
FROM Bank
WHERE Balance > 5000;
Solution c) Update balance in second row
sql
UPDATE Bank SET Balance = 8000.00 WHERE S_No = 2;
Solution d) Select with between in the field balance
sql
SELECT * FROM Bank WHERE Balance BETWEEN 1000 AND 10000;
Solution e) Trigger when balance is below 1000
sql
CREATE OR REPLACE TRIGGER low_balance_trigger
AFTER INSERT OR UPDATE OF Balance ON Bank
FOR EACH ROW
BEGIN
IF :NEW.Balance < 1000 THEN
DBMS_OUTPUT.PUT_LINE('WARNING: Account ' || :NEW.Acc_No ||
' for customer ' || :NEW.Cust_Name ||
' has low balance: ' || :NEW.Balance);
END IF;
END;
/
-- Test the trigger
UPDATE Bank SET Balance = 800 WHERE S_No = 4;
9. Account Table
Table Creation
sql
CREATE TABLE Account (
Account_No VARCHAR2(20) PRIMARY KEY,
Cust_Name VARCHAR2(100) NOT NULL,
Branch_Name VARCHAR2(50),
Account_Balance NUMBER(12,2) DEFAULT 0,
Account_Type VARCHAR2(20) CHECK (Account_Type IN ('Savings', 'Current', 'Fixed'))
);
-- Insert sample data
INSERT INTO Account VALUES ('AC001', 'John Smith', 'Main Branch', 5000.00, 'Savings');
INSERT INTO Account VALUES ('AC002', 'Jane Doe', 'North Branch', 12000.50, 'Current');
INSERT INTO Account VALUES ('AC003', 'Robert Johnson', 'Main Branch', 3500.75, 'Savings');
INSERT INTO Account VALUES ('AC004', 'Emily Davis', 'South Branch', 25000.25, 'Fixed');
INSERT INTO Account VALUES ('AC005', 'Michael Wilson', 'North Branch', 800.00, 'Savings');
Solution a) Display customers of specific branch
sql
SELECT Cust_Name, Account_No
FROM Account
WHERE Branch_Name = 'Main Branch';
Solution b) Display customers with balance > 10000
sql
SELECT Cust_Name, Account_Type
FROM Account
WHERE Account_Balance > 10000;
Solution c) Add column Cust_Date_of_Birth
sql
ALTER TABLE Account ADD Cust_Date_of_Birth DATE;
Solution d) Display customers with balance < 1000
sql
SELECT Account_No, Cust_Name, Branch_Name
FROM Account
WHERE Account_Balance < 1000;
Solution e) Procedure for the Account Database
sql
CREATE OR REPLACE PROCEDURE get_account_summary(p_branch VARCHAR2 DEFAULT NULL) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Account Summary Report');
DBMS_OUTPUT.PUT_LINE('--------------------');
IF p_branch IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('Branch: ' || p_branch);
ELSE
DBMS_OUTPUT.PUT_LINE('All Branches');
END IF;
DBMS_OUTPUT.PUT_LINE('--------------------');
-- Branch statistics
FOR branch_rec IN (
SELECT Branch_Name,
COUNT(*) AS Num_Accounts,
SUM(Account_Balance) AS Total_Balance,
AVG(Account_Balance) AS Avg_Balance
FROM Account
WHERE p_branch IS NULL OR Branch_Name = p_branch
GROUP BY Branch_Name
ORDER BY Branch_Name
) LOOP
DBMS_OUTPUT.PUT_LINE('Branch: ' || branch_rec.Branch_Name);
DBMS_OUTPUT.PUT_LINE(' Number of Accounts: ' || branch_rec.Num_Accounts);
DBMS_OUTPUT.PUT_LINE(' Total Balance: ' || TO_CHAR(branch_rec.Total_Balance, '$999,999
DBMS_OUTPUT.PUT_LINE(' Average Balance: ' || TO_CHAR(branch_rec.Avg_Balance, '$999,999
DBMS_OUTPUT.PUT_LINE('--------------------');
END LOOP;
-- Account type statistics
FOR type_rec IN (
SELECT Account_Type, COUNT(*) AS Num_Accounts
FROM Account
WHERE p_branch IS NULL OR Branch_Name = p_branch
GROUP BY Account_Type
ORDER BY Account_Type
) LOOP
DBMS_OUTPUT.PUT_LINE('Account Type: ' || type_rec.Account_Type);
DBMS_OUTPUT.PUT_LINE(' Number of Accounts: ' || type_rec.Num_Accounts);
DBMS_OUTPUT.PUT_LINE('--------------------');
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
/
-- Execute the procedure
EXEC get_account_summary();
EXEC get_account_summary('Main Branch');
10. Customer and Order System
Table Creation
sql
CREATE TABLE CUSTOMER (
C_ID NUMBER PRIMARY KEY,
Name VARCHAR2(100) NOT NULL,
Address VARCHAR2(200),
City VARCHAR2(50),
Mobile_No VARCHAR2(20)
);
CREATE TABLE ORDER_TABLE (
C_ID NUMBER,
P_ID NUMBER,
P_Name VARCHAR2(100),
P_COST NUMBER(10,2),
PRIMARY KEY (C_ID, P_ID),
FOREIGN KEY (C_ID) REFERENCES CUSTOMER(C_ID)
);
-- Insert sample data
INSERT INTO CUSTOMER VALUES (1, 'John Smith', '123 Main St', 'New York', '555-1234');
INSERT INTO CUSTOMER VALUES (2, 'Jane Doe', '456 Oak Ave', 'Chicago', '555-5678');
INSERT INTO CUSTOMER VALUES (3, 'Robert Johnson', '789 Pine Rd', 'Los Angeles', '555-9012');
INSERT INTO CUSTOMER VALUES (4, 'Emily Davis', '321 Elm St', 'Delhi', '555-3456');
INSERT INTO CUSTOMER VALUES (5, 'Michael Wilson', '654 Maple Ln', 'Delhi', '555-7890');
INSERT INTO ORDER_TABLE VALUES (1, 101, 'Laptop', 1200.00);
INSERT INTO ORDER_TABLE VALUES (1, 102, 'Printer', 350.00);
INSERT INTO ORDER_TABLE VALUES (2, 103, 'Smartphone', 800.00);
INSERT INTO ORDER_TABLE VALUES (3, 104, 'Tablet', 600.00);
INSERT INTO ORDER_TABLE VALUES (3, 105, 'Monitor', 450.00);
INSERT INTO ORDER_TABLE VALUES (4, 106, 'Keyboard', 100.00);
INSERT INTO ORDER_TABLE VALUES (5, 107, 'External Hard Drive', 120.00);
INSERT INTO ORDER_TABLE VALUES (5, 108, 'Wireless Mouse', 50.00);
INSERT INTO ORDER_TABLE VALUES (5, 109, 'Smart Watch', 350.00);
Solution a) List customers who ordered products over 500
sql
SELECT c.Name, c.Address
FROM CUSTOMER c
JOIN ORDER_TABLE o ON c.C_ID = o.C_ID
WHERE o.P_COST > 500;
Solution b) List products with cost >= 1000
sql
SELECT P_Name
FROM ORDER_TABLE
WHERE P_COST >= 1000;
Solution c) List products ordered by customers from Delhi
sql
SELECT o.P_Name, o.P_COST
FROM ORDER_TABLE o
JOIN CUSTOMER c ON o.C_ID = c.C_ID
WHERE c.City = 'Delhi';
Solution d) Add Email_id column
sql
ALTER TABLE CUSTOMER ADD Email_id VARCHAR2(100);
Solution e) User defined function
sql
CREATE OR REPLACE FUNCTION calculate_total_order_value(p_c_id NUMBER)
RETURN NUMBER IS
v_total NUMBER := 0;
BEGIN
SELECT SUM(P_COST)
INTO v_total
FROM ORDER_TABLE
WHERE C_ID = p_c_id;
RETURN NVL(v_total, 0);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 0;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RETURN -1;
END;
/
-- Test the function
SET SERVEROUTPUT ON
DECLARE
v_customer_id NUMBER := 5;
v_total NUMBER;
BEGIN
v_total := calculate_total_order_value(v_customer_id);
DBMS_OUTPUT.PUT_LINE('Total order value for customer ' || v_customer_id || ': $' || v_total
END;
/
11. Salesman Database
Table Creation
sql
CREATE TABLE SALESMAN (
Salesman_id NUMBER PRIMARY KEY,
Name VARCHAR2(100) NOT NULL,
City VARCHAR2(50),
Commission NUMBER(5,2)
);
CREATE TABLE CUSTOMER (
Customer_id NUMBER PRIMARY KEY,
Cust_Name VARCHAR2(100) NOT NULL,
City VARCHAR2(50),
Grade NUMBER,
Salesman_id NUMBER,
FOREIGN KEY (Salesman_id) REFERENCES SALESMAN(Salesman_id) ON DELETE SET NULL
);
CREATE TABLE ORDERS (
Ord_No NUMBER PRIMARY KEY,
Purchase_Amt NUMBER(10,2),
Ord_Date DATE,
Customer_id NUMBER,
Salesman_id NUMBER,
FOREIGN KEY (Customer_id) REFERENCES CUSTOMER(Customer_id),
FOREIGN KEY (Salesman_id) REFERENCES SALESMAN(Salesman_id) ON DELETE CASCADE
);
-- Insert sample data
INSERT INTO SALESMAN VALUES (1000, 'John Smith', 'New York', 12.5);
INSERT INTO SALESMAN VALUES (1001, 'Jane Doe', 'Chicago', 10.0);
INSERT INTO SALESMAN VALUES (1002, 'Robert Johnson', 'Los Angeles', 8.5);
INSERT INTO SALESMAN VALUES (1003, 'Emily Davis', 'New York', 11.0);
INSERT INTO CUSTOMER VALUES (2000, 'Thomas Wilson', 'New York', 3, 1000);
INSERT INTO CUSTOMER VALUES (2001, 'Sarah Brown', 'Chicago', 2, 1001);
INSERT INTO CUSTOMER VALUES (2002, 'Michael Lee', 'Los Angeles', 1, 1002);
INSERT INTO CUSTOMER VALUES (2003, 'Jessica Clark', 'Chicago', 3, 1001);
INSERT INTO CUSTOMER VALUES (2004, 'David Taylor', 'New York', 2, 1000);
INSERT INTO CUSTOMER VALUES (2005, 'Jennifer White', 'Los Angeles', 1, 1002);
INSERT INTO ORDERS VALUES (3000, 1200.50, TO_DATE('2023-01-15', 'YYYY-MM-DD'), 2000, 1000);
INSERT INTO ORDERS VALUES (3001, 950.75, TO_DATE('2023-01-20', 'YYYY-MM-DD'), 2001, 1001);
INSERT INTO ORDERS VALUES (3002, 2500.00, TO_DATE('2023-02-05', 'YYYY-MM-DD'), 2002, 1002);
INSERT INTO ORDERS VALUES (3003, 1800.25, TO_DATE('2023-02-15', 'YYYY-MM-DD'), 2003, 1001);
INSERT INTO ORDERS VALUES (3004, 1100.00, TO_DATE('2023-03-01', 'YYYY-MM-DD'), 2004, 1000);
INSERT INTO ORDERS VALUES (3005, 3200.50, TO_DATE('2023-03-10', 'YYYY-MM-DD'), 2000, 1000);
INSERT INTO ORDERS VALUES (3006, 1500.75, TO_DATE('2023-03-15', 'YYYY-MM-DD'), 2005, 1002);
Solution a) Find salesmen who had more than one customer
sql
SELECT s.Salesman_id, s.Name
FROM SALESMAN s
WHERE (
SELECT COUNT(*)
FROM CUSTOMER c
WHERE c.Salesman_id = s.Salesman_id
) > 1;
Solution b) List salesmen with and without customers in their cities
sql
-- Salesmen with customers in their cities
SELECT s.Name AS "Salesman", s.City, 'Has customers in city' AS "Status"
FROM SALESMAN s
WHERE EXISTS (
SELECT 1 FROM CUSTOMER c
WHERE c.Salesman_id = s.Salesman_id AND c.City = s.City
)
UNION
-- Salesmen without customers in their cities
SELECT s.Name AS "Salesman", s.City, 'No customers in city' AS "Status"
FROM SALESMAN s
WHERE NOT EXISTS (
SELECT 1 FROM CUSTOMER c
WHERE c.Salesman_id = s.Salesman_id AND c.City = s.City
);
Solution c) Create a view for salesman with highest order
sql
CREATE OR REPLACE VIEW Highest_Order_Salesman AS
SELECT s.Salesman_id, s.Name, o.Ord_Date, o.Purchase_Amt
FROM SALESMAN s
JOIN ORDERS o ON s.Salesman_id = o.Salesman_id
WHERE (o.Ord_Date, o.Purchase_Amt) IN (
SELECT Ord_Date, MAX(Purchase_Amt)
FROM ORDERS
GROUP BY Ord_Date
);
Solution d) Delete salesman with id 1000
sql
DELETE FROM SALESMAN WHERE Salesman_id = 1000;
-- This will cascade to delete related orders due to ON DELETE CASCADE
-- Customers will have their Salesman_id set to NULL due to ON DELETE SET NULL
Solution e) Triggers for the Salesman table
sql
CREATE OR REPLACE TRIGGER salesman_commission_trigger
BEFORE INSERT OR UPDATE OF Commission ON SALESMAN
FOR EACH ROW
BEGIN
-- Ensure commission is within valid range (0-30%)
IF :NEW.Commission < 0 THEN
:NEW.Commission := 0;
ELSIF :NEW.Commission > 30 THEN
:NEW.Commission := 30;
END IF;
DBMS_OUTPUT.PUT_LINE('Commission for ' || :NEW.Name || ' set to ' || :NEW.Commission || '%'
END;
/
CREATE OR REPLACE TRIGGER order_update_trigger
AFTER INSERT OR UPDATE ON ORDERS
FOR EACH ROW
DECLARE
v_salesman_name SALESMAN.Name%TYPE;
v_customer_name CUSTOMER.Cust_Name%TYPE;
BEGIN
-- Get salesman and customer names
SELECT Name INTO v_salesman_name
FROM SALESMAN
WHERE Salesman_id = :NEW.Salesman_id;
SELECT Cust_Name INTO v_customer_name
FROM CUSTOMER
WHERE Customer_id = :NEW.Customer_id;
DBMS_OUTPUT.PUT_LINE('Order #' || :NEW.Ord_No || ' processed:');
DBMS_OUTPUT.PUT_LINE(' Date: ' || TO_CHAR(:NEW.Ord_Date, 'DD-MON-YYYY'));
DBMS_OUTPUT.PUT_LINE(' Amount: $' || :NEW.Purchase_Amt);
DBMS_OUTPUT.PUT_LINE(' Customer: ' || v_customer_name);
DBMS_OUTPUT.PUT_LINE(' Salesman: ' || v_salesman_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error: Salesman or Customer not found.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
/
-- Test the trigger
INSERT INTO SALESMAN VALUES (1004, 'Patricia Adams', 'Boston', 35.0);
INSERT INTO ORDERS VALUES (3007, 2200.00, TO_DATE('2023-04-01', 'YYYY-MM-DD'), 2001, 1001);
12-29. Additional Database Operations
These questions are variations and repetitions of the previous ones. I'll provide detailed solutions for a
few key examples that haven't been fully covered yet:
Bank Database with Constraints (Question 12)
sql
CREATE TABLE Bank_Account (
Account_No VARCHAR2(20) PRIMARY KEY,
Account_Holder VARCHAR2(100) NOT NULL,
Balance NUMBER(12,2) DEFAULT 0 CHECK (Balance >= 0),
Account_Type VARCHAR2(20) CHECK (Account_Type IN ('Savings', 'Current', 'Fixed')),
Opening_Date DATE DEFAULT SYSDATE,
Branch_Code VARCHAR2(10) NOT NULL
);
-- Insert sample records
INSERT INTO Bank_Account VALUES ('AC001', 'John Smith', 1200000.00, 'Savings', TO_DATE('2022-01
INSERT INTO Bank_Account VALUES ('AC002', 'Jane Doe', 950000.75, 'Current', TO_DATE('2022-02-20
INSERT INTO Bank_Account VALUES ('AC003', 'Robert Johnson', 1500000.25, 'Fixed', TO_DATE('2022-
INSERT INTO Bank_Account VALUES ('AC004', 'Emily Davis', 800000.50, 'Savings', TO_DATE('2022-04
INSERT INTO Bank_Account VALUES ('AC005', 'Michael Wilson', 1100000.00, 'Current', TO_DATE('202
-- PL/SQL to retrieve depositors with balance above 10 lakhs
CREATE OR REPLACE PROCEDURE get_high_value_depositors IS
BEGIN
DBMS_OUTPUT.PUT_LINE('High Value Depositors (Balance > 10 Lakhs)');
DBMS_OUTPUT.PUT_LINE('------------------------------------------');
FOR depositor IN (
SELECT Account_No, Account_Holder, Balance, Account_Type, Branch_Code
FROM Bank_Account
WHERE Balance > 1000000
HAVING Balance > 1000000 -- Using HAVING clause as per requirement
ORDER BY Balance DESC
) LOOP
DBMS_OUTPUT.PUT_LINE('Account: ' || depositor.Account_No);
DBMS_OUTPUT.PUT_LINE('Holder: ' || depositor.Account_Holder);
DBMS_OUTPUT.PUT_LINE('Balance: ₹' || TO_CHAR(depositor.Balance, '9,999,999.99'));
DBMS_OUTPUT.PUT_LINE('Type: ' || depositor.Account_Type);
DBMS_OUTPUT.PUT_LINE('Branch: ' || depositor.Branch_Code);
DBMS_OUTPUT.PUT_LINE('------------------------------------------');
END LOOP;
END;
/
-- Execute the procedure
EXEC get_high_value_depositors;
Cargo Service Database with Referential Integrity (Question 13)
sql
CREATE TABLE Cargo_Company (
Company_ID VARCHAR2(10) PRIMARY KEY,
Company_Name VARCHAR2(100) NOT NULL,
Contact_No VARCHAR2(20),
Email VARCHAR2(100),
Address VARCHAR2(200)
);
CREATE TABLE Customer (
Customer_ID VARCHAR2(10) PRIMARY KEY,
Customer_Name VARCHAR2(100) NOT NULL,
Contact_No VARCHAR2(20),
Email VARCHAR2(100),
Address VARCHAR2(200)
);
CREATE TABLE Cargo_Type (
Type_ID VARCHAR2(10) PRIMARY KEY,
Type_Name VARCHAR2(50) NOT NULL,
Description VARCHAR2(200),
Base_Rate NUMBER(10,2) NOT NULL
);
CREATE TABLE Cargo_Booking (
Booking_ID VARCHAR2(20) PRIMARY KEY,
Customer_ID VARCHAR2(10) NOT NULL,
Company_ID VARCHAR2(10) NOT NULL,
Type_ID VARCHAR2(10) NOT NULL,
Source_Location VARCHAR2(100) NOT NULL,
Destination VARCHAR2(100) NOT NULL,
Booking_Date DATE DEFAULT SYSDATE,
Delivery_Date DATE,
Weight NUMBER(10,2),
Volume NUMBER(10,2),
Amount NUMBER(12,2),
Status VARCHAR2(20) DEFAULT 'Booked' CHECK (Status IN ('Booked', 'In Transit', 'Delivered',
FOREIGN KEY (Customer_ID) REFERENCES Customer(Customer_ID) ON DELETE CASCADE,
FOREIGN KEY (Company_ID) REFERENCES Cargo_Company(Company_ID) ON DELETE CASCADE,
FOREIGN KEY (Type_ID) REFERENCES Cargo_Type(Type_ID)
);
-- Insert sample data
INSERT INTO Cargo_Company VALUES ('CC001', 'Express Cargo Ltd', '555-1234', 'contact@expresscar
INSERT INTO Cargo_Company VALUES ('CC002', 'Swift Delivery Inc', '555-5678', 'info@swiftdeliver
INSERT INTO Customer VALUES ('CU001', 'John Smith', '555-9876', '[email protected]', '789 Custom
INSERT INTO Customer VALUES ('CU002', 'Jane Doe', '555-5432', '[email protected]', '321 Client A
INSERT INTO Cargo_Type VALUES ('CT001', 'Standard', 'Regular delivery service', 100.00);
INSERT INTO Cargo_Type VALUES ('CT002', 'Express', 'Fast delivery service', 200.00);
INSERT INTO Cargo_Type VALUES ('CT003', 'Fragile', 'Special handling for fragile items', 250.00
INSERT INTO Cargo_Booking VALUES ('BK001', 'CU001', 'CC001', 'CT001', 'New York', 'Chicago',
TO_DATE('2023-01-15', 'YYYY-MM-DD'),
TO_DATE('2023-01-20', 'YYYY-MM-DD'),
25.5, 2.3, 300.00, 'Delivered');
INSERT INTO Cargo_Booking VALUES ('BK002', 'CU002', 'CC002', 'CT002', 'Los Angeles', 'Miami',
TO_DATE('2023-02-10', 'YYYY-MM-DD'),
TO_DATE('2023-02-12', 'YYYY-MM-DD'),
15.0, 1.5, 450.00, 'Delivered');
INSERT INTO Cargo_Booking VALUES ('BK003', 'CU001', 'CC001', 'CT003', 'Chicago', 'Boston',
TO_DATE('2023-03-05', 'YYYY-MM-DD'),
TO_DATE('2023-03-10', 'YYYY-MM-DD'),
10.2, 1.0, 350.00, 'Booked');
-- Trigger for cargo booking and cancellation
CREATE OR REPLACE TRIGGER cargo_booking_trigger
BEFORE INSERT OR UPDATE OF Status ON Cargo_Booking
FOR EACH ROW
DECLARE
v_customer_name Customer.Customer_Name%TYPE;
v_company_name Cargo_Company.Company_Name%TYPE;
v_cargo_type Cargo_Type.Type_Name%TYPE;
BEGIN
-- Get names for display purposes
SELECT Customer_Name INTO v_customer_name
FROM Customer
WHERE Customer_ID = :NEW.Customer_ID;
SELECT Company_Name INTO v_company_name
FROM Cargo_Company
WHERE Company_ID = :NEW.Company_ID;
SELECT Type_Name INTO v_cargo_type
FROM Cargo_Type
WHERE Type_ID = :NEW.Type_ID;
-- For new bookings
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE('New cargo booking created:');
DBMS_OUTPUT.PUT_LINE('Booking ID: ' || :NEW.Booking_ID);
DBMS_OUTPUT.PUT_LINE('Customer: ' || v_customer_name);
DBMS_OUTPUT.PUT_LINE('Company: ' || v_company_name);
DBMS_OUTPUT.PUT_LINE('Type: ' || v_cargo_type);
DBMS_OUTPUT.PUT_LINE('From: ' || :NEW.Source_Location || ' To: ' || :NEW.Destination);
DBMS_OUTPUT.PUT_LINE('Amount: $' || :NEW.Amount);
-- For status updates to Cancelled
ELSIF UPDATING AND :OLD.Status != :NEW.Status AND :NEW.Status = 'Cancelled' THEN
DBMS_OUTPUT.PUT_LINE('Cargo booking cancelled:');
DBMS_OUTPUT.PUT_LINE('Booking ID: ' || :NEW.Booking_ID);
DBMS_OUTPUT.PUT_LINE('Customer: ' || v_customer_name);
DBMS_OUTPUT.PUT_LINE('Original booking date: ' || TO_CHAR(:NEW.Booking_Date, 'DD-MON-YY
-- If we wanted to enforce business rules like cancellation fees:
-- :NEW.Amount := :NEW.Amount * 0.8; -- 20% cancellation fee
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_