Showing posts with label Triggers. Show all posts
Showing posts with label Triggers. Show all posts

oracle Triggers 50 Examples

Basic INSERT Triggers

1. Insert Trigger for Audit Table

Description: This trigger writes an audit record after a new employee row is inserted.

CREATE OR REPLACE TRIGGER audit_insert
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  INSERT INTO audit_log (operation, table_name, row_id, changed_at)
  VALUES ('INSERT', 'employees', :NEW.employee_id, SYSDATE);
END;
/

2. Insert Trigger to Auto-Populate Fields

Description: This trigger sets created date and created by values automatically before insert.

CREATE OR REPLACE TRIGGER auto_populate_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  :NEW.created_date := SYSDATE;
  :NEW.created_by := USER;
END;
/

3. Insert Trigger to Validate Data

Description: This trigger prevents inserting employees with a negative salary.

CREATE OR REPLACE TRIGGER validate_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  IF :NEW.salary < 0 THEN
    RAISE_APPLICATION_ERROR(-20001, 'Salary cannot be negative');
  END IF;
END;
/

Basic UPDATE Triggers

4. Update Trigger to Log Changes

Description: This trigger stores old and new salary values after an employee salary update.

CREATE OR REPLACE TRIGGER log_update
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
  INSERT INTO update_log (employee_id, old_salary, new_salary, changed_at)
  VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

5. Update Trigger to Prevent Changes

Description: This trigger blocks salary increases during update.

CREATE OR REPLACE TRIGGER prevent_update
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
  IF :OLD.salary < :NEW.salary THEN
    RAISE_APPLICATION_ERROR(-20002, 'Salary cannot be increased');
  END IF;
END;
/

6. Update Trigger to Automatically Update Timestamps

Description: This trigger refreshes the last updated timestamp before an employee row is updated.

CREATE OR REPLACE TRIGGER update_timestamp
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
  :NEW.last_updated := SYSDATE;
END;
/

Basic DELETE Triggers

7. Delete Trigger to Move Data to Archive Table

Description: This trigger copies deleted employee rows into an archive table.

CREATE OR REPLACE TRIGGER archive_on_delete
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
  INSERT INTO archived_employees (employee_id, name, salary, deleted_at)
  VALUES (:OLD.employee_id, :OLD.name, :OLD.salary, SYSDATE);
END;
/

8. Delete Trigger to Prevent Deletion

Description: This trigger stops all delete operations on employees.

CREATE OR REPLACE TRIGGER prevent_deletion
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
  RAISE_APPLICATION_ERROR(-20003, 'Deletion is not allowed');
END;
/

9. Delete Trigger to Clean Up Related Data

Description: This trigger removes related employee project records after an employee is deleted.

CREATE OR REPLACE TRIGGER cleanup_on_delete
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
  DELETE FROM employee_projects WHERE employee_id = :OLD.employee_id;
END;
/

Compound Triggers

10. Compound Trigger for Handling Multiple Actions

Description: This trigger shows how to place logic in statement-level and row-level sections in one trigger.

CREATE OR REPLACE TRIGGER compound_trigger_example
FOR INSERT OR UPDATE OR DELETE ON employees
COMPOUND TRIGGER
  BEFORE_STATEMENT IS
  BEGIN
    -- Actions before statement
  END BEFORE_STATEMENT;
  AFTER STATEMENT IS
  BEGIN
    -- Actions after statement
  END AFTER_STATEMENT;
  AFTER EACH ROW IS
  BEGIN
    -- Actions after each row
  END AFTER EACH ROW;
END;
/

Triggers with PL/SQL Block

11. Trigger with Exception Handling

Description: This trigger demonstrates exception handling and logs the error message into an error table.

CREATE OR REPLACE TRIGGER example_trigger
AFTER INSERT ON employees
FOR EACH ROW
DECLARE
  v_message VARCHAR2(100);
BEGIN
  BEGIN
    -- Trigger logic
  EXCEPTION
    WHEN OTHERS THEN
      v_message := 'Error: ' || SQLERRM;
      INSERT INTO error_log (error_message, error_date)
      VALUES (v_message, SYSDATE);
  END;
END;
/

Triggers on Views

12. Insert Trigger on a View

Description: This INSTEAD OF trigger lets users insert into a view by redirecting data into the base table.

CREATE OR REPLACE TRIGGER view_insert_trigger
INSTEAD OF INSERT ON emp_view
FOR EACH ROW
BEGIN
  INSERT INTO employees (employee_id, name, salary)
  VALUES (:NEW.employee_id, :NEW.name, :NEW.salary);
END;
/

13. Update Trigger on a View

Description: This INSTEAD OF trigger redirects view updates to the underlying employees table.

CREATE OR REPLACE TRIGGER view_update_trigger
INSTEAD OF UPDATE ON emp_view
FOR EACH ROW
BEGIN
  UPDATE employees
  SET name = :NEW.name, salary = :NEW.salary
  WHERE employee_id = :OLD.employee_id;
END;
/

Advanced Triggers

14. Trigger to Manage Sequence Values

Description: This trigger assigns the next sequence value to the employee ID before insert.

CREATE OR REPLACE TRIGGER manage_sequence
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  :NEW.employee_id := employees_seq.NEXTVAL;
END;
/

15. Trigger to Calculate and Update Totals

Description: This trigger recalculates the order total after row changes in order_items.

CREATE OR REPLACE TRIGGER update_totals
AFTER INSERT OR UPDATE ON order_items
FOR EACH ROW
BEGIN
  UPDATE orders
  SET total_amount = (SELECT SUM(item_price * quantity) FROM order_items WHERE order_id = :NEW.order_id)
  WHERE order_id = :NEW.order_id;
END;
/

Triggers for Error Handling

16. Trigger to Log Errors

Description: This trigger simulates an error and writes the error message into an error log table.

CREATE OR REPLACE TRIGGER log_error_trigger
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
BEGIN
  -- Custom error handling logic
  BEGIN
    -- Simulate an error
    RAISE_APPLICATION_ERROR(-20004, 'Custom error message');
  EXCEPTION
    WHEN OTHERS THEN
      INSERT INTO error_log (error_message, error_date)
      VALUES (SQLERRM, SYSDATE);
  END;
END;
/

DML Triggers

17. Trigger to Calculate Discounts

Description: This trigger calculates a discount automatically based on the order total amount.

CREATE OR REPLACE TRIGGER calculate_discount
BEFORE INSERT OR UPDATE ON orders
FOR EACH ROW
BEGIN
  IF :NEW.total_amount > 1000 THEN
    :NEW.discount := :NEW.total_amount * 0.1;
  ELSE
    :NEW.discount := 0;
  END IF;
END;
/

18. Trigger to Synchronize Data Across Tables

Description: This trigger updates the department manager name when an employee changes.

CREATE OR REPLACE TRIGGER sync_data
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
  UPDATE departments
  SET manager_name = :NEW.name
  WHERE department_id = :NEW.department_id;
END;
/

Triggers with Custom Functions

19. Trigger Using a Custom Function

Description: This trigger calls a custom salary calculation function during insert.

CREATE OR REPLACE TRIGGER trigger_with_function
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  :NEW.salary := calculate_salary(:NEW.base_salary);
END;
/

20. Trigger to Call Another Procedure

Description: This trigger calls a stored procedure after a new employee is inserted.

CREATE OR REPLACE TRIGGER call_procedure_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  log_employee_insert(:NEW.employee_id, :NEW.name);
END;
/

Row-Level and Statement-Level Triggers

21. Row-Level Trigger with Detailed Logging

Description: This trigger logs whether the change was an insert, update, or delete for each row.

CREATE OR REPLACE TRIGGER detailed_log_trigger
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
BEGIN
  INSERT INTO detailed_log (operation, employee_id, name, operation_date)
  VALUES (
    CASE
      WHEN INSERTING THEN 'INSERT'
      WHEN UPDATING THEN 'UPDATE'
      WHEN DELETING THEN 'DELETE'
    END,
    :OLD.employee_id,
    :NEW.name,
    SYSDATE
  );
END;
/

22. Statement-Level Trigger to Monitor Execution Time

Description: This trigger prints a message after an insert statement finishes running.

CREATE OR REPLACE TRIGGER monitor_execution_time
AFTER INSERT ON employees
BEGIN
  DBMS_OUTPUT.PUT_LINE('Insert statement executed at: ' || SYSDATE);
END;
/

Triggers for Data Integrity

23. Trigger to Ensure Referential Integrity

Description: This trigger blocks inserts or updates when the department ID does not exist.

CREATE OR REPLACE TRIGGER check_ref_integrity
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  IF NOT EXISTS (SELECT 1 FROM departments WHERE department_id = :NEW.department_id) THEN
    RAISE_APPLICATION_ERROR(-20005, 'Invalid department ID');
  END IF;
END;
/

24. Trigger to Enforce Business Rules

Description: This trigger enforces a minimum salary business rule before insert or update.

CREATE OR REPLACE TRIGGER enforce_business_rules
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  IF :NEW.salary < 20000 THEN
    RAISE_APPLICATION_ERROR(-20006, 'Salary must be at least 20,000');
  END IF;
END;
/

Complex Trigger Logic

25. Trigger with Multiple Conditions

Description: This trigger checks whether salary is below zero or above the maximum allowed amount.

CREATE OR REPLACE TRIGGER multi_condition_trigger
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  IF :NEW.salary < 0 THEN
    RAISE_APPLICATION_ERROR(-20007, 'Salary cannot be negative');
  ELSIF :NEW.salary > 100000 THEN
    RAISE_APPLICATION_ERROR(-20008, 'Salary cannot exceed 100,000');
  END IF;
END;
/

26. Trigger to Handle Multiple Tables

Description: This trigger writes to a log table and updates departments after employee changes.

CREATE OR REPLACE TRIGGER multi_table_trigger
AFTER INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  INSERT INTO employee_log (employee_id, log_date, log_message)
  VALUES (:NEW.employee_id, SYSDATE, 'Employee data updated');

UPDATE departments
SET last_updated = SYSDATE
WHERE department_id = :NEW.department_id;
END;
/

Triggers for Historical Tracking

27. Trigger to Track Historical Changes

Description: This trigger stores old and new salary values every time an employee row is updated.

CREATE OR REPLACE TRIGGER history_tracking_trigger
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
  INSERT INTO employee_history (employee_id, old_salary, new_salary, update_date)
  VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

28. Trigger to Maintain Revision History

Description: This trigger stores order revisions whenever the total amount changes.

CREATE OR REPLACE TRIGGER revision_history_trigger
AFTER UPDATE ON orders
FOR EACH ROW
BEGIN
  INSERT INTO order_revisions (order_id, old_amount, new_amount, revision_date)
  VALUES (:OLD.order_id, :OLD.total_amount, :NEW.total_amount, SYSDATE);
END;
/

Triggers with Bulk Processing

29. Bulk Processing with Triggers

Description: This trigger is a placeholder for bulk processing logic such as collection-based operations.

CREATE OR REPLACE TRIGGER bulk_process_trigger
AFTER INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  -- Use bulk operations to process data
  -- For example, using DBMS_SQL or PL/SQL tables
END;
/

30. Trigger to Handle Multiple Inserts

Description: This trigger inserts several task rows for each new employee.

CREATE OR REPLACE TRIGGER multi_insert_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  FOR i IN 1..5 LOOP
    INSERT INTO employee_tasks (employee_id, task_id, task_date)
    VALUES (:NEW.employee_id, i, SYSDATE);
  END LOOP;
END;
/

Triggers for Logging and Monitoring

31. Trigger to Monitor Changes

Description: This trigger logs insert, update, and delete operations into a change log table.

CREATE OR REPLACE TRIGGER change_monitoring_trigger
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
BEGIN
  INSERT INTO change_log (operation, employee_id, operation_date)
  VALUES (
    CASE
      WHEN INSERTING THEN 'INSERT'
      WHEN UPDATING THEN 'UPDATE'
      WHEN DELETING THEN 'DELETE'
    END,
    :OLD.employee_id,
    SYSDATE
  );
END;
/

32. Trigger to Log User Actions

Description: This trigger logs user actions from the employee_actions table into an audit table.

CREATE OR REPLACE TRIGGER user_action_log
AFTER INSERT ON employee_actions
FOR EACH ROW
BEGIN
  INSERT INTO user_actions_log (user_id, action_type, action_date)
  VALUES (:NEW.user_id, :NEW.action_type, SYSDATE);
END;
/

Triggers for Conditional Logic

33. Trigger with Conditional Logic

Description: This trigger logs employees whose salary is above 50000.

CREATE OR REPLACE TRIGGER conditional_logic_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  IF :NEW.salary > 50000 THEN
    INSERT INTO high_salary_log (employee_id, salary, log_date)
    VALUES (:NEW.employee_id, :NEW.salary, SYSDATE);
  END IF;
END;
/

34. Trigger to Handle Different Roles

Description: This trigger logs employees with the Manager role.

CREATE OR REPLACE TRIGGER role_based_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  IF :NEW.role = 'Manager' THEN
    INSERT INTO manager_log (employee_id, log_date)
    VALUES (:NEW.employee_id, SYSDATE);
  END IF;
END;
/

Triggers for User Interaction

35. Trigger to Send Notifications

Description: This trigger calls a notification procedure after a new order is inserted.

CREATE OR REPLACE TRIGGER send_notification_trigger
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
  -- Call a procedure to send notifications
  send_order_notification(:NEW.order_id);
END;
/

36. Trigger to Generate Reports

Description: This trigger calls a reporting procedure after a new employee is inserted.

CREATE OR REPLACE TRIGGER report_generation_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  -- Generate a report
  generate_employee_report(:NEW.employee_id);
END;
/

Complex Logic with Triggers

37. Trigger with Nested Logic

Description: This trigger adds a row to the high salary report when salary is greater than 60000.

CREATE OR REPLACE TRIGGER nested_logic_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  IF :NEW.salary > 60000 THEN
    BEGIN
      INSERT INTO high_salary_report (employee_id, salary, report_date)
      VALUES (:NEW.employee_id, :NEW.salary, SYSDATE);
    END;
  END IF;
END;
/

38. Trigger for Cross-Table Validation

Description: This trigger prevents insert if the department ID does not exist.

CREATE OR REPLACE TRIGGER cross_table_validation_trigger
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  IF NOT EXISTS (SELECT 1 FROM departments WHERE department_id = :NEW.department_id) THEN
    RAISE_APPLICATION_ERROR(-20009, 'Department ID does not exist');
  END IF;
END;
/

Triggers for Data Aggregation

39. Trigger to Aggregate Data

Description: This trigger updates daily sales totals whenever a new sale is inserted.

CREATE OR REPLACE TRIGGER aggregate_data_trigger
AFTER INSERT ON sales
FOR EACH ROW
BEGIN
  UPDATE sales_summary
  SET total_sales = (SELECT SUM(sale_amount) FROM sales WHERE sale_date = :NEW.sale_date)
  WHERE sale_date = :NEW.sale_date;
END;
/

40. Trigger to Update Statistics

Description: This trigger refreshes product statistics after inserts or updates in products.

CREATE OR REPLACE TRIGGER update_statistics_trigger
AFTER INSERT OR UPDATE ON products
FOR EACH ROW
BEGIN
  UPDATE product_statistics
  SET total_units = (SELECT SUM(units_sold) FROM sales WHERE product_id = :NEW.product_id)
  WHERE product_id = :NEW.product_id;
END;
/

Triggers for Complex Operations

41. Trigger to Perform Complex Calculation

Description: This trigger calculates the total amount using quantity and a custom price function.

CREATE OR REPLACE TRIGGER complex_calculation_trigger
AFTER INSERT OR UPDATE ON orders
FOR EACH ROW
BEGIN
  :NEW.total_amount := :NEW.quantity * calculate_price(:NEW.product_id);
END;
/

42. Trigger to Synchronize Data Between Tables

Description: This trigger updates the order summary when an order changes.

CREATE OR REPLACE TRIGGER data_synchronization_trigger
AFTER UPDATE ON orders
FOR EACH ROW
BEGIN
  UPDATE order_summary
  SET total_amount = (SELECT SUM(total_amount) FROM orders WHERE order_id = :NEW.order_id)
  WHERE order_id = :NEW.order_id;
END;
/

Triggers for Date and Time Handling

43. Trigger to Manage Dates

Description: This trigger validates that event dates are not in the past.

CREATE OR REPLACE TRIGGER manage_dates_trigger
AFTER INSERT ON events
FOR EACH ROW
BEGIN
  IF :NEW.event_date < SYSDATE THEN
    RAISE_APPLICATION_ERROR(-20010, 'Event date cannot be in the past');
  END IF;
END;
/

44. Trigger to Handle Expiry Dates

Description: This trigger blocks products with expired dates from being inserted or updated.

CREATE OR REPLACE TRIGGER handle_expiry_dates
BEFORE INSERT OR UPDATE ON products
FOR EACH ROW
BEGIN
  IF :NEW.expiry_date < SYSDATE THEN
    RAISE_APPLICATION_ERROR(-20011, 'Product has expired');
  END IF;
END;
/

Triggers for Data Transformation

45. Trigger to Transform Data

Description: This trigger converts employee names to uppercase before saving them.

CREATE OR REPLACE TRIGGER data_transformation_trigger
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  :NEW.employee_name := UPPER(:NEW.employee_name);
END;
/

46. Trigger to Standardize Data

Description: This trigger converts email addresses to lowercase before saving them.

CREATE OR REPLACE TRIGGER standardize_data_trigger
BEFORE INSERT OR UPDATE ON customers
FOR EACH ROW
BEGIN
  :NEW.email_address := LOWER(:NEW.email_address);
END;
/

Triggers for Security and Access Control

47. Trigger to Control Access

Description: This trigger prevents inserts unless the current user is admin.

CREATE OR REPLACE TRIGGER control_access_trigger
BEFORE INSERT ON sensitive_data
FOR EACH ROW
BEGIN
  IF USER <> 'admin' THEN
    RAISE_APPLICATION_ERROR(-20012, 'Access denied');
  END IF;
END;
/

48. Trigger to Mask Sensitive Information

Description: This trigger replaces sensitive SSN values with masked text before saving.

CREATE OR REPLACE TRIGGER mask_sensitive_info
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
  :NEW.social_security_number := 'XXX-XX-XXXX';
END;
/

Triggers for Synchronization

49. Trigger for Data Synchronization Across Systems

Description: This trigger calls an external synchronization procedure after inserting an employee.

CREATE OR REPLACE TRIGGER data_sync_trigger
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
  -- Call external API to synchronize data
  sync_employee_data(:NEW.employee_id);
END;
/

50. Trigger for Inter-System Communication

Description: This trigger notifies another system when an order is updated.

CREATE OR REPLACE TRIGGER inter_system_communication_trigger
AFTER UPDATE ON orders
FOR EACH ROW
BEGIN
  -- Notify another system about the update
  notify_system_of_order_update(:NEW.order_id);
END;
/

Note: Some example triggers are illustrative and may need small adjustments before running in a real Oracle schema.

Oracle PL/SQL trigger 100 programs

1. Basic BEFORE INSERT Trigger

CREATE OR REPLACE TRIGGER trg_before_insert_employee
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   :NEW.hire_date := SYSDATE;
END;
/

2. Basic AFTER INSERT Trigger

CREATE OR REPLACE TRIGGER trg_after_insert_employee
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
   INSERT INTO audit_log (log_message)
   VALUES ('Employee ' || :NEW.employee_id || ' inserted.');
END;
/

3. BEFORE UPDATE Trigger for Salary Increase

CREATE OR REPLACE TRIGGER trg_before_update_salary
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < :OLD.salary THEN
      RAISE_APPLICATION_ERROR(-20001, 'Salary cannot be decreased.');
   END IF;
END;
/

4. AFTER UPDATE Trigger for Salary Log

CREATE OR REPLACE TRIGGER trg_after_update_salary
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   INSERT INTO salary_audit (employee_id, old_salary, new_salary, change_date)
   VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

5. BEFORE DELETE Trigger

CREATE OR REPLACE TRIGGER trg_before_delete_employee
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.job_id = 'MANAGER' THEN
      RAISE_APPLICATION_ERROR(-20002, 'Managers cannot be deleted.');
   END IF;
END;
/

6. AFTER DELETE Trigger

