Skip to main content
Every useful thing you do with a database starts with a question: “Who earns the most?” “How many employees are in each city?” “What is the average salary per department?” SQL answers all of these with the SELECT statement. This page walks you through every major SELECT feature, from the simplest column retrieval to grouped aggregations with HAVING, using a consistent employees database throughout.

The Sample Data

All examples use these two tables. Set them up using the SQLite Setup page if you have not already. employee (selected rows shown)

SELECT — Retrieve Columns

SELECT tells SQL which columns to return. FROM tells it which table to read.

All Columns

* is a wildcard meaning “every column”. Use it for quick exploration, but name columns explicitly in production code so schema changes do not silently break your queries.

Specific Columns

Column Aliases with AS

Give a column a temporary display name using AS. Aliases make output readable and are required when you rename calculated expressions.
You cannot use an alias defined in SELECT inside a WHERE clause. SQL executes WHERE before SELECT, so the alias does not yet exist at that point. Use the original expression or a subquery instead.

DISTINCT — Remove Duplicates

DISTINCT eliminates duplicate values from the result.

WHERE — Filter Rows

WHERE evaluates a condition for each row and includes only the rows where the condition is TRUE.

Comparison Operators

Logical Operators: AND, OR, NOT

Combine multiple conditions with logical operators.

BETWEEN — Range Check

BETWEEN is inclusive — both boundary values are included.

IN — List Membership

IN is cleaner and often faster when matching against a list of values.

LIKE — Pattern Matching

LIKE searches text columns for patterns. Two wildcards are available:

IS NULL / IS NOT NULL

NULL means “unknown value”. You cannot test for NULL using =; you must use IS NULL.

Practice: Filter employees

Write a query that returns the name and salary of employees from Hyderabad who earn more than ₹55,000.

ORDER BY — Sort Results

ORDER BY sorts the result set. Default order is ascending (ASC). Use DESC for descending.

LIMIT and OFFSET — Pagination

LIMIT caps the number of rows returned. OFFSET skips a given number of rows before starting to return results. Together they power pagination.
Always pair LIMIT with ORDER BY. Without ordering, the database returns rows in an undefined sequence and your “page 2” might overlap with “page 1”.

Aggregate Functions

Aggregate functions collapse many rows into a single value. They are most useful when combined with GROUP BY.

Practice: Salary statistics

Write a query that returns the average, minimum, and maximum salary for all employees in one result row.

GROUP BY — Aggregate Per Group

GROUP BY splits the rows into groups and applies aggregate functions to each group independently.
Every column in the SELECT clause must either be listed in GROUP BY or wrapped in an aggregate function. You cannot select a non-grouped, non-aggregated column.

HAVING — Filter Groups

WHERE filters individual rows before grouping. HAVING filters groups after aggregation. Use HAVING whenever your filter condition involves an aggregate function.

WHERE vs. HAVING — Quick Rule

SQL Execution Order

You write SQL in one order, but the database runs each clause in a different sequence. Understanding this explains many confusing behaviours (like why you cannot use SELECT aliases in WHERE).

Full Query Example

This query uses every clause covered on this page. Read it clause by clause following the execution order above.

Practice: Departmental payroll report

Write a query that returns, for each department (excluding NULL), the department ID, the number of employees, and the total payroll — but only for departments whose total payroll exceeds ₹100,000. Sort by total payroll descending.

Next: SQL JOINs

Learn how to combine rows from multiple tables using INNER JOIN, LEFT JOIN, and more to answer cross-table questions.