Syntax Differences
ROWNUMfor limiting rows—WHERE ROWNUM <= 10; 12c+ supportsFETCH FIRST 10 ROWS ONLYDUALtable for expressions—SELECT sysdate FROM dualVARCHAR2notVARCHAR—VARCHAR is reserved, VARCHAR2 is the standard- String concatenation with
||—not CONCAT for multiple values - Empty string equals NULL—
'' IS NULLis true; breaks logic from other databases
Pagination
- ROWNUM assigned before ORDER BY—wrap in subquery:
SELECT * FROM (SELECT ... ORDER BY x) WHERE ROWNUM <= 10 - Offset requires nested subquery:
SELECT * FROM (SELECT a.*, ROWNUM rn FROM (...) a WHERE ROWNUM <= 20) WHERE rn > 10 - 12c+:
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY—cleaner, use when available
NULL Handling
NVL(col, default)for null replacement—faster than COALESCE for two argsNVL2(col, if_not_null, if_null)for conditional—common Oracle pattern- Empty string is NULL—
LENGTH('')returns NULL, not 0 NULLIF(a, b)returns NULL if equal—useful for avoiding division by zero
Dates
SYSDATEfor current datetime—no parenthesesTO_DATE('2024-01-15', 'YYYY-MM-DD')for string to date—format requiredTO_CHAR(date, 'YYYY-MM-DD HH24:MI:SS')for date to string- Date arithmetic in days—
SYSDATE + 1is tomorrow,SYSDATE + 1/24is one hour
Sequences
- Create:
CREATE SEQUENCE seq_name START WITH 1 INCREMENT BY 1 - Get next:
seq_name.NEXTVAL—SELECT seq_name.NEXTVAL FROM dual - Current value:
seq_name.CURRVAL—only after NEXTVAL in same session - 12c+: identity columns—
GENERATED ALWAYS AS IDENTITY
Hierarchical Queries
CONNECT BY PRIOR child = parentfor tree traversalSTART WITH parent IS NULLfor root nodesLEVELpseudo-column shows depth—WHERE LEVEL <= 3limits depthSYS_CONNECT_BY_PATH(col, '/')builds path string
Bind Variables
- Always use bind variables—literals cause hard parse every time
- PL/SQL:
:variable_namesyntax - Performance critical—literal values fill shared pool, cause contention
CURSOR_SHARING=FORCEas workaround but not recommended long-term
Hints
/*+ INDEX(table idx_name) */forces index use/*+ FULL(table) */forces full table scan/*+ PARALLEL(table, 4) */enables parallel query- Hints inside
SELECT /*+ hint */—common placement after SELECT keyword
PL/SQL Blocks
- Anonymous block:
BEGIN ... END;with/on new line to execute DBMS_OUTPUT.PUT_LINE()for debug output—SET SERVEROUTPUT ONfirst- Exception handling:
EXCEPTION WHEN OTHERS THEN—always handle or log EXECUTE IMMEDIATE 'sql string'for dynamic SQL—beware injection
Transactions
- No auto-commit by default—must
COMMITexplicitly SAVEPOINT namethenROLLBACK TO namefor partial rollback- DDL auto-commits—
CREATE TABLEcommits any pending transaction SELECT FOR UPDATE WAIT 5waits 5 seconds for lock—avoids indefinite hang
Performance
EXPLAIN PLAN FOR sql; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)—shows planV$SQLandV$SESSIONfor monitoring—requires privileges- Avoid
SELECT *—fetches all columns including LOBs - Index hint when optimizer chooses wrong—
/*+ INDEX(t idx) */
Common Traps
MINUSinstead ofEXCEPT—Oracle uses MINUS for set differenceDECODEis Oracle-specific—use CASE for portability- Implicit type conversion—
WHERE num_col = '123'works but prevents index use ROWIDis physical—don't store or rely on across transactions