Oracle Database Guide — SQL, PL/SQL, and Enterprise Features
Oracle Database is a multi-model enterprise relational database management system known for its high performance, scalability, security features, and support for SQL and PL/SQL across mission-critical applications worldwide.
What You’ll Learn
By the end of this tutorial, you’ll understand Oracle Database architecture, connect using SQL*Plus, write SQL and PL/SQL queries, create tables with constraints and indexes, work with sequences and views, and use Oracle-specific features like materialized views and partitioning.
Why Oracle Matters
Oracle powers the world’s largest financial systems, government databases, and enterprise resource planning platforms. DodaZIP’s cloud backend uses Oracle for compliance-critical audit logs, while Durga Antivirus Pro leverages Oracle for its threat intelligence warehouse. Mastering Oracle opens doors to enterprise database administration and high-paying backend roles.
Oracle Learning Path
flowchart LR
A[SQL Basics] --> B[MySQL]
B --> C[Oracle]
C --> D[SQL Server]
D --> E[MongoDB]
E --> F[Database Design]
C --> G{You Are Here}
style G fill:#f90,color:#fff
What Is Oracle Database? (The “Why” First)
Think of Oracle Database as a fortress for enterprise data. Unlike MySQL or PostgreSQL which are designed for web applications, Oracle is built for environments where data loss is simply not an option — banking systems, air traffic control, hospital records. It offers features like Real Application Clusters (RAC) for high availability, Advanced Security for encryption, and partitioning for managing petabytes of data.
Oracle Database Editions
| Edition | Use Case | Key Limitation |
|---|---|---|
| Enterprise Edition | Large-scale production | Most expensive, full feature set |
| Standard Edition 2 | Mid-range servers | Limited to 2 sockets, no RAC |
| Express Edition (XE) | Learning, small apps | 12GB user data, 2GB RAM limit |
| Free | Developer sandbox | Same limits as XE, no cost |
Connecting with SQL*Plus
SQL*Plus is Oracle’s command-line interface — your direct line to the database:
# Connect as system administrator
sqlplus system/your_password@localhost:1521/XEPDB1
# Expected output:
# Connected to:
# Oracle Database 21c Express Edition Release 21.0.0.0.0-- View your current user and database
SELECT USER, SYSDATE FROM DUAL;
-- Output:
-- USER | SYSDATE
-- SYSTEM | 2026-06-07 10:30:00DUAL is a special Oracle table with one row, used for queries that don’t need a real table. It’s unique to Oracle — no other database has it.
Creating Tables with Oracle-Specific Features
Oracle has its own data types and table creation syntax:
-- Create a customers table with Oracle features
CREATE TABLE customers (
customer_id NUMBER(10) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
first_name VARCHAR2(50) NOT NULL,
last_name VARCHAR2(50) NOT NULL,
email VARCHAR2(100) NOT NULL,
phone VARCHAR2(20),
credit_limit NUMBER(10, 2) CHECK (credit_limit > 0),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR2(20) DEFAULT 'ACTIVE'
);
-- Create an orders table
CREATE TABLE orders (
order_id NUMBER(10) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
customer_id NUMBER(10) NOT NULL,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
total_amount NUMBER(12, 2) NOT NULL,
status VARCHAR2(20) DEFAULT 'PENDING',
CONSTRAINT fk_orders_customer
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
-- Add a comment on a column
COMMENT ON COLUMN customers.credit_limit IS 'Maximum credit allowed for this customer';Oracle-Specific Features:
NUMBER(precision, scale)— Oracle’s numeric type (replaces INT, DECIMAL from other databases)VARCHAR2— Oracle’s variable-length string type (use this instead of VARCHAR)GENERATED BY DEFAULT AS IDENTITY— Oracle 12c+ auto-increment (replaces AUTO_INCREMENT)COMMENT ON COLUMN— documentation stored in the data dictionaryCHECKconstraints — inline validation without separate triggers
Sequences — Oracle’s Auto-Increment
Before identity columns (pre-12c), Oracle used sequences for generating unique numbers:
-- Create a sequence
CREATE SEQUENCE customer_seq
START WITH 1000
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- Use the sequence in an INSERT
INSERT INTO customers (customer_id, first_name, last_name, email)
VALUES (customer_seq.NEXTVAL, 'Alice', 'Johnson', 'alice@example.com');
-- Check the current value without incrementing
SELECT customer_seq.CURRVAL FROM DUAL;Output:
CURRVAL
1000Sequences are still widely used in legacy Oracle systems. They’re more flexible than AUTO_INCREMENT — you can cache values, cycle after reaching a maximum, and control increment size.
SQL vs PL/SQL in Oracle
| Feature | SQL | PL/SQL |
|---|---|---|
| Purpose | Data querying and manipulation | Procedural logic + SQL |
| Execution | Statement at a time | Block at a time |
| Variables | No (except bind variables) | Yes (DECLARE section) |
| Control flow | No | IF, LOOP, WHILE, FOR |
| Error handling | Minimal | EXCEPTION block |
| Speed | Fast for single statements | Faster for multi-step operations |
PL/SQL Example — Stored Procedure
CREATE OR REPLACE PROCEDURE apply_credit_increase (
p_customer_id NUMBER,
p_increase_percent NUMBER
) AS
v_current_limit NUMBER(10, 2);
BEGIN
-- Get the current credit limit
SELECT credit_limit INTO v_current_limit
FROM customers
WHERE customer_id = p_customer_id;
-- Update with the increase
UPDATE customers
SET credit_limit = v_current_limit * (1 + p_increase_percent / 100)
WHERE customer_id = p_customer_id;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Credit limit increased for customer ' || p_customer_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Customer not found: ' || p_customer_id);
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END apply_credit_increase;
/
-- Call the procedure
EXEC apply_credit_increase(1000, 10);Indexes — Optimizing Query Performance
Oracle offers multiple index types:
-- B-tree index (default) — good for equality and range queries
CREATE INDEX idx_customers_email ON customers(email);
-- Bitmap index — good for low-cardinality columns (status, gender)
CREATE BITMAP INDEX idx_orders_status ON orders(status);
-- Function-based index — index on an expression
CREATE INDEX idx_customers_upper_email ON customers(UPPER(email));
-- Check index usage
SELECT index_name, index_type, uniqueness
FROM user_indexes
WHERE table_name = 'CUSTOMERS';Output:
INDEX_NAME | INDEX_TYPE | UNIQUENESS
IDX_CUSTOMERS_EMAIL | NORMAL | NONUNIQUE
IDX_CUSTOMERS_UPPER_EMAIL | FUNCTION-BASED NORMAL | NONUNIQUEViews and Materialized Views
Regular View — A Saved Query
CREATE OR REPLACE VIEW vw_customer_orders AS
SELECT
c.customer_id,
c.first_name || ' ' || c.last_name AS full_name,
COUNT(o.order_id) AS order_count,
NVL(SUM(o.total_amount), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name;
-- Query the view (looks like a table)
SELECT * FROM vw_customer_orders WHERE total_spent > 1000;Materialized View — Physically Stored Results
-- Refreshed daily
CREATE MATERIALIZED VIEW mv_monthly_sales
REFRESH COMPLETE
START WITH SYSDATE
NEXT SYSDATE + 1
AS
SELECT
TRUNC(order_date, 'MM') AS month,
COUNT(*) AS order_count,
SUM(total_amount) AS revenue
FROM orders
GROUP BY TRUNC(order_date, 'MM');Materialized views are a killer Oracle feature. Unlike regular views (which run the query every time), materialized views store the result on disk and refresh on a schedule. They dramatically speed up dashboard queries on large datasets.
Oracle Architecture
flowchart TB
subgraph Users
U1[User Process]
U2[User Process]
end
subgraph Instance
SGA[Shared Global Area]
PMON[PMON]
SMON[SMON]
DBWR[DB Writer]
LGWR[Log Writer]
CKPT[Checkpoint]
end
subgraph Storage
DF[Data Files]
CF[Control Files]
RF[Redo Log Files]
end
U1 --> SGA
U2 --> SGA
SGA --> DBWR --> DF
SGA --> LGWR --> RF
PMON --> SGA
SMON --> SGA
CKPT --> DF
Oracle’s architecture separates the instance (memory + background processes) from the database (disk storage). This allows multiple instances to access the same database (RAC) for high availability.
Common Oracle Errors
1. ORA-00942: Table or View Does Not Exist
-- The table might not exist, or you don't have SELECT privilege
SELECT * FROM secret_table;
-- ORA-00942: table or view does not existFix: Check the table name spelling and verify privileges with SELECT * FROM ALL_TABLES WHERE TABLE_NAME = 'SECRET_TABLE'.
2. ORA-00001: Unique Constraint Violated
INSERT INTO customers (customer_id, email) VALUES (1000, 'alice@example.com');
-- If customer_id 1000 or email already exists:
-- ORA-00001: unique constraint (SYSTEM.SYS_C0012345) violatedFix: Use MERGE (upsert) or check for existing records first.
3. ORA-00933: SQL Command Not Properly Ended
-- WRONG — Oracle doesn't support JOIN ... USING with AS table alias before 23c
SELECT * FROM orders o JOIN customers c USING (customer_id);
-- RIGHT
SELECT * FROM orders o JOIN customers c ON o.customer_id = c.customer_id;4. ORA-01400: Cannot Insert NULL
INSERT INTO customers (first_name, last_name) VALUES (NULL, 'Smith');
-- ORA-01400: cannot insert NULL into ("SYSTEM"."CUSTOMERS"."FIRST_NAME")Fix: Always provide values for NOT NULL columns, or use NVL / COALESCE to supply defaults.
5. ORA-01555: Snapshot Too Old
This occurs when a long-running query tries to read a previous version of a block that has been overwritten. Fix: Increase UNDO_RETENTION or tune the query to run faster.
6. ORA-01722: Invalid Number
SELECT * FROM customers WHERE customer_id = 'ABC';
-- ORA-01722: invalid numberFix: Don’t compare NUMBER columns with string literals. Remove non-numeric characters before conversion.
7. ORA-01017: Invalid Username/Password
Fix: Reset the password using ALTER USER username IDENTIFIED BY new_password as a DBA.
Practice Questions
1. What is the difference between SQL and PL/SQL?
SQL is for querying and manipulating data one statement at a time. PL/SQL is Oracle’s procedural extension that adds variables, loops, conditionals, and error handling — allowing multiple SQL operations in a single block.
2. What is a sequence in Oracle?
A sequence is a database object that generates unique numeric values. It’s commonly used for primary key generation, replacing AUTO_INCREMENT from other databases. You access it with NEXTVAL (get next) and CURRVAL (get current).
3. How is a materialized view different from a regular view?
A regular view is a saved query that runs each time you access it. A materialized view stores the query results physically on disk and refreshes on a schedule — it’s faster for queries but uses storage and can be stale.
4. Challenge: Write a PL/SQL block that loops through all customers and prints their names.
BEGIN
FOR rec IN (SELECT first_name, last_name FROM customers) LOOP
DBMS_OUTPUT.PUT_LINE('Customer: ' || rec.first_name || ' ' || rec.last_name);
END LOOP;
END;
/5. What does DUAL do in Oracle?
DUAL is a dummy table with one row, used for SELECT statements that don’t need data from a real table — like SELECT SYSDATE FROM DUAL. It’s Oracle-specific and required in many contexts where other databases don’t need a FROM clause.
Real-World Task: Create an Audit Log System
Design a schema for tracking changes to sensitive data — like what Durga Antivirus Pro uses for security audits:
-- Audit log table
CREATE TABLE audit_log (
audit_id NUMBER(10) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
table_name VARCHAR2(100) NOT NULL,
action VARCHAR2(10) NOT NULL CHECK (action IN ('INSERT', 'UPDATE', 'DELETE')),
record_id NUMBER(10) NOT NULL,
old_values CLOB,
new_values CLOB,
changed_by VARCHAR2(100) DEFAULT USER,
changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Trigger to capture changes on customers table
CREATE OR REPLACE TRIGGER trg_customers_audit
AFTER INSERT OR UPDATE OR DELETE ON customers
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO audit_log (table_name, action, record_id, new_values)
VALUES ('CUSTOMERS', 'INSERT', :NEW.customer_id,
'first_name=' || :NEW.first_name || ', email=' || :NEW.email);
ELSIF UPDATING THEN
INSERT INTO audit_log (table_name, action, record_id,
old_values, new_values)
VALUES ('CUSTOMERS', 'UPDATE', :OLD.customer_id,
'first_name=' || :OLD.first_name,
'first_name=' || :NEW.first_name);
ELSIF DELETING THEN
INSERT INTO audit_log (table_name, action, record_id, old_values)
VALUES ('CUSTOMERS', 'DELETE', :OLD.customer_id,
'first_name=' || :OLD.first_name || ', email=' || :OLD.email);
END IF;
END;
/FAQ
Try It Yourself
Create the customers and orders schema above in Oracle XE, then run these queries:
-- Which customers haven't ordered anything?
SELECT c.first_name, c.last_name
FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);
-- Monthly order summary
SELECT
TO_CHAR(order_date, 'YYYY-MM') AS month,
COUNT(*) AS orders,
SUM(total_amount) AS revenue
FROM orders
GROUP BY TO_CHAR(order_date, 'YYYY-MM')
ORDER BY month;
-- Customer ranking by total spend
SELECT
first_name || ' ' || last_name AS customer,
NVL(SUM(total_amount), 0) AS total_spent,
RANK() OVER (ORDER BY NVL(SUM(total_amount), 0) DESC) AS rank
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, first_name, last_name;These query patterns are used by DodaZIP for cloud file audit trails and by Durga Antivirus Pro for analyzing threat detection patterns across enterprise deployments.
What’s Next
Congratulations on completing this Oracle Database tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro