◆ Data Analytics · SQL Guide

SQL Queries Every Data Analyst Should Know

From filtering rows to window functions — the practical SQL toolkit that shows up in almost every real analyst job, explained with syntax, examples, and when to actually use each one.

| By Affordable AI, Nagpur

SQL Queries Every Data Analyst Should Know | Affordable AI
Why this matters

SQL is still the most-used tool in a data analyst's day

Dashboards get the attention, but almost every dashboard, report, and "quick number" a stakeholder asks for starts with a SQL query. Analysts who are fast and confident in SQL spend less time fighting the database and more time actually interpreting what the data means.

This guide walks through the queries that show up again and again in real analyst work — filtering, aggregating, joining, and the intermediate patterns like window functions and CTEs that separate a comfortable SQL user from a genuinely strong one.

Analyst reviewing data charts and SQL results on a laptop screen
13Query patterns covered
90%Of daily analyst work uses SQL
1Skill that compounds fastest
The queries

The SQL toolkit, one pattern at a time

Every example uses a simple orders, customers, and products schema so you can follow the logic without extra context-switching.

1. SELECT & WHERE — filtering rows

Foundations

This is the query you'll write more than any other. SELECT chooses which columns to return, and WHERE filters rows before any grouping happens.

select_where.sql
SELECT order_id, customer_id, order_amount, order_date
FROM orders
WHERE order_amount > 500
  AND order_date >= '2026-01-01';
Use it when: a stakeholder asks "show me all orders above ₹500 this year" — the most common first step in almost any analysis.

2. ORDER BY & LIMIT — sorting and sampling

Foundations

ORDER BY sorts your result set, and LIMIT caps how many rows come back — essential for "top N" questions.

top_orders.sql
SELECT customer_id, order_amount
FROM orders
ORDER BY order_amount DESC
LIMIT 10;
Use it when: you need the top 10 highest orders, the 5 most recent signups, or a quick spot-check sample of a table.

3. Aggregate functions — COUNT, SUM, AVG, MIN, MAX

Foundations

Aggregate functions collapse many rows into a single summary number — the backbone of almost every KPI.

aggregates.sql
SELECT
  COUNT(*)              AS total_orders,
  SUM(order_amount)     AS total_revenue,
  AVG(order_amount)     AS avg_order_value,
  MIN(order_date)       AS first_order,
  MAX(order_date)       AS last_order
FROM orders;
Use it when: building a summary card for a dashboard — total revenue, order count, average order value.

4. GROUP BY & HAVING — aggregating by category

Foundations

GROUP BY buckets rows before aggregating, and HAVING filters those groups after aggregation — WHERE can't do that since it runs before grouping.

group_having.sql
SELECT customer_id, COUNT(*) AS order_count, SUM(order_amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING SUM(order_amount) > 10000
ORDER BY total_spent DESC;
Use it when: finding high-value customers, e.g. "who has spent more than ₹10,000 total?"

5. INNER & LEFT JOIN — combining tables

Core skill

Real data lives across multiple tables. INNER JOIN returns only matching rows; LEFT JOIN keeps every row from the left table even without a match — critical for finding "missing" data, like customers with zero orders.

inner_join.sql
SELECT c.customer_name, o.order_id, o.order_amount
FROM customers c
INNER JOIN orders o
  ON c.id = o.customer_id;
left_join.sql
SELECT c.customer_name, o.order_id
FROM customers c
LEFT JOIN orders o
  ON c.id = o.customer_id
WHERE o.order_id IS NULL;
Use it when: combining customer details with their orders, or finding customers who never placed one.

6. Subqueries — a query inside a query

Core skill

A subquery runs first and feeds its result into the outer query — useful when you need to filter against an aggregated or computed value.

subquery.sql
SELECT customer_name
FROM customers
WHERE id IN (
  SELECT customer_id
  FROM orders
  GROUP BY customer_id
  HAVING SUM(order_amount) > 50000
);
Use it when: your filter condition itself depends on an aggregate, like "customers whose total spend exceeds ₹50,000."

7. CTEs — the WITH clause

Core skill

A Common Table Expression names a temporary result set so you can reference it like a table — it makes multi-step logic dramatically easier to read than nested subqueries.

cte.sql
WITH monthly_totals AS (
  SELECT DATE_TRUNC('month', order_date) AS month,
         SUM(order_amount) AS revenue
  FROM orders
  GROUP BY month
)
SELECT month, revenue,
       revenue - LAG(revenue) OVER (ORDER BY month) AS mom_change
FROM monthly_totals
ORDER BY month;
Use it when: a query needs several logical steps — build the base numbers in the CTE, then analyze them in the final SELECT.

8. Window functions — ROW_NUMBER, RANK, LAG/LEAD

Intermediate

Window functions calculate across a set of related rows without collapsing them into one row — perfect for rankings, running totals, and period-over-period comparisons.

window_fn.sql
SELECT customer_id, order_date, order_amount,
  ROW_NUMBER() OVER (
    PARTITION BY customer_id ORDER BY order_date
  ) AS order_sequence,
  SUM(order_amount) OVER (
    PARTITION BY customer_id ORDER BY order_date
  ) AS running_total
FROM orders;
Use it when: you need "each customer's 1st, 2nd, 3rd order" or a running/cumulative total — one of the most-asked skills in analyst interviews.

9. CASE WHEN — conditional logic

Intermediate

CASE WHEN is SQL's if/else. It's how you create custom categories, buckets, or flags right inside a query.

case_when.sql
SELECT order_id, order_amount,
  CASE
    WHEN order_amount >= 1000 THEN 'High value'
    WHEN order_amount >= 300  THEN 'Mid value'
    ELSE 'Low value'
  END AS order_segment
FROM orders;
Use it when: segmenting customers or orders into readable buckets for a report, like "High / Mid / Low value."

10. UNION / UNION ALL — stacking result sets

Intermediate

UNION combines the results of two queries into one list, removing duplicates. UNION ALL does the same but keeps duplicates and runs faster.

union.sql
SELECT customer_name, 'Active' AS status FROM active_customers
UNION ALL
SELECT customer_name, 'Inactive' AS status FROM inactive_customers;
Use it when: merging two similarly-shaped tables or reports, like combining this year's and last year's data.

11. Date & time functions

Intermediate

Almost every business question has a time dimension. Date functions let you truncate, extract, and compare dates cleanly.

dates.sql
SELECT
  DATE_TRUNC('week', order_date)     AS order_week,
  EXTRACT(DOW FROM order_date)      AS day_of_week,
  DATEDIFF(day, order_date, CURRENT_DATE) AS days_since_order
FROM orders;
Use it when: building weekly/monthly trends, cohort analysis, or "days since last purchase" churn signals.

12. NULL handling — COALESCE, DISTINCT, IS NULL

Data quality

Messy, missing, or duplicate data breaks reports silently. These patterns keep your results clean and trustworthy.

null_handling.sql
SELECT DISTINCT customer_id,
  COALESCE(discount_code, 'NONE') AS discount_code
FROM orders
WHERE customer_id IS NOT NULL;
Use it when: cleaning a raw table before analysis — replacing blanks with defaults and removing exact duplicates.

13. Pivoting with CASE — rows to columns

Data quality

Many BI tools want wide, pivoted tables. Combining CASE with an aggregate is the classic SQL way to turn row values into columns.

pivot.sql
SELECT
  customer_id,
  SUM(CASE WHEN product_category = 'Electronics' THEN order_amount ELSE 0 END) AS electronics,
  SUM(CASE WHEN product_category = 'Apparel'     THEN order_amount ELSE 0 END) AS apparel
FROM orders
GROUP BY customer_id;
Use it when: building a spend-by-category table for a spreadsheet or dashboard export.
Writing better SQL

Five habits that separate clean SQL from messy SQL

📐

Format for readability

Put keywords on their own lines and indent consistently. Six months from now, you'll thank yourself.

🏷️

Alias tables and columns

Short, clear aliases like o for orders make multi-table joins far easier to scan and debug.

🧪

Test on a small slice first

Add a LIMIT while building a query, then remove it once the logic is confirmed correct.

🧩

Break big queries into CTEs

If a query is hard to read in one pass, it's usually a sign it should be split into named steps.

Sanity-check your row counts

After a join, compare row counts before and after — a silent join explosion is the #1 cause of wrong numbers.

💬

Comment the "why," not the "what"

Explain business logic decisions in comments — the SQL itself already shows what's happening.

Keep learning

Want to go from "knows SQL" to "job-ready data analyst"?

Explore structured, affordable data analytics and AI courses built for real career outcomes — SQL, Excel, Python, and dashboarding, taught with practical projects.

FAQ

Quick answers before you go

Do I need to know all 13 of these to get a data analyst job?

No — SELECT/WHERE, GROUP BY, JOINs, and CASE WHEN cover most entry-level work. Window functions and CTEs are what tend to come up in interviews for stronger roles, so they're worth practicing once the basics feel automatic.

Does the SQL syntax change between MySQL, PostgreSQL, and SQL Server?

The core patterns above work almost everywhere. Small differences show up mainly in date functions and string functions, so it's worth checking your specific database's documentation for those.

What's the fastest way to actually get good at SQL?

Write queries against a real, messy dataset rather than only following tutorials. Recreate reports you've seen at work, and try rebuilding each pattern in this guide from memory.

Should I learn window functions before or after joins?

After. Joins are used constantly and come up almost immediately; window functions are an intermediate step once you're comfortable combining and aggregating tables.