SQL basics

SQL is the language you use to ask a database for data, put data in and change it. This guide starts with the order in which a SELECT statement is actually processed, then works through functions and GROUP BY, joins, subqueries, window functions and hierarchical queries, and finishes with the statements that change data and make those changes stick. The examples keep coming back to the same employee and department tables, and every chapter has a figure you can play with. Oracle is the baseline, and wherever SQL Server behaves differently, you'll see it called out. How to split up and design the tables in the first place is covered in the data modeling guide.

01

Relational databases and SELECT basics

The vocabulary of relational databases

A relational database keeps data in tables (grids of rows and columns) and links tables to each other through key values. Theory uses different names for the same things, so it's worth learning the pairs.

Theory (relational model)In a tableWhat it means
RelationTableA set of rows that share the same structure
TupleRowOne instance
AttributeColumnOne property
DegreeNumber of columnsHow many attributes there are
CardinalityNumber of rowsHow many tuples there are
DomainRange of values for a columnThe set of values an attribute is allowed to take

Relations have a few properties. No two tuples can be exactly the same, there's no order among tuples or among attributes, and every value is atomic — it can't be broken down any further.

Keys come in several kinds, too.

KeyCondition
Super keyUniqueness only — any combination of columns that can tell rows apart
Candidate keyUniqueness + minimality — a candidate for the primary key
Primary key (PK)The candidate key picked to represent the table. No NULLs, no duplicates
Alternate keyThe candidate keys that weren't picked as the primary key
Foreign key (FK)A column that references another table's primary key

