SELECT, WHERE, and JOIN, you can answer simple questions. This page gives you the tools to answer hard questions — “Who are the top 3 earners in each department?”, “What is the running total of salaries?”, “Which employees earn above the company average?” — using subqueries, CTEs, and window functions. You will also learn how indexes make queries fast and how views let you save complex queries as reusable objects.
Subqueries
A subquery is aSELECT inside another SQL statement. The inner query runs first and its result is used by the outer query. You can place subqueries in the WHERE clause, the FROM clause, or even the SELECT list.
Subquery in WHERE
AVG(salary)). The outer query compares each row’s salary against it.
Subquery with IN
Correlated Subquery
A correlated subquery references a column from the outer query. It re-executes for every row the outer query processes.Correlated subqueries are powerful but can be slow on large tables because they run once per row. A
JOIN or window function often achieves the same result more efficiently.Common Table Expressions (CTEs)
A CTE gives a subquery a name and makes it readable. You define it withWITH before the main query. CTEs can reference each other, making multi-step logic clean and debuggable.
Basic CTE Syntax
Example: High Earners per Department
Chained CTEs
Window Functions
Window functions perform calculations across a set of related rows without collapsing them the wayGROUP BY does. Every row stays in the output; the function just adds an extra computed column.
The key syntax element is OVER(...), which defines the “window” — which rows the function looks at when computing each result.
ROW_NUMBER()
Assigns a unique sequential integer to each row within a window.Top 3 Earners Per Department
Wrap the window function in a CTE and filter on the rank:RANK() and DENSE_RANK()
Both assign ranks but handle ties differently.
If two employees share a salary:
RANK() would give them both rank 3 and skip rank 4. DENSE_RANK() gives them both rank 3 and continues with rank 4 for the next employee.
LAG() and LEAD()
Access the value from a previous (LAG) or following (LEAD) row within the window.
Running Total (Cumulative SUM)
CASE WHEN Expressions
CASE WHEN is SQL’s conditional logic — like if/elif/else inside a query.
Simple Classification
Conditional Aggregation
You can combineCASE WHEN with aggregate functions to create pivot-like summaries.
String Functions
SQLite provides built-in string functions for cleaning and transforming text data.Date Functions
Store dates asTEXT in 'YYYY-MM-DD' format and use SQLite’s date functions to manipulate them.
Indexes
An index is a data structure that lets the database find rows matching a condition without scanning every row in the table. Think of it as the index at the back of a book.Why Indexes Matter
Without an index, a query likeWHERE city = 'Hyderabad' reads every single row (a full table scan). With an index on city, the database jumps directly to the matching rows.
When to Index
Good candidates
- Columns used frequently in
WHEREclauses - Columns used in
JOINconditions - Columns used in
ORDER BYon large tables - Foreign key columns
When to avoid
- Very small tables (full scan is fast enough)
- Columns you update very frequently (indexes slow down writes)
- Columns with very low cardinality (e.g., a boolean column)
Query Plan
Check how SQLite executes your query withEXPLAIN QUERY PLAN:
USING INDEX in the output — that confirms the index is being used.
Views
A view is a saved query stored in the database that you can query like a table. It does not store data itself — it re-runs the underlying query each time you select from it.Create a View
Query a View
Drop a View
Complete Analytics Example
This query uses CTEs, window functions, and CASE expressions to produce a department-level performance report in one statement:Next: NumPy
Move into data analysis — learn NumPy arrays, vectorized operations, and broadcasting for fast numerical computing in Python.