Oracle SQL Patterns Cheat Sheet — Common Query Patterns for DBAs
Oracle SQL Patterns Cheat Sheet
Section titled “Oracle SQL Patterns Cheat Sheet”Common Oracle SQL patterns and query templates that every DBA needs. Copy, adapt, and use these patterns in your daily work.
Top-N Queries
Section titled “Top-N Queries”Top N rows (12c+ FETCH FIRST)
Section titled “Top N rows (12c+ FETCH FIRST)”SELECT employee_id, salaryFROM employeesORDER BY salary DESCFETCH FIRST 10 ROWS ONLY;Top N with ties
Section titled “Top N with ties”SELECT employee_id, salaryFROM employeesORDER BY salary DESCFETCH FIRST 10 ROWS WITH TIES;Top N per group (classic)
Section titled “Top N per group (classic)”SELECT *FROM ( SELECT e.*, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) rn FROM employees e)WHERE rn <= 3;Pagination (offset + limit)
Section titled “Pagination (offset + limit)”SELECT *FROM employeesORDER BY employee_idOFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;Analytical Functions
Section titled “Analytical Functions”Running totals
Section titled “Running totals”SELECT order_date, amount, SUM(amount) OVER (ORDER BY order_date) running_totalFROM orders;Moving average
Section titled “Moving average”SELECT order_date, amount, AVG(amount) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) avg_7dayFROM daily_sales;Rank, Dense Rank, Row Number
Section titled “Rank, Dense Rank, Row Number”SELECT employee_id, department_id, salary, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rnk, DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) dense_rnk, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) rnFROM employees;Lag and Lead (previous/next row)
Section titled “Lag and Lead (previous/next row)”SELECT order_date, amount, LAG(amount, 1) OVER (ORDER BY order_date) prev_amount, LEAD(amount, 1) OVER (ORDER BY order_date) next_amount, amount - LAG(amount, 1) OVER (ORDER BY order_date) changeFROM daily_sales;NTILE (divide into buckets)
Section titled “NTILE (divide into buckets)”SELECT employee_id, salary, NTILE(4) OVER (ORDER BY salary) quartileFROM employees;LISTAGG (aggregate strings)
Section titled “LISTAGG (aggregate strings)”SELECT department_id, LISTAGG(last_name, ', ') WITHIN GROUP (ORDER BY last_name) employeesFROM employeesGROUP BY department_id;Hierarchical Queries
Section titled “Hierarchical Queries”Connect By (traditional)
Section titled “Connect By (traditional)”SELECT LEVEL, LPAD(' ', 2 * (LEVEL - 1)) || employee_id AS tree, employee_id, manager_id, last_nameFROM employeesSTART WITH manager_id IS NULLCONNECT BY PRIOR employee_id = manager_idORDER SIBLINGS BY last_name;Recursive CTE (ANSI standard, 11gR2+)
Section titled “Recursive CTE (ANSI standard, 11gR2+)”WITH emp_tree (employee_id, manager_id, last_name, lvl, path) AS ( SELECT employee_id, manager_id, last_name, 1, CAST(last_name AS VARCHAR2(4000)) FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.employee_id, e.manager_id, e.last_name, t.lvl + 1, t.path || ' > ' || e.last_name FROM employees e JOIN emp_tree t ON e.manager_id = t.employee_id)SELECT lvl, LPAD(' ', 2 * (lvl - 1)) || last_name AS tree, pathFROM emp_treeORDER BY path;SYS_CONNECT_BY_PATH
Section titled “SYS_CONNECT_BY_PATH”SELECT employee_id, SYS_CONNECT_BY_PATH(last_name, ' / ') full_pathFROM employeesSTART WITH manager_id IS NULLCONNECT BY PRIOR employee_id = manager_id;Pivot and Unpivot
Section titled “Pivot and Unpivot”PIVOT (rows to columns)
Section titled “PIVOT (rows to columns)”SELECT *FROM ( SELECT department_id, job_id, salary FROM employees)PIVOT ( SUM(salary) FOR job_id IN ('SA_MAN' AS sales_mgr, 'SA_REP' AS sales_rep, 'IT_PROG' AS it_prog));UNPIVOT (columns to rows)
Section titled “UNPIVOT (columns to rows)”SELECT *FROM quarterly_salesUNPIVOT ( amount FOR quarter IN (q1_sales AS 'Q1', q2_sales AS 'Q2', q3_sales AS 'Q3', q4_sales AS 'Q4'));Cross-tab without PIVOT (works on all versions)
Section titled “Cross-tab without PIVOT (works on all versions)”SELECT department_id, SUM(CASE WHEN job_id = 'SA_MAN' THEN salary END) sales_mgr, SUM(CASE WHEN job_id = 'SA_REP' THEN salary END) sales_rep, SUM(CASE WHEN job_id = 'IT_PROG' THEN salary END) it_progFROM employeesGROUP BY department_id;Date Patterns
Section titled “Date Patterns”Common date operations
Section titled “Common date operations”-- Current timestampSELECT SYSDATE, SYSTIMESTAMP FROM dual;
-- Truncate to day/month/yearSELECT TRUNC(SYSDATE), -- midnight today TRUNC(SYSDATE, 'MM'), -- first of month TRUNC(SYSDATE, 'YYYY'), -- first of year TRUNC(SYSDATE, 'IW') -- Monday of this week (ISO)FROM dual;
-- Add intervalsSELECT SYSDATE + 7 AS next_week, ADD_MONTHS(SYSDATE, 3) AS next_quarter, SYSDATE + INTERVAL '4' HOUR AS four_hours_laterFROM dual;
-- Difference between datesSELECT ROUND(date2 - date1) AS days_diff, ROUND((date2 - date1) * 24) AS hours_diff, MONTHS_BETWEEN(date2, date1) AS months_diffFROM dual;Date ranges
Section titled “Date ranges”-- All rows from todayWHERE created_date >= TRUNC(SYSDATE) AND created_date < TRUNC(SYSDATE) + 1
-- Last 7 daysWHERE created_date >= SYSDATE - 7
-- Specific monthWHERE created_date >= TO_DATE('2025-01-01', 'YYYY-MM-DD') AND created_date < TO_DATE('2025-02-01', 'YYYY-MM-DD')Generate date series
Section titled “Generate date series”SELECT TRUNC(SYSDATE) - LEVEL + 1 AS day_dateFROM dualCONNECT BY LEVEL <= 30ORDER BY 1;DBA-Specific Patterns
Section titled “DBA-Specific Patterns”Find objects by name pattern
Section titled “Find objects by name pattern”SELECT owner, object_name, object_type, status, createdFROM dba_objectsWHERE object_name LIKE UPPER('&pattern') || '%'ORDER BY owner, object_type, object_name;Table row counts (all tables in a schema)
Section titled “Table row counts (all tables in a schema)”SELECT table_name, num_rows, last_analyzedFROM dba_tablesWHERE owner = UPPER('&schema')ORDER BY num_rows DESC NULLS LAST;Find columns across all tables
Section titled “Find columns across all tables”SELECT owner, table_name, column_name, data_type, data_lengthFROM dba_tab_columnsWHERE column_name LIKE UPPER('&column_pattern') || '%'ORDER BY owner, table_name;Session kill script generator
Section titled “Session kill script generator”SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''' IMMEDIATE;' AS kill_cmdFROM v$sessionWHERE username = UPPER('&username');Index usage detection (12c+)
Section titled “Index usage detection (12c+)”ALTER INDEX owner.index_name MONITORING USAGE;-- Wait for a representative period, then check:SELECT * FROM v$object_usage WHERE index_name = 'INDEX_NAME';Partition pruning check
Section titled “Partition pruning check”EXPLAIN PLAN FOR <your query>;SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);-- Look for "PARTITION RANGE" or "PARTITION LIST" operations-- "Pstart" and "Pstop" show which partitions are accessedConditional Logic
Section titled “Conditional Logic”DECODE vs CASE
Section titled “DECODE vs CASE”-- DECODE (Oracle-specific, equality only)SELECT DECODE(status, 'A', 'Active', 'I', 'Inactive', 'Unknown') status_text FROM table1;
-- CASE (ANSI standard, supports ranges)SELECT CASE WHEN salary >= 100000 THEN 'Executive' WHEN salary >= 50000 THEN 'Senior' ELSE 'Junior' END salary_bandFROM employees;NVL, NVL2, COALESCE, NULLIF
Section titled “NVL, NVL2, COALESCE, NULLIF”SELECT NVL(commission_pct, 0), -- replace NULL with 0 NVL2(commission_pct, 'Has Comm', 'No Comm'), -- if not null / if null COALESCE(phone, mobile, email, 'N/A'), -- first non-null NULLIF(col1, col2) -- NULL if equalFROM employees;Useful DBA Query Templates
Section titled “Useful DBA Query Templates”Space usage by schema
Section titled “Space usage by schema”SELECT owner, ROUND(SUM(bytes) / 1024 / 1024) size_mb, COUNT(*) segment_countFROM dba_segmentsWHERE owner NOT IN ('SYS', 'SYSTEM', 'DBSNMP', 'MDSYS', 'CTXSYS', 'XDB')GROUP BY ownerORDER BY 2 DESC;Long-running sessions
Section titled “Long-running sessions”SELECT s.sid, s.serial#, s.username, s.status, s.last_call_et / 60 minutes_idle, s.sql_id, s.eventFROM v$session sWHERE s.username IS NOT NULL AND s.last_call_et > 3600ORDER BY s.last_call_et DESC;Table fragmentation estimate
Section titled “Table fragmentation estimate”SELECT table_name, ROUND(blocks * 8 / 1024) allocated_mb, ROUND(num_rows * avg_row_len / 1024 / 1024) actual_mb, ROUND(blocks * 8 / 1024) - ROUND(num_rows * avg_row_len / 1024 / 1024) wasted_mbFROM dba_tablesWHERE owner = UPPER('&schema') AND blocks > 0ORDER BY 4 DESC NULLS LAST;Related Resources
Section titled “Related Resources”- Performance Analysis Scripts (171 tools) — Production-ready query scripts
- Schema Analysis Scripts (60 tools) — Object and schema queries
- Date Functions Cheat Sheet — Detailed date function reference
- V$ Views Reference — Dynamic performance view guide
- Oracle Performance Tuning Cheat Sheet — Tuning parameters and shortcuts