The rules that keep data correct at all times are called integrity constraints. The classic ones are entity integrity (a primary key can't be NULL or duplicated), referential integrity (a foreign key value must exist in the table it references, or be NULL) and domain integrity (a column value must stay inside its defined domain).

The theoretical operations behind relational databases are called relational algebra. Here's how each part of SQL lines up with them.

TypeOperationSymbolIn SQL
Pure relational operatorsSELECT (selection)σWHERE — picks the rows that match a condition
PROJECT (projection)πSELECT list — picks the columns you want
JOIN⋈JOIN — attaches two relations on a shared value
DIVISION÷Keeps only rows that have every value on the dividing side (no direct SQL syntax)
Set operatorsUnion / intersection / difference∪ / ∩ / −UNION / INTERSECT / MINUS (EXCEPT)
Cartesian product×CROSS JOIN

The four kinds of SQL statements

KindCommandsWhat they do
DML (manipulation)SELECT, INSERT, UPDATE, DELETE, MERGEQuery, add, change and remove data. SELECT on its own is sometimes called DQL
DDL (definition)CREATE, ALTER, DROP, RENAME, TRUNCATECreate, change and remove structures such as tables
DCL (control)GRANT, REVOKEGive and take away privileges
TCL (transaction control)COMMIT, ROLLBACK, SAVEPOINTMake changes final or undo them

SELECT and WHERE

Here's the skeleton of a SELECT.

SELECT [DISTINCT] column [AS alias], ...
FROM   table
WHERE  condition
ORDER BY column [ASC | DESC];
  • DISTINCT removes duplicate rows from the result (a row counts as a duplicate only if the whole SELECT list matches)
  • An alias is attached with AS; if it contains spaces or special characters, wrap it in double quotes
  • To join strings together, Oracle uses || and SQL Server uses + (both have the CONCAT function)

These are the operators you'll use in WHERE.

OperatorMeaningWatch out
=, <>, !=, ^=, >, <, >=, <=Comparison<>, != and ^= all mean "not equal"
BETWEEN a AND bFrom a up to bBoth ends are included. Put the smaller value first
IN (a, b, c)Equal to one of the values in the listIf a NOT IN list contains a NULL, no rows come back at all
LIKE 'A%'Pattern% is any run of zero or more characters, _ is exactly one character. Use ESCAPE to search for % itself
IS NULL / IS NOT NULLIs it NULL?= NULL is always unknown, so it returns no rows

When you chain several conditions, precedence matters. According to the Oracle docs, the order is parentheses → comparison operators → NOT → AND → OR. AND comes before OR, so A OR B AND C is evaluated as A OR (B AND C). If you're ever unsure, add parentheses — it's the safe bet.

Why does NOT IN (10, 20, NULL) return nothing at all? NOT IN expands to “not 10 AND not 20 AND not NULL”, and any comparison with NULL is always ‘unknown’, so the whole condition can never be true. If a subquery might return NULLs, use NOT EXISTS instead, or filter the NULLs out.

ORDER BY: sorting, and where NULLs end up

ORDER BY sorts in ascending order (ASC) by default, and you can sort by a column name, an alias or a position number in the SELECT list (1, 2 …). The tricky part is NULL. Oracle treats NULL as the largest value, so in ascending order it goes last; SQL Server treats it as the smallest, so it goes first. In Oracle you can place NULLs yourself with NULLS FIRST or NULLS LAST.

The order a SELECT is processed in

A SELECT statement isn't processed in the order it's written. Once you know the real order, questions like “Why can't I use an alias in WHERE?” and “Why can't I put SUM in WHERE?” answer themselves. Step through the figure below.

SELECT DEPT_CODE, SUM(SALARY) AS TOTAL
▶FROM EMP
WHERE SALARY >= 260
GROUP BY DEPT_CODE
HAVING SUM(SALARY) >= 280
ORDER BY TOTAL DESC;

EMP

EMP_NONAMEDEPT_CODESALARY
101AvaD10300
102BenD10250
103ChrisD20400
104DanaD20350
105EliNULL280
106FayD30260

Step 1 — FROM

Processing order
FROM

Step through it. The order it's written in (SELECT on top) isn't the order it's processed in.

FROM comes first. It pulls in all 6 rows of the EMP table. SELECT is written at the top, but it's actually handled near the very end.

To sum up: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. An alias is created in SELECT, so only the ORDER BY that comes after it can use it.

If a question says… → pick this

  • “Number of columns / rows in a relation”Degree / cardinality
  • “Satisfies both uniqueness and minimality”Candidate key
  • “A foreign key must be a value in the referenced table, or NULL”Referential integrity
  • “The relational operation that picks only the columns you want”PROJECT (π)
  • “GRANT, REVOKE”DCL
  • “BETWEEN 100 AND 200”Includes 100 and 200
  • “A NULL in a NOT IN list”0 rows
  • “Where NULL goes in an Oracle ascending sort”Last (first in SQL Server)
  • “Why WHERE can't use a SELECT alias”WHERE is processed before SELECT

02

Functions, GROUP BY and HAVING

You've pulled columns out with SELECT. Now it's time to reshape values (functions) and to bundle rows up and count them (GROUP BY).

Single-row functions: one value back per row

Functions come in two kinds. Single-row functions return one result for each row, and multi-row functions (aggregate functions) bundle many rows into a single result. You can use single-row functions anywhere — SELECT, WHERE, ORDER BY — and you can nest one function inside another.

KindOracleSQL ServerExample and result
CharacterLOWER, UPPERLOWER, UPPERUPPER('sql') → 'SQL'
SUBSTRSUBSTRINGSUBSTR('DATABASE', 3, 4) → 'TABA'
LENGTHLENLENGTH('SQL') → 3
LTRIM, RTRIM, TRIMLTRIM, RTRIM, TRIMTRIM(' A ') → 'A'
CONCAT, ||CONCAT, +'A' || 'B' → 'AB'
NumberROUND, TRUNCROUNDROUND(38.567, 1) → 38.6 / TRUNC(38.567, 1) → 38.5
CEIL, FLOORCEILING, FLOORCEIL(3.1) → 4 / FLOOR(-3.1) → -4
MOD%MOD(7, 3) → 1
DateSYSDATEGETDATE()The current date and time
EXTRACTDATEPARTEXTRACT(YEAR FROM HIRE_DATE)

In Oracle, adding a number to a date counts in days: HIRE_DATE + 1 is the next day, and HIRE_DATE + 1/24 is an hour later. One more thing: Oracle treats an empty string (‘’) as NULL, while SQL Server keeps empty strings and NULL apart.

Type conversion and CASE

There are two ways to change a data type: explicit conversion, where you call a function yourself (Oracle: TO_CHAR, TO_NUMBER, TO_DATE; SQL Server: CAST, CONVERT), and implicit conversion, where the database does it for you. Implicit conversion is handy, but it can convert things in ways you didn't expect or stop an index from being used, so it's a good habit to convert explicitly.

To return different values depending on a condition, use CASE. There's the simple CASE, which compares against a single value, and the searched CASE, which takes conditions. Oracle also has the DECODE function, which does the same job.

SELECT NAME,
       CASE WHEN SALARY >= 350 THEN 'High'
            WHEN SALARY >= 280 THEN 'Mid'
            ELSE 'Low' END AS GRADE,      -- without ELSE you get NULL
       DECODE(DEPT_CODE, 'D10', 'Sales', 'D20', 'Dev', 'Other') AS DEPT_NAME
FROM   EMP;

Functions for handling NULL

FunctionReturnsExample
NVL(a, b) / ISNULL(a, b)b if a is NULL, otherwise aNVL(BONUS, 0)
NVL2(a, b, c)b if a isn't NULL, c if it is (Oracle)NVL2(BONUS, 'Yes', 'No')
NULLIF(a, b)NULL if a and b are equal, otherwise aNULLIF(10, 10) → NULL
COALESCE(a, b, c, ...)The first value that isn't NULLCOALESCE(NULL, NULL, 3) → 3

Aggregate functions and NULL

Aggregate functions like COUNT, SUM, AVG, MAX and MIN bundle many rows into a single value. There's one rule to remember: every one of them except COUNT(*) ignores NULLs. Try switching functions in the figure below.

EMP

NAMESALARYBONUS
Ava30050
Ben250NULL
Chris400NULL
Dana35030
Eli280NULL
Fay26020

COUNT(*) = 6

Calculation
Rows used
6 / 6

Switch functions. Green rows went into the calculation; struck-through rows were left out.

COUNT(*) counts the rows themselves. A row whose BONUS is NULL is still a row, so the answer is 6.

Put DISTINCT inside an aggregate function and each duplicate value is counted only once (COUNT(DISTINCT DEPT_CODE)). If no rows match at all, COUNT returns 0, while SUM, AVG, MAX and MIN return NULL.

GROUP BY and HAVING

GROUP BY bundles rows that share the same value and aggregates each group. Once rows are grouped, each group becomes a single line, and that brings some rules with it.

  • Any column in the SELECT list that isn't inside an aggregate function must also be in GROUP BY
  • Don't use SELECT aliases in GROUP BY — given the processing order, the alias doesn't exist yet (the latest Oracle 23ai allows it, but exams go by the traditional rule)
  • NULLs form a group of their own
  • GROUP BY doesn't guarantee any order — if you need one, use ORDER BY

To put a condition on groups, use HAVING. WHERE filters rows before they're grouped; HAVING filters groups after they're formed. That's why conditions on aggregate functions can only go in HAVING. If a condition doesn't need an aggregate function, filtering it early in WHERE is the better choice, since it leaves fewer rows to process.

SELECT   DEPT_CODE, COUNT(*) AS HEADCOUNT, AVG(SALARY) AS AVG_SAL
FROM     EMP
WHERE    SALARY >= 250          -- filter rows first
GROUP BY DEPT_CODE
HAVING   COUNT(*) >= 2;         -- then filter the groups

If a question says… → pick this

  • “SUBSTR('DATABASE', 3, 4)”'TABA'
  • “An empty string in Oracle”Treated as NULL
  • “NULL if a and b are equal”NULLIF(a, b)
  • “The first value that isn't NULL”COALESCE
  • “The aggregate function that counts NULLs”Only COUNT(*)
  • “AVG(BONUS) vs AVG(NVL(BONUS, 0))”They divide by a different number of rows
  • “The clause for conditions on aggregate functions”HAVING
  • “A column not in GROUP BY in the SELECT list”Error unless it's wrapped in an aggregate function

Pro only

That’s the free part of this guide

The other 5 chapters are open to Pro subscribers. Each one continues with 3D visuals and “if a question says…” tips, and the last chapter lets you check yourself with a short quiz.

  1. 03Joins
  2. 04Subqueries, views and set operators
  3. 05Group functions, window functions and Top N
  4. 06Self joins, hierarchical queries, PIVOT and regular expressions
  5. 07Data management statements: DML, TCL, DDL and DCL

Advertisement

PasslyExam

You have read the concept. Now test it on exam questions

PasslyExam offers original practice questions, explanations and full mock exams built around each certification’s exam guide. The explanations cover why the right option is right and why the look-alike options are wrong. Sign up to practice for free every day.

Exams that cover this concept

More guides on this topic

Guides on other topics

See all concept guides