CREATE OR REPLACE TRIGGER trg_after_delete_employee
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
   INSERT INTO employee_archive (employee_id, first_name, last_name, delete_date)
   VALUES (:OLD.employee_id, :OLD.first_name, :OLD.last_name, SYSDATE);
END;
/

7. Trigger to Prevent Insert if Employee Already Exists

CREATE OR REPLACE TRIGGER trg_prevent_duplicate_employee
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF EXISTS (SELECT 1 FROM employees WHERE email = :NEW.email) THEN
      RAISE_APPLICATION_ERROR(-20003, 'Employee with this email already exists.');
   END IF;
END;
/

8. Trigger to Set Default Values on Insert

CREATE OR REPLACE TRIGGER trg_default_values
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary IS NULL THEN
      :NEW.salary := 3000;
   END IF;
   IF :NEW.department_id IS NULL THEN
      :NEW.department_id := 10;
   END IF;
END;
/

9. BEFORE UPDATE Trigger to Prevent Update of Primary Key

CREATE OR REPLACE TRIGGER trg_prevent_primary_key_update
BEFORE UPDATE OF employee_id ON employees
FOR EACH ROW
BEGIN
   RAISE_APPLICATION_ERROR(-20004, 'Primary key cannot be updated.');
END;
/

10. Trigger for Auditing Table Changes

CREATE OR REPLACE TRIGGER trg_audit_employee_changes
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
BEGIN
   INSERT INTO employee_audit (operation, employee_id, change_date)
   VALUES (CASE WHEN INSERTING THEN 'INSERT'
                WHEN UPDATING THEN 'UPDATE'
                WHEN DELETING THEN 'DELETE' END,
           :NEW.employee_id,
           SYSDATE);
END;
/

11. Trigger to Auto-Increment ID on Insert

CREATE OR REPLACE TRIGGER trg_auto_increment_id
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   SELECT employee_seq.NEXTVAL INTO :NEW.employee_id FROM dual;
END;
/

12. Trigger to Log Changes in Job Title

CREATE OR REPLACE TRIGGER trg_log_job_title_changes
AFTER UPDATE OF job_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id <> :OLD.job_id THEN
      INSERT INTO job_title_log (employee_id, old_job_id, new_job_id, change_date)
      VALUES (:OLD.employee_id, :OLD.job_id, :NEW.job_id, SYSDATE);
   END IF;
END;
/

13. Trigger to Deny Weekend Inserts

CREATE OR REPLACE TRIGGER trg_deny_weekend_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF TO_CHAR(SYSDATE, 'DY') IN ('SAT', 'SUN') THEN
      RAISE_APPLICATION_ERROR(-20005, 'Inserts are not allowed on weekends.');
   END IF;
END;
/

14. Trigger to Update Managers Report Count

CREATE OR REPLACE TRIGGER trg_update_manager_report_count
AFTER INSERT OR DELETE ON employees
FOR EACH ROW
BEGIN
   IF INSERTING THEN
      UPDATE employees
      SET report_count = report_count + 1
      WHERE employee_id = :NEW.manager_id;
   ELSIF DELETING THEN
      UPDATE employees
      SET report_count = report_count - 1
      WHERE employee_id = :OLD.manager_id;
   END IF;
END;
/

15. Trigger to Calculate Age on Insert

CREATE OR REPLACE TRIGGER trg_calculate_age
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   :NEW.age := TRUNC(MONTHS_BETWEEN(SYSDATE, :NEW.date_of_birth) / 12);
END;
/

16. Trigger to Prevent Future Hire Dates

CREATE OR REPLACE TRIGGER trg_prevent_future_hire_date
BEFORE INSERT OR UPDATE OF hire_date ON employees
FOR EACH ROW
BEGIN
   IF :NEW.hire_date > SYSDATE THEN
      RAISE_APPLICATION_ERROR(-20006, 'Hire date cannot be in the future.');
   END IF;
END;
/

17. Trigger to Default Commission to Zero

CREATE OR REPLACE TRIGGER trg_default_commission
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.commission_pct IS NULL THEN
      :NEW.commission_pct := 0;
   END IF;
END;
/

18. Trigger to Log Changes to Employee Contact Information

CREATE OR REPLACE TRIGGER trg_log_contact_update
AFTER UPDATE OF email, phone_number ON employees
FOR EACH ROW
BEGIN
   INSERT INTO contact_audit (employee_id, old_email, new_email, old_phone, new_phone, change_date)
   VALUES (:OLD.employee_id, :OLD.email, :NEW.email, :OLD.phone_number, :NEW.phone_number, SYSDATE);
END;
/

19. Trigger to Prevent Deletion of Critical Data

CREATE OR REPLACE TRIGGER trg_prevent_critical_data_deletion
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.department_id = 10 THEN
      RAISE_APPLICATION_ERROR(-20007, 'Employees from department 10 cannot be deleted.');
   END IF;
END;
/

20. Trigger to Auto-Fill Full Name on Insert

CREATE OR REPLACE TRIGGER trg_auto_fill_full_name
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   :NEW.full_name := :NEW.first_name || ' ' || :NEW.last_name;
END;
/

21. Trigger to Ensure Minimum Salary

CREATE OR REPLACE TRIGGER trg_ensure_minimum_salary
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < 2000 THEN
      :NEW.salary := 2000;
   END IF;
END;
/

22. Trigger to Log Promotions

CREATE OR REPLACE TRIGGER trg_log_promotions
AFTER UPDATE OF job_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id <> :OLD.job_id THEN
      INSERT INTO promotion_log (employee_id, old_job_id, new_job_id, promotion_date)
      VALUES (:OLD.employee_id, :OLD.job_id, :NEW.job_id, SYSDATE);
   END IF;
END;
/

23. Trigger to Calculate Service Duration on Update

CREATE OR REPLACE TRIGGER trg_calculate_service_duration
AFTER UPDATE OF hire_date ON employees
FOR EACH ROW
BEGIN
   :NEW.service_duration := TRUNC(MONTHS_BETWEEN(SYSDATE, :NEW.hire_date) / 12);
END;
/

24. Trigger to Audit Salary Changes

CREATE OR REPLACE TRIGGER trg_audit_salary_changes
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   INSERT INTO salary_audit_log (employee_id, old_salary, new_salary, change_date)
   VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

25. Trigger to Restrict Updates During Business Hours

CREATE OR REPLACE TRIGGER trg_restrict_updates
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF TO_CHAR(SYSDATE, 'HH24') BETWEEN 9 AND 17 THEN
      RAISE_APPLICATION_ERROR(-20008, 'Updates are not allowed during business hours.');
   END IF;
END;
/

26. Trigger to Log Employee Termination

CREATE OR REPLACE TRIGGER trg_log_termination
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
   INSERT INTO termination_log (employee_id, termination_date)
   VALUES (:OLD.employee_id, SYSDATE);
END;
/

27. Trigger to Prevent Deletion of Active Employees

CREATE OR REPLACE TRIGGER trg_prevent_active_employee_deletion
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.status = 'ACTIVE' THEN
      RAISE_APPLICATION_ERROR(-20009, 'Active employees cannot be deleted.');
   END IF;
END;
/

28. Trigger to Enforce Unique Email

CREATE OR REPLACE TRIGGER trg_enforce_unique_email
BEFORE INSERT OR UPDATE OF email ON employees
FOR EACH ROW
DECLARE
   email_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO email_count
   FROM employees
   WHERE email = :NEW.email AND employee_id != :NEW.employee_id;

IF email_count > 0 THEN
RAISE_APPLICATION_ERROR(-20010, 'Email must be unique.');
END IF;
END;
/

29. Trigger to Prevent Insert During Maintenance Window

CREATE OR REPLACE TRIGGER trg_prevent_maintenance_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF TO_CHAR(SYSDATE, 'DY') = 'SUN' THEN
      RAISE_APPLICATION_ERROR(-20011, 'Inserts are not allowed during maintenance.');
   END IF;
END;
/

30. Trigger to Log Manager Changes

CREATE OR REPLACE TRIGGER trg_log_manager_changes
AFTER UPDATE OF manager_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.manager_id <> :OLD.manager_id THEN
      INSERT INTO manager_change_log (employee_id, old_manager_id, new_manager_id, change_date)
      VALUES (:OLD.employee_id, :OLD.manager_id, :NEW.manager_id, SYSDATE);
   END IF;
END;
/

31. Trigger to Enforce Maximum Number of Reports

CREATE OR REPLACE TRIGGER trg_enforce_max_reports
BEFORE INSERT OR UPDATE OF manager_id ON employees
FOR EACH ROW
DECLARE
   report_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO report_count
   FROM employees
   WHERE manager_id = :NEW.manager_id;

IF report_count >= 10 THEN
RAISE_APPLICATION_ERROR(-20012, 'Manager already has maximum number of reports.');
END IF;
END;
/

32. Trigger to Automatically Set Employee Status

CREATE OR REPLACE TRIGGER trg_set_employee_status
BEFORE INSERT OR UPDATE OF end_date ON employees
FOR EACH ROW
BEGIN
   IF :NEW.end_date IS NOT NULL THEN
      :NEW.status := 'INACTIVE';
   ELSE
      :NEW.status := 'ACTIVE';
   END IF;
END;
/

33. Trigger to Deny Update of Critical Fields

CREATE OR REPLACE TRIGGER trg_deny_critical_update
BEFORE UPDATE OF first_name, last_name, department_id ON employees
FOR EACH ROW
BEGIN
   RAISE_APPLICATION_ERROR(-20013, 'These fields cannot be updated.');
END;
/

34. Trigger to Prevent Negative Salary

CREATE OR REPLACE TRIGGER trg_prevent_negative_salary
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < 0 THEN
      RAISE_APPLICATION_ERROR(-20014, 'Salary cannot be negative.');
   END IF;
END;
/

35. Trigger to Set Default Hire Date

CREATE OR REPLACE TRIGGER trg_default_hire_date
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.hire_date IS NULL THEN
      :NEW.hire_date := SYSDATE;
   END IF;
END;
/

36. Trigger to Log Email Address Changes

CREATE OR REPLACE TRIGGER trg_log_email_changes
AFTER UPDATE OF email ON employees
FOR EACH ROW
BEGIN
   IF :NEW.email <> :OLD.email THEN
      INSERT INTO email_change_log (employee_id, old_email, new_email, change_date)
      VALUES (:OLD.employee_id, :OLD.email, :NEW.email, SYSDATE);
   END IF;
END;
/

37. Trigger to Restrict Deletion of Employees with Reports

CREATE OR REPLACE TRIGGER trg_restrict_employee_with_reports
BEFORE DELETE ON employees
FOR EACH ROW
DECLARE
   report_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO report_count
   FROM employees
   WHERE manager_id = :OLD.employee_id;

IF report_count > 0 THEN
RAISE_APPLICATION_ERROR(-20015, 'Employees with reports cannot be deleted.');
END IF;
END;
/

38. Trigger to Auto-Assign Manager

CREATE OR REPLACE TRIGGER trg_auto_assign_manager
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.manager_id IS NULL THEN
      :NEW.manager_id := (SELECT manager_id FROM department_managers WHERE department_id = :NEW.department_id);
   END IF;
END;
/

39. Trigger to Log Department Changes

CREATE OR REPLACE TRIGGER trg_log_department_changes
AFTER UPDATE OF department_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id <> :OLD.department_id THEN
      INSERT INTO department_change_log (employee_id, old_department_id, new_department_id, change_date)
      VALUES (:OLD.employee_id, :OLD.department_id, :NEW.department_id, SYSDATE);
   END IF;
END;
/

40. Trigger to Deny Deletion of Recent Hires

CREATE OR REPLACE TRIGGER trg_deny_recent_hire_deletion
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
   IF MONTHS_BETWEEN(SYSDATE, :OLD.hire_date) < 6 THEN
      RAISE_APPLICATION_ERROR(-20016, 'Recent hires cannot be deleted.');
   END IF;
END;
/

41. Trigger to Restrict Salary Increase to Specific Percentage

CREATE OR REPLACE TRIGGER trg_restrict_salary_increase
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary > :OLD.salary * 1.10 THEN
      RAISE_APPLICATION_ERROR(-20017, 'Salary increase cannot exceed 10%.');
   END IF;
END;
/

42. Trigger to Prevent Updates to Terminated Employees

CREATE OR REPLACE TRIGGER trg_prevent_terminated_employee_update
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.status = 'TERMINATED' THEN
      RAISE_APPLICATION_ERROR(-20018, 'Terminated employees cannot be updated.');
   END IF;
END;
/

43. Trigger to Enforce Salary Range

CREATE OR REPLACE TRIGGER trg_enforce_salary_range
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < 2000 OR :NEW.salary > 10000 THEN
      RAISE_APPLICATION_ERROR(-20019, 'Salary must be between 2000 and 10000.');
   END IF;
END;
/

44. Trigger to Log Bonus Changes

CREATE OR REPLACE TRIGGER trg_log_bonus_changes
AFTER UPDATE OF bonus ON employees
FOR EACH ROW
BEGIN
   INSERT INTO bonus_audit (employee_id, old_bonus, new_bonus, change_date)
   VALUES (:OLD.employee_id, :OLD.bonus, :NEW.bonus, SYSDATE);
END;
/

45. Trigger to Automatically Set Full Name

CREATE OR REPLACE TRIGGER trg_auto_set_full_name
BEFORE INSERT OR UPDATE OF first_name, last_name ON employees
FOR EACH ROW
BEGIN
   :NEW.full_name := :NEW.first_name || ' ' || :NEW.last_name;
END;
/

46. Trigger to Restrict Updates Based on Role

