Oracle
Updated: May 22, 2026Categories: Query
Printed from:
Oracle Database Comprehensive Cheatsheet
1. Connection and Basic Commands
SQL*Plus Connection
SQL
1234567891011121314151617181920-- Connect to database (Easy Connect syntax)
sqlplus username/password@//host:1521/service_name
-- Connect with sys privileges
sqlplus / as sysdba
-- Show current user
SHOW USER;
-- Show current container (CDB/PDB context)
SHOW CON_NAME;
-- Switch to a pluggable database
ALTER SESSION SET CONTAINER = my_pdb;
-- Show current connection details
SELECT sys_context('USERENV', 'CON_NAME'),
sys_context('USERENV', 'DB_NAME')
FROM dual;
Since Oracle 21c, the non-CDB architecture is desupported. All new databases in 19c+ and 23ai are multitenant (CDB with one or more PDBs).
Command Line Basics
Bash
123456789101112# Start Oracle listener
lsnrctl start
# Stop Oracle listener
lsnrctl stop
# Check listener status
lsnrctl status
# Start the database (from SQL*Plus as sysdba)
# STARTUP; SHUTDOWN IMMEDIATE;
2. Database and Schema Operations
Create and Manage Schemas
SQL
12345678910111213141516171819-- Create a local user inside a PDB
-- (Common users in the CDB root must be prefixed with C##)
CREATE USER enterprise_user IDENTIFIED BY "StrongP@ssw0rd"
DEFAULT TABLESPACE users
QUOTA UNLIMITED ON users;
-- Grant privileges (RESOURCE no longer implies UNLIMITED TABLESPACE since 12c)
GRANT CONNECT, RESOURCE, CREATE VIEW TO enterprise_user;
-- Schema-only (passwordless) account — useful for app schemas (19c+)
CREATE USER app_schema NO AUTHENTICATION;
-- Alter user password
ALTER USER enterprise_user IDENTIFIED BY "NewPassword123";
-- Lock/Unlock user account
ALTER USER enterprise_user ACCOUNT LOCK;
ALTER USER enterprise_user ACCOUNT UNLOCK;
3. Table Operations
Create Table
SQL
123456789101112131415161718192021-- Basic table creation (23ai: IF NOT EXISTS supported)
CREATE TABLE IF NOT EXISTS employees (
employee_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
first_name VARCHAR2(50) NOT NULL,
last_name VARCHAR2(50) NOT NULL,
email VARCHAR2(100) UNIQUE,
is_active BOOLEAN DEFAULT TRUE, -- 23ai native BOOLEAN
hire_date DATE DEFAULT SYSDATE,
salary NUMBER(10,2) CHECK (salary > 0)
);
-- Create table with foreign key
CREATE TABLE departments (
dept_id NUMBER PRIMARY KEY,
dept_name VARCHAR2(100),
manager_id NUMBER,
CONSTRAINT fk_manager
FOREIGN KEY (manager_id)
REFERENCES employees(employee_id)
);
Alter Table
SQL
123456789101112-- Add column (23ai: IF NOT EXISTS supported)
ALTER TABLE employees ADD (phone_number VARCHAR2(20));
-- Modify column
ALTER TABLE employees MODIFY (email VARCHAR2(150));
-- Drop column
ALTER TABLE employees DROP COLUMN phone_number;
-- Rename table
RENAME employees TO company_employees;
Drop Table
SQL
123-- Drop table with cascade constraints (23ai: IF EXISTS supported)
DROP TABLE IF EXISTS employees CASCADE CONSTRAINTS;
4. Oracle-Specific Data Types
SQL
12345678910111213141516-- Common Oracle Data Types
NUMBER(p,s) -- Numeric with precision and scale
VARCHAR2(size) -- Variable-length character string (up to 32767 with extended strings)
CHAR(size) -- Fixed-length character string
DATE -- Date and time (second precision)
TIMESTAMP -- More precise date and time (fractional seconds)
TIMESTAMP WITH TIME ZONE
INTERVAL YEAR TO MONTH / DAY TO SECOND
RAW(size) -- Binary data
CLOB / NCLOB -- Character large object
BLOB -- Binary large object
JSON -- Native JSON type (21c+) — preferred over VARCHAR2/CLOB+IS JSON
BOOLEAN -- Native SQL BOOLEAN (23ai)
VECTOR(dim, type) -- AI Vector Search type (23ai), e.g. VECTOR(1536, FLOAT32)
XMLTYPE -- XML data type
5. CRUD Operations
Insert
SQL
1234567891011121314151617-- Basic insert
INSERT INTO employees
(first_name, last_name, email, salary)
VALUES
('John', 'Doe', 'john.doe@company.com', 75000);
-- Multi-row VALUES (23ai table value constructor)
INSERT INTO employees (first_name, last_name, email, salary) VALUES
('John', 'Doe', 'john@co.com', 75000),
('Jane', 'Smith', 'jane@co.com', 85000);
-- Pre-23ai bulk insert (still valid)
INSERT ALL
INTO employees (first_name, last_name, email, salary) VALUES ('John','Doe','john@co.com',75000)
INTO employees (first_name, last_name, email, salary) VALUES ('Jane','Smith','jane@co.com',85000)
SELECT 1 FROM dual;
Select
SQL
123456789101112131415-- Basic select
SELECT * FROM employees;
-- Filtered select with bind variables
SELECT first_name, last_name, salary
FROM employees
WHERE salary > :min_salary
AND department_id = :dept_id;
-- Pagination (Oracle 12c+ row-limiting clause)
SELECT *
FROM employees
ORDER BY employee_id
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
Update
SQL
12345678910111213-- Update with condition
UPDATE employees
SET salary = salary * 1.10
WHERE performance_rating = 'EXCELLENT';
-- Update with subquery
UPDATE departments d
SET manager_id = (
SELECT employee_id
FROM employees e
WHERE e.last_name = 'Smith'
);
Delete
SQL
1234567-- Delete with condition
DELETE FROM employees
WHERE hire_date < ADD_MONTHS(SYSDATE, -120);
-- Truncate (faster than delete for entire table)
TRUNCATE TABLE temp_employees;
6. Joins and Relationships
SQL
12345678910111213141516171819202122232425262728-- Inner Join
SELECT e.first_name, d.dept_name
FROM employees e
JOIN departments d ON e.department_id = d.dept_id;
-- Left Outer Join
SELECT e.first_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.dept_id;
-- Full Outer Join
SELECT e.first_name, d.dept_name
FROM employees e
FULL JOIN departments d ON e.department_id = d.dept_id;
-- Cross Join
SELECT e.first_name, p.product_name
FROM employees e
CROSS JOIN products p;
-- Lateral / cross apply
SELECT e.first_name, t.top_project
FROM employees e,
LATERAL (SELECT project_name AS top_project
FROM projects p
WHERE p.lead_id = e.employee_id
FETCH FIRST 1 ROWS ONLY) t;
7. Indexes and Constraints
SQL
123456789101112131415161718192021222324-- B-Tree Index (default)
CREATE INDEX idx_employee_name
ON employees (last_name, first_name);
-- Unique Index
CREATE UNIQUE INDEX idx_unique_email
ON employees (email);
-- Bitmap Index (low-cardinality columns; avoid on heavily DML'd OLTP tables)
CREATE BITMAP INDEX idx_department
ON employees (department_id);
-- Function-based Index
CREATE INDEX idx_emp_upper_last
ON employees (UPPER(last_name));
-- Invisible Index (test impact before going live)
CREATE INDEX idx_emp_dept ON employees(department_id) INVISIBLE;
-- Check Constraint
ALTER TABLE employees
ADD CONSTRAINT chk_salary
CHECK (salary BETWEEN 30000 AND 500000);
8. Functions and Operators
String Functions
SQL
12345678SELECT
UPPER(first_name) AS upper_name,
LOWER(last_name) AS lower_name,
INITCAP(email) AS proper_case,
SUBSTR(first_name, 1, 3) AS name_prefix,
REGEXP_REPLACE(phone, '[^0-9]', '') AS digits_only
FROM employees;
Date Functions
SQL
123456789SELECT
SYSDATE,
SYSTIMESTAMP,
ADD_MONTHS(hire_date, 12) AS one_year_anniversary,
MONTHS_BETWEEN(SYSDATE, hire_date) AS months_employed,
LAST_DAY(SYSDATE) AS month_end,
TRUNC(SYSDATE, 'IW') AS week_start
FROM employees;
Numeric Functions
SQL
123456SELECT
ROUND(salary, -3) AS salary_rounded,
TRUNC(salary, 0) AS salary_truncated,
MOD(employee_id, 5) AS employee_group
FROM employees;
JSON Functions
SQL
1234567891011121314151617-- Native JSON since 21c; simplified dot-notation and JSON_TABLE
SELECT j.data.customer.name AS customer_name,
j.data.total AS order_total
FROM orders j
WHERE j.data.status = 'PAID';
-- 23ai JSON Relational Duality View — expose relational data as JSON documents
CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW employee_dv AS
SELECT JSON {
'_id' : e.employee_id,
'firstName' : e.first_name,
'lastName' : e.last_name,
'department' : (SELECT JSON {'id': d.dept_id, 'name': d.dept_name}
FROM departments d WHERE d.dept_id = e.department_id)
}
FROM employees e WITH INSERT UPDATE DELETE;
9. Oracle-Specific Features (PL/SQL)
Basic PL/SQL Block
SQL
123456789101112131415SET SERVEROUTPUT ON;
DECLARE
v_employee_count NUMBER;
v_avg_salary NUMBER;
BEGIN
SELECT COUNT(*), AVG(salary)
INTO v_employee_count, v_avg_salary
FROM employees;
DBMS_OUTPUT.PUT_LINE('Total Employees: ' || v_employee_count);
DBMS_OUTPUT.PUT_LINE('Average Salary : ' || v_avg_salary);
END;
/
Stored Procedure
SQL
12345678910111213141516CREATE OR REPLACE PROCEDURE update_employee_salary (
p_employee_id IN NUMBER,
p_raise_percentage IN NUMBER
) AS
BEGIN
UPDATE employees
SET salary = salary * (1 + p_raise_percentage/100)
WHERE employee_id = p_employee_id;
-- Prefer letting the caller commit; commit here only for autonomous units.
END update_employee_salary;
/
-- Execute procedure
EXEC update_employee_salary(1001, 5);
Trigger
SQL
1234567891011121314151617CREATE OR REPLACE TRIGGER trg_audit_employees
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
BEGIN
INSERT INTO employee_audit_log (action, employee_id, change_date)
VALUES (
CASE
WHEN INSERTING THEN 'INSERT'
WHEN UPDATING THEN 'UPDATE'
WHEN DELETING THEN 'DELETE'
END,
COALESCE(:NEW.employee_id, :OLD.employee_id),
SYSDATE
);
END;
/
Sequence / Identity
SQL
123456789101112131415-- Sequence
CREATE SEQUENCE seq_employee_id
START WITH 1
INCREMENT BY 1
MAXVALUE 999999
NOCACHE
NOCYCLE;
-- Use in insert
INSERT INTO employees (employee_id, first_name, last_name)
VALUES (seq_employee_id.NEXTVAL, 'New', 'Employee');
-- Modern preferred form: identity column on the table itself (12c+)
-- See CREATE TABLE example in section 3.
10. Advanced Features
Partitioning
SQL
1234567891011-- Range Partitioning with automatic interval partitions (11g+)
CREATE TABLE sales_data (
sale_date DATE,
product_id NUMBER,
amount NUMBER(10,2)
)
PARTITION BY RANGE (sale_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH')) (
PARTITION p_seed VALUES LESS THAN (DATE '2024-01-01')
);
Materialized Views
SQL
1234567891011CREATE MATERIALIZED VIEW mv_employee_summary
BUILD IMMEDIATE
REFRESH FAST ON COMMIT -- requires materialized view logs
ENABLE QUERY REWRITE
AS
SELECT department_id,
COUNT(*) AS employee_count,
AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id;
Hierarchical Queries
SQL
1234567891011121314151617-- CONNECT BY
SELECT employee_id, first_name, last_name, manager_id, LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
-- Recursive CTE (ANSI alternative)
WITH org (employee_id, manager_id, full_name, lvl) AS (
SELECT employee_id, manager_id, first_name||' '||last_name, 1
FROM employees WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.manager_id, e.first_name||' '||e.last_name, o.lvl + 1
FROM employees e
JOIN org o ON e.manager_id = o.employee_id
)
SELECT * FROM org;
AI Vector Search (23ai)
SQL
12345678910111213-- Store and search embeddings natively
CREATE TABLE doc_chunks (
id NUMBER PRIMARY KEY,
chunk CLOB,
embedding VECTOR(1536, FLOAT32)
);
-- Approximate nearest-neighbor search
SELECT id, chunk
FROM doc_chunks
ORDER BY VECTOR_DISTANCE(embedding, :query_vec, COSINE)
FETCH APPROXIMATE FIRST 10 ROWS ONLY;
11. Performance Optimization
Explain Plan
SQL
123456789EXPLAIN PLAN FOR
SELECT * FROM employees
WHERE department_id = 10;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- Plan from the cursor cache for a recently executed statement
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(sql_id => 'abc123xyz', format => 'ALLSTATS LAST'));
SQL Hints
SQL
123456789-- Force index usage (use sparingly; prefer good statistics + SQL Plan Management)
SELECT /*+ INDEX(employees idx_employee_name) */
first_name, last_name
FROM employees
WHERE last_name LIKE 'S%';
-- Parallel execution hint
SELECT /*+ PARALLEL(employees, 4) */ COUNT(*) FROM employees;
Statistics & SQL Tuning
SQL
12345-- Gather optimizer statistics
EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEES');
-- Real-time / Automatic SQL Plan Management captures and evolves plans automatically.
12. Security and User Management
SQL
12345678910111213141516171819202122-- Create Role
CREATE ROLE enterprise_read_only;
-- Grant privileges to role
GRANT SELECT ON employees TO enterprise_read_only;
-- Create user with role and a mandatory password profile
CREATE USER readonly_user
IDENTIFIED BY "ReadOnlyP@ss123"
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
PROFILE app_profile;
GRANT enterprise_read_only TO readonly_user;
-- Transparent Data Encryption (column-level)
ALTER TABLE employees MODIFY (salary ENCRYPT USING 'AES256');
-- SQL Firewall (23ai) — capture and enforce allow-listed SQL per user
EXEC DBMS_SQL_FIREWALL.ENABLE;
EXEC DBMS_SQL_FIREWALL.CREATE_CAPTURE(username => 'APP_USER', top_level_only => TRUE);
13. Best Practices and Common Patterns
- Always use bind variables — protects against SQL injection and maximises cursor sharing.
- Avoid
SELECT *in production code; list columns explicitly. - Design with the multitenant architecture in mind (CDB/PDB); non-CDB is desupported.
- Prefer identity columns or sequences over application-generated keys.
- Use the native
JSONtype (21c+) and JSON Relational Duality Views (23ai) instead of storing JSON in CLOBs. - Keep optimizer statistics fresh (
DBMS_STATS) and let SQL Plan Management stabilize plans rather than hard-coding hints. - Use
EXPLAIN PLAN/DBMS_XPLAN.DISPLAY_CURSORwithALLSTATS LASTto diagnose real execution. - Handle exceptions explicitly in PL/SQL; avoid
WHEN OTHERS THEN NULL. - Apply least-privilege: grant via roles, use schema-only accounts for application schemas, and enable SQL Firewall on sensitive accounts.
- Use Transparent Data Encryption and Data Redaction for sensitive data at rest and in queries.
- Back up with RMAN and validate restores regularly; consider Oracle Data Guard for DR.
- Patch promptly — apply the latest Release Update (RU) for your release (19c LTS or 23ai).
Note: This cheatsheet reflects features available in Oracle Database 19c (Long Term Support) and Oracle Database 23ai. Always refer to the official Oracle documentation for the most up-to-date and detailed information for your specific release.
Continue Learning
Discover more cheatsheets to boost your productivity