DATABASE LOGIC

How to give your database a working brain.

SQL is just asking for data. PL/SQL is asking for data, thinking about it, and making decisions—all without leaving the database.

Plain SQL

SQL is a simple language. It can only ask simple questions.

SELECT * FROM customers;
  • Cannot make choices (If/Then).
  • Cannot repeat tasks easily (Loops).
  • Crashes hard if there is an error.

PL/SQL

PL/SQL is a full programming language built exactly for Oracle databases.

IF customer_score > 100 THEN
  give_discount();
END IF;
  • Can make smart choices.
  • Can process millions of rows in a loop.
  • Catches errors and keeps working safely.

The Secret to High Speed

Why do big companies use PL/SQL? It stops data from traveling back and forth over the network. If your code lives in the database, it processes data instantly.

The Slow Way (No PL/SQL)

Your App
10,000 TRIPS
Database

The app asks for a row, waits, processes it, and sends it back. It repeats this 10,000 times. This is extremely slow.

The Fast Way (PL/SQL)

Your App
1 SINGLE TRIP
DB + PL/SQL CODE

The app sends one single command: "Do the job." The database does all 10,000 checks internally and instantly.

The 4 Parts of Every PL/SQL Job

Every piece of PL/SQL code is built like a sandwich. It has a specific start, middle, and end. We call this a "Block".

1. DECLARE

(Optional)

The Setup Area

Before you do any work, you must tell the database what tools you need. If you need a box to hold a number, you make it here.

DECLARE
  total_sales NUMBER;
2. BEGIN

(Required)

The Work Area

This is where the actual action happens. You look at data, change data, and do your math here.

BEGIN
  total_sales := 500 + 200;
  UPDATE customers SET money = total_sales;
3. EXCEPTION

(Optional)

The Safety Net

If something goes wrong in the "BEGIN" area, the code drops down to here instead of crashing.

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    print('Nobody is here!');
4. END

(Required)

The Finish Line

This simply tells the database that your code block is completely finished.

END;

Variables (Memory Boxes)

Variables are like labeled boxes. You put data in them so you can remember it and use it later in your code.

1
v_name
Holds Text (VARCHAR2)
2
v_age
Holds Numbers (NUMBER)

Decisions (IF/THEN)

Your code can look at data and choose different paths, just like a car at a fork in the road.

IF customer_points > 500 THEN
  -- Path A
  upgrade_to_gold();
ELSE
  -- Path B
  send_warning_email();
END IF;

Doing Chores Fast (Loops)

Imagine you have 5,000 users. You need to add $10 to every account. Doing this one by one by hand would take weeks. A PL/SQL "Loop" does this automatically in a fraction of a second.

  • FOR Loop (Counts 1 to 10)
  • WHILE Loop (Runs until told to stop)
  • CURSOR Loop (Runs for every row in a table)
-- Give $10 to all 5,000 users

FOR current_user IN 1..5000 LOOP
  add_money(current_user, 10);
END LOOP;

The 3 Big Tools in Enterprise Databases

Stored Procedures

A saved set of instructions. Once you write the code, you save it inside the database. Anyone can run it later by just calling its name, like pressing a button.

EXECUTE pay_employees();

Functions

A machine that does math. You give it information, it calculates something, and it returns a final answer back to you.

tax := calculate_tax(500);

Triggers

An invisible tripwire. You tell the database: "If someone deletes a record, automatically copy it to a backup table first."

AFTER DELETE ON users...
ERROR HANDLING

What Happens When Things Break?

In standard systems, an error crashes the whole program. PL/SQL uses "Exceptions". When an error drops, the Exception net catches it safely.

Trying to update user #999...
ERROR: User #999 does not exist!
EXCEPTION CAUGHT. Writing error to log. Program continues smoothly.

Putting It All Together

Let's look at a real, complete piece of PL/SQL code designed to give a bonus to top employees.

award_bonus_procedure.sql
-- 1. Setup Area
DECLARE
  v_bonus_amount  NUMBER := 500; -- Create a box holding the number 500
  v_employee_id   NUMBER := 101; -- Create a box holding the ID 101

-- 2. Work Area
BEGIN
  -- Update the database directly
  UPDATE employees 
  SET salary = salary + v_bonus_amount
  WHERE id = v_employee_id;

  -- Check if anything actually changed
  IF SQL%NOTFOUND THEN
    -- If no employee was found, trigger an error on purpose
    RAISE NO_DATA_FOUND;
  END IF;

  -- Save the changes permanently
  COMMIT;

-- 3. Safety Net Area
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    dbms_output.put_line('Stop! This employee does not exist.');
  WHEN OTHERS THEN
    dbms_output.put_line('Something else went completely wrong.');

-- 4. Finish Line
END;

Cursors: The Data Conveyor Belt

If you ask SQL for 1,000 customers, it dumps all 1,000 on your desk at once. This can crash your memory. A Cursor acts like a factory conveyor belt. It holds the data in the database and hands you exactly one row at a time.

1. OPEN Conveyor_Belt;
2. FETCH next_row;
3. PROCESS data;
4. CLOSE Conveyor_Belt;

Why use it?

  • It uses almost zero memory.
  • You can stop processing halfway through if you find what you need.
  • Perfect for sending line-by-line emails or printing reports.

Parameters: The Mailboxes

Procedures are useless if they always do the exact same thing. You need to give them new instructions. We do this using Parameters (labeled mailboxes attached to your code).

IN

Data you give TO the code.

p_user_id IN NUMBER

The Engine

Calculates total score based on the given user ID.

OUT

The final answer it gives back.

p_score OUT NUMBER

Packages: The Toolbox

If you write 500 different functions, your database becomes a messy junk drawer. A Package is a digital folder that groups related procedures, functions, and variables together.

Performance Bonus: When you use one tool in a package, the database loads the entire package into memory. The next tool you use is instantly ready.
HR_PACKAGE
Procedure: hire_employee()
Function: calculate_payroll()
Procedure: fire_employee()

Strict Data Types

PL/SQL is very strict. You cannot put a word into a box meant for dates. You must declare the "shape" of your box first.

VARCHAR2

Words, names, addresses. Always needs a max length.

VARCHAR2(50)

NUMBER

Math, prices, IDs. Handles decimals perfectly.

NUMBER(10,2)

DATE

Stores Year, Month, Day, Hour, Minute, and Second.

DATE

BOOLEAN

Simple logic. Can only be TRUE, FALSE, or NULL.

BOOLEAN

CASE Statements

If you have 10 different options, writing 10 IF/THEN rules gets messy. A CASE statement acts like a clean train switchboard, routing data down the exact correct track immediately.

v_discount := CASE customer_tier
  WHEN 'BRONZE' THEN 5
  WHEN 'SILVER' THEN 10
  WHEN 'GOLD' THEN 20
  ELSE 0 -- Default fallback
END;
B
Give 5% Off
S
Give 10% Off
G
Give 20% Off

Talking to the Screen (Debugging)

Because PL/SQL runs deep inside the database server, you can't normally see what it's doing. If you need to print a message to your screen to test your logic, you use the built-in megaphone: DBMS_OUTPUT.

SQL*Plus Terminal
SQL> SET SERVEROUTPUT ON;
SQL> EXECUTE test_procedure;
Starting loop...
Checking user ID: 101
WARNING: User 101 has zero balance!
Checking user ID: 102
Loop finished. Processed 2 users.
SQL>

COMMIT (The Save Button)

When you update data, it is only changed in your private memory. No one else can see it yet. COMMIT makes your changes permanent and visible to the whole company.

COMMIT;

ROLLBACK (The Undo Button)

Did you accidentally delete the entire database instead of one row? Don't panic. As long as you haven't typed COMMIT, you can type ROLLBACK to undo everything like it never happened.

ROLLBACK;

Bulk Collect: The Giant Shovel

A standard Loop goes back and forth to the data tables 1,000 times to get 1,000 rows. BULK COLLECT takes a giant shovel, scoops up all 1,000 rows at once, and drops them into memory. It is extremely fast.

REGULAR LOOP (SLOW)
Fetching 1 by 1...
BULK COLLECT (FAST)
1 Massive Fetch

Security: Stopping Hackers

Hackers use "SQL Injection" to trick your database. If you let users type directly into your SQL queries, they can type "DROP TABLE users" and destroy everything.

Bind Variables act like quarantine zones. They tell the database: "Treat this input as plain text, NOT as code."

DANGEROUS (DO NOT DO THIS): sql_stmt := 'SELECT * FROM users WHERE name = ' || user_input;
SAFE (BIND VARIABLE): sql_stmt := 'SELECT * FROM users WHERE name = :1';
EXECUTE IMMEDIATE sql_stmt USING user_input;

The Night Shift (Job Scheduling)

You don't have to be at your desk to run PL/SQL. You can use DBMS_SCHEDULER to tell the database to automatically run your procedures at a specific time, like midnight every Sunday.

12:00 AM
RUN backup_data()
08:00 AM