CREATE OR REPLACE TRIGGER trg_restrict_update_based_on_role
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF USER NOT IN ('HR_ADMIN', 'HR_MANAGER') THEN
      RAISE_APPLICATION_ERROR(-20020, 'You are not authorized to update employee records.');
   END IF;
END;
/

47. Trigger to Prevent Multiple Active Assignments

CREATE OR REPLACE TRIGGER trg_prevent_multiple_active_assignments
BEFORE INSERT OR UPDATE OF status ON employees
FOR EACH ROW
DECLARE
   active_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO active_count
   FROM employees
   WHERE employee_id = :NEW.employee_id AND status = 'ACTIVE';

IF active_count > 0 AND :NEW.status = 'ACTIVE' THEN
RAISE_APPLICATION_ERROR(-20021, 'Employee cannot have multiple active assignments.');
END IF;
END;
/

48. Trigger to Log Termination Reason

CREATE OR REPLACE TRIGGER trg_log_termination_reason
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
   INSERT INTO termination_reason_log (employee_id, termination_reason, termination_date)
   VALUES (:OLD.employee_id, :OLD.termination_reason, SYSDATE);
END;
/

49. Trigger to Prevent Update of Salary for Executives

CREATE OR REPLACE TRIGGER trg_prevent_executive_salary_update
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :OLD.job_id = 'EXECUTIVE' THEN
      RAISE_APPLICATION_ERROR(-20022, 'Salary for executives cannot be updated.');
   END IF;
END;
/

50. Trigger to Enforce Employee Age Limit

CREATE OR REPLACE TRIGGER trg_enforce_age_limit
BEFORE INSERT OR UPDATE OF date_of_birth ON employees
FOR EACH ROW
DECLARE
   age INTEGER;
BEGIN
   age := TRUNC(MONTHS_BETWEEN(SYSDATE, :NEW.date_of_birth) / 12);

IF age < 18 THEN
RAISE_APPLICATION_ERROR(-20023, 'Employee must be at least 18 years old.');
END IF;
END;
/

51. Trigger to Log Updates to Employee Address

CREATE OR REPLACE TRIGGER trg_log_address_update
AFTER UPDATE OF address ON employees
FOR EACH ROW
BEGIN
   INSERT INTO address_audit (employee_id, old_address, new_address, change_date)
   VALUES (:OLD.employee_id, :OLD.address, :NEW.address, SYSDATE);
END;
/

52. Trigger to Auto-Fill Department on Insert

CREATE OR REPLACE TRIGGER trg_auto_fill_department
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id IS NULL THEN
      :NEW.department_id := (SELECT department_id FROM departments WHERE department_name = 'Sales');
   END IF;
END;
/

53. Trigger to Deny Updates During Non-Business Hours

CREATE OR REPLACE TRIGGER trg_deny_updates_non_business_hours
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF TO_CHAR(SYSDATE, 'HH24') NOT BETWEEN 9 AND 17 THEN
      RAISE_APPLICATION_ERROR(-20024, 'Updates are not allowed outside business hours.');
   END IF;
END;
/

54. Trigger to Log Changes to Contact Information

CREATE OR REPLACE TRIGGER trg_log_contact_information_changes
AFTER UPDATE OF email, phone_number, address ON employees
FOR EACH ROW
BEGIN
   INSERT INTO contact_information_audit (employee_id, old_email, new_email, old_phone, new_phone, old_address, new_address, change_date)
   VALUES (:OLD.employee_id, :OLD.email, :NEW.email, :OLD.phone_number, :NEW.phone_number, :OLD.address, :NEW.address, SYSDATE);
END;
/

55. Trigger to Prevent Update of Department for Managers

CREATE OR REPLACE TRIGGER trg_prevent_manager_department_update
BEFORE UPDATE OF department_id ON employees
FOR EACH ROW
BEGIN
   IF :OLD.job_id = 'MANAGER' THEN
      RAISE_APPLICATION_ERROR(-20025, 'Department for managers cannot be updated.');
   END IF;
END;
/

56. Trigger to Log Updates to Salary

CREATE OR REPLACE TRIGGER trg_log_salary_updates
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   INSERT INTO salary_update_log (employee_id, old_salary, new_salary, change_date)
   VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

57. Trigger to Enforce Manager Assignment

CREATE OR REPLACE TRIGGER trg_enforce_manager_assignment
BEFORE INSERT OR UPDATE OF manager_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id = 'EMPLOYEE' AND :NEW.manager_id IS NULL THEN
      RAISE_APPLICATION_ERROR(-20026, 'Employee must have a manager assigned.');
   END IF;
END;
/

58. Trigger to Deny Insert of Duplicate Email

CREATE OR REPLACE TRIGGER trg_deny_duplicate_email_insert
BEFORE INSERT ON employees
FOR EACH ROW
DECLARE
   email_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO email_count
   FROM employees
   WHERE email = :NEW.email;

IF email_count > 0 THEN
RAISE_APPLICATION_ERROR(-20027, 'Email already exists.');
END IF;
END;
/

59. Trigger to Log Changes to Job ID

CREATE OR REPLACE TRIGGER trg_log_job_id_changes
AFTER UPDATE OF job_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id <> :OLD.job_id THEN
      INSERT INTO job_id_audit (employee_id, old_job_id, new_job_id, change_date)
      VALUES (:OLD.employee_id, :OLD.job_id, :NEW.job_id, SYSDATE);
   END IF;
END;
/

60. Trigger to Prevent Update of Manager ID

CREATE OR REPLACE TRIGGER trg_prevent_manager_id_update
BEFORE UPDATE OF manager_id ON employees
FOR EACH ROW
BEGIN
   IF :OLD.job_id = 'MANAGER' THEN
      RAISE_APPLICATION_ERROR(-20028, 'Manager ID cannot be updated.');
   END IF;
END;
/

61. Trigger to Auto-Assign Default Department

CREATE OR REPLACE TRIGGER trg_auto_assign_default_department
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id IS NULL THEN
      :NEW.department_id := 1;
   END IF;
END;
/

62. Trigger to Restrict Updates to Certain Columns

CREATE OR REPLACE TRIGGER trg_restrict_column_updates
BEFORE UPDATE OF first_name, last_name ON employees
FOR EACH ROW
BEGIN
   RAISE_APPLICATION_ERROR(-20029, 'First name and last name cannot be updated.');
END;
/

63. Trigger to Enforce Unique Combination of Columns

CREATE OR REPLACE TRIGGER trg_enforce_unique_combination
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
DECLARE
   combination_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO combination_count
   FROM employees
   WHERE first_name = :NEW.first_name AND last_name = :NEW.last_name AND date_of_birth = :NEW.date_of_birth;

IF combination_count > 0 THEN
RAISE_APPLICATION_ERROR(-20030, 'Combination of first name, last name, and date of birth must be unique.');
END IF;
END;
/

64. Trigger to Log Deletions

CREATE OR REPLACE TRIGGER trg_log_deletions
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
   INSERT INTO deletion_log (employee_id, deletion_date)
   VALUES (:OLD.employee_id, SYSDATE);
END;
/

65. Trigger to Enforce Non-Negative Bonus

CREATE OR REPLACE TRIGGER trg_enforce_non_negative_bonus
BEFORE INSERT OR UPDATE OF bonus ON employees
FOR EACH ROW
BEGIN
   IF :NEW.bonus < 0 THEN
      RAISE_APPLICATION_ERROR(-20031, 'Bonus cannot be negative.');
   END IF;
END;
/

66. Trigger to Automatically Set Status Based on Date

CREATE OR REPLACE TRIGGER trg_auto_set_status_based_on_date
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
   IF :NEW.end_date IS NOT NULL THEN
      :NEW.status := 'INACTIVE';
   ELSE
      :NEW.status := 'ACTIVE';
   END IF;
END;
/

67. Trigger to Prevent Insert if Department is Full

CREATE OR REPLACE TRIGGER trg_prevent_insert_if_department_full
BEFORE INSERT ON employees
FOR EACH ROW
DECLARE
   department_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO department_count
   FROM employees
   WHERE department_id = :NEW.department_id;

IF department_count >= 100 THEN
RAISE_APPLICATION_ERROR(-20032, 'Department is full.');
END IF;
END;
/

68. Trigger to Log Changes to Phone Number

CREATE OR REPLACE TRIGGER trg_log_phone_number_changes
AFTER UPDATE OF phone_number ON employees
FOR EACH ROW
BEGIN
   IF :NEW.phone_number <> :OLD.phone_number THEN
      INSERT INTO phone_number_audit (employee_id, old_phone_number, new_phone_number, change_date)
      VALUES (:OLD.employee_id, :OLD.phone_number, :NEW.phone_number, SYSDATE);
   END IF;
END;
/

69. Trigger to Restrict Updates to Active Employees

CREATE OR REPLACE TRIGGER trg_restrict_updates_to_active_employees
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.status <> 'ACTIVE' THEN
      RAISE_APPLICATION_ERROR(-20033, 'Updates are only allowed for active employees.');
   END IF;
END;
/

70. Trigger to Enforce Salary Based on Job ID

CREATE OR REPLACE TRIGGER trg_enforce_salary_based_on_job_id
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id = 'MANAGER' AND :NEW.salary < 5000 THEN
      RAISE_APPLICATION_ERROR(-20034, 'Salary for managers must be at least 5000.');
   END IF;
END;
/

71. Trigger to Log Insertions

CREATE OR REPLACE TRIGGER trg_log_insertions
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
   INSERT INTO insertion_log (employee_id, insertion_date)
   VALUES (:NEW.employee_id, SYSDATE);
END;
/

72. Trigger to Prevent Updates Based on Date

CREATE OR REPLACE TRIGGER trg_prevent_updates_based_on_date
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.hire_date < TO_DATE('01-JAN-2020', 'DD-MON-YYYY') THEN
      RAISE_APPLICATION_ERROR(-20035, 'Records created before 2020 cannot be updated.');
   END IF;
END;
/

73. Trigger to Automatically Assign Job ID

CREATE OR REPLACE TRIGGER trg_auto_assign_job_id
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id IS NULL THEN
      :NEW.job_id := 'EMPLOYEE';
   END IF;
END;
/

74. Trigger to Enforce Unique Phone Number

CREATE OR REPLACE TRIGGER trg_enforce_unique_phone_number
BEFORE INSERT OR UPDATE OF phone_number ON employees
FOR EACH ROW
DECLARE
   phone_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO phone_count
   FROM employees
   WHERE phone_number = :NEW.phone_number AND employee_id != :NEW.employee_id;

IF phone_count > 0 THEN
RAISE_APPLICATION_ERROR(-20036, 'Phone number must be unique.');
END IF;
END;
/

75. Trigger to Log Updates to Department ID

CREATE OR REPLACE TRIGGER trg_log_department_id_updates
AFTER UPDATE OF department_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id <> :OLD.department_id THEN
      INSERT INTO department_id_audit (employee_id, old_department_id, new_department_id, change_date)
      VALUES (:OLD.employee_id, :OLD.department_id, :NEW.department_id, SYSDATE);
   END IF;
END;
/

76. Trigger to Restrict Updates to Salary

CREATE OR REPLACE TRIGGER trg_restrict_salary_updates
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary > 10000 THEN
      RAISE_APPLICATION_ERROR(-20037, 'Salary cannot exceed 10000.');
   END IF;
END;
/

77. Trigger to Automatically Set Job ID Based on Department

CREATE OR REPLACE TRIGGER trg_auto_set_job_id_based_on_department
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id = 10 THEN
      :NEW.job_id := 'MANAGER';
   ELSE
      :NEW.job_id := 'EMPLOYEE';
   END IF;
END;
/

78. Trigger to Log Changes to Email Address

CREATE OR REPLACE TRIGGER trg_log_email_address_changes
AFTER UPDATE OF email ON employees
FOR EACH ROW
BEGIN
   IF :NEW.email <> :OLD.email THEN
      INSERT INTO email_audit (employee_id, old_email, new_email, change_date)
      VALUES (:OLD.employee_id, :OLD.email, :NEW.email, SYSDATE);
   END IF;
END;
/

79. Trigger to Enforce Minimum Age for Employees

CREATE OR REPLACE TRIGGER trg_enforce_minimum_age
BEFORE INSERT OR UPDATE OF date_of_birth ON employees
FOR EACH ROW
DECLARE
   age INTEGER;
BEGIN
   age := TRUNC(MONTHS_BETWEEN(SYSDATE, :NEW.date_of_birth) / 12);

IF age < 21 THEN
RAISE_APPLICATION_ERROR(-20038, 'Employee must be at least 21 years old.');
END IF;
END;
/

80. Trigger to Log Changes to Status

CREATE OR REPLACE TRIGGER trg_log_status_changes
AFTER UPDATE OF status ON employees
FOR EACH ROW
BEGIN
   IF :NEW.status <> :OLD.status THEN
      INSERT INTO status_audit (employee_id, old_status, new_status, change_date)
      VALUES (:OLD.employee_id, :OLD.status, :NEW.status, SYSDATE);
   END IF;
END;
/

81. Trigger to Prevent Updates to Manager ID

CREATE OR REPLACE TRIGGER trg_prevent_manager_id_update
BEFORE UPDATE OF manager_id ON employees
FOR EACH ROW
BEGIN
   IF :OLD.job_id = 'MANAGER' THEN
      RAISE_APPLICATION_ERROR(-20039, 'Manager ID cannot be updated.');
   END IF;
END;
/

82. Trigger to Automatically Assign Default Manager

CREATE OR REPLACE TRIGGER trg_auto_assign_default_manager
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.manager_id IS NULL THEN
      :NEW.manager_id := 100; -- Default Manager ID
   END IF;
END;
/

83. Trigger to Log Salary Changes

CREATE OR REPLACE TRIGGER trg_log_salary_changes
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   INSERT INTO salary_audit_log (employee_id, old_salary, new_salary, change_date)
   VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

84. Trigger to Prevent Insert if Department is Full

CREATE OR REPLACE TRIGGER trg_prevent_insert_if_department_full
BEFORE INSERT ON employees
FOR EACH ROW
DECLARE
   department_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO department_count
   FROM employees
   WHERE department_id = :NEW.department_id;

IF department_count >= 50 THEN
RAISE_APPLICATION_ERROR(-20040, 'Department is full.');
END IF;
END;
/

85. Trigger to Enforce Maximum Salary Based on Job ID

CREATE OR REPLACE TRIGGER trg_enforce_max_salary_based_on_job_id
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id = 'EMPLOYEE' AND :NEW.salary > 5000 THEN
      RAISE_APPLICATION_ERROR(-20041, 'Salary for employees cannot exceed 5000.');
   END IF;
END;
/

86. Trigger to Log Department Changes

CREATE OR REPLACE TRIGGER trg_log_department_changes
AFTER UPDATE OF department_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id <> :OLD.department_id THEN
      INSERT INTO department_audit (employee_id, old_department_id, new_department_id, change_date)
      VALUES (:OLD.employee_id, :OLD.department_id, :NEW.department_id, SYSDATE);
   END IF;
END;
/

87. Trigger to Restrict Deletion of Employees with Active Assignments

CREATE OR REPLACE TRIGGER trg_restrict_deletion_of_active_assignments
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.status = 'ACTIVE' THEN
      RAISE_APPLICATION_ERROR(-20042, 'Employees with active assignments cannot be deleted.');
   END IF;
END;
/

88. Trigger to Automatically Set Hire Date

CREATE OR REPLACE TRIGGER trg_auto_set_hire_date
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
   IF :NEW.hire_date IS NULL THEN
      :NEW.hire_date := SYSDATE;
   END IF;
END;
/

89. Trigger to Log Updates to Manager ID

CREATE OR REPLACE TRIGGER trg_log_manager_id_updates
AFTER UPDATE OF manager_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.manager_id <> :OLD.manager_id THEN
      INSERT INTO manager_audit (employee_id, old_manager_id, new_manager_id, change_date)
      VALUES (:OLD.employee_id, :OLD.manager_id, :NEW.manager_id, SYSDATE);
   END IF;
END;
/

90. Trigger to Restrict Salary Decrease

CREATE OR REPLACE TRIGGER trg_restrict_salary_decrease
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < :OLD.salary THEN
      RAISE_APPLICATION_ERROR(-20043, 'Salary cannot be decreased.');
   END IF;
END;
/

91. Trigger to Enforce Unique Combination of Name and DOB

CREATE OR REPLACE TRIGGER trg_enforce_unique_name_dob_combination
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW
DECLARE
   name_dob_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO name_dob_count
   FROM employees
   WHERE first_name = :NEW.first_name AND last_name = :NEW.last_name AND date_of_birth = :NEW.date_of_birth AND employee_id != :NEW.employee_id;

IF name_dob_count > 0 THEN
RAISE_APPLICATION_ERROR(-20044, 'Combination of first name, last name, and date of birth must be unique.');
END IF;
END;
/

92. Trigger to Log Email Changes

CREATE OR REPLACE TRIGGER trg_log_email_changes
AFTER UPDATE OF email ON employees
FOR EACH ROW
BEGIN
   INSERT INTO email_audit_log (employee_id, old_email, new_email, change_date)
   VALUES (:OLD.employee_id, :OLD.email, :NEW.email, SYSDATE);
END;
/

93. Trigger to Restrict Updates to Managers

CREATE OR REPLACE TRIGGER trg_restrict_updates_to_managers
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.job_id = 'MANAGER' THEN
      RAISE_APPLICATION_ERROR(-20045, 'Managers cannot be updated.');
   END IF;
END;
/

94. Trigger to Log Phone Number Changes

CREATE OR REPLACE TRIGGER trg_log_phone_number_changes
AFTER UPDATE OF phone_number ON employees
FOR EACH ROW
BEGIN
   INSERT INTO phone_number_audit_log (employee_id, old_phone_number, new_phone_number, change_date)
   VALUES (:OLD.employee_id, :OLD.phone_number, :NEW.phone_number, SYSDATE);
END;
/

95. Trigger to Prevent Update if Department is Full

CREATE OR REPLACE TRIGGER trg_prevent_update_if_department_full
BEFORE UPDATE ON employees
FOR EACH ROW
DECLARE
   department_count INTEGER;
BEGIN
   SELECT COUNT(*) INTO department_count
   FROM employees
   WHERE department_id = :NEW.department_id;

IF department_count >= 100 THEN
RAISE_APPLICATION_ERROR(-20046, 'Department is full.');
END IF;
END;
/

96. Trigger to Enforce Minimum Salary

CREATE OR REPLACE TRIGGER trg_enforce_minimum_salary
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < 3000 THEN
      RAISE_APPLICATION_ERROR(-20047, 'Salary must be at least 3000.');
   END IF;
END;
/

97. Trigger to Log Updates to Full Name

CREATE OR REPLACE TRIGGER trg_log_full_name_updates
AFTER UPDATE OF first_name, last_name ON employees
FOR EACH ROW
BEGIN
   INSERT INTO full_name_audit_log (employee_id, old_full_name, new_full_name, change_date)
   VALUES (:OLD.employee_id, :OLD.first_name || ' ' || :OLD.last_name, :NEW.first_name || ' ' || :NEW.last_name, SYSDATE);
END;
/

98. Trigger to Prevent Update if Employee is Inactive

CREATE OR REPLACE TRIGGER trg_prevent_update_if_inactive
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
   IF :OLD.status = 'INACTIVE' THEN
      RAISE_APPLICATION_ERROR(-20048, 'Inactive employees cannot be updated.');
   END IF;
END;
/

99. Trigger to Enforce Salary Cap Based on Job ID

CREATE OR REPLACE TRIGGER trg_enforce_salary_cap_based_on_job_id
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.job_id = 'EXECUTIVE' AND :NEW.salary > 20000 THEN
      RAISE_APPLICATION_ERROR(-20049, 'Salary for executives cannot exceed 20000.');
   END IF;
END;
/

100. Trigger to Log Department ID Changes

CREATE OR REPLACE TRIGGER trg_log_department_id_changes
AFTER UPDATE OF department_id ON employees
FOR EACH ROW
BEGIN
   IF :NEW.department_id <> :OLD.department_id THEN
      INSERT INTO department_id_audit_log (employee_id, old_department_id, new_department_id, change_date)
      VALUES (:OLD.employee_id, :OLD.department_id, :NEW.department_id, SYSDATE);
   END IF;
END;
/