By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
SQL for analytics is the toolbox that lets you pull, reshape, and summarize data stored in relational databases so you can feed clean, feature‑rich tables into your machine‑learning pipelines. Whether you’re building a churn‑prediction model for a telecom provider or creating the input matrix for a recommendation engine, you first need to join the right tables, aggregate metrics, and compute window‑based features (e.g., “average spend over the past 30 days”) directly in SQL—saving time, memory, and downstream preprocessing.
INNER JOIN
LEFT/RIGHT OUTER JOIN
NULL
ON a.customer_id = b.customer_id
FUNC() OVER (PARTITION BY col1 ORDER BY col2 ROWS BETWEEN X PRECEDING AND Y FOLLOWING)
LAG(revenue, 1) OVER (PARTITION BY cust_id ORDER BY date)
SUM(col)
AVG(col)
COUNT(*)
MAX(col)
MIN(col)
SELECT key, AGG(col) FROM tbl GROUP BY key
WHERE
SELECT
FROM
HAVING
WITH
UNION
UNION ALL
JOIN
python sql = """ SELECT c.customer_id, c.signup_date, t.transaction_id, t.amount, t.date FROM customers c LEFT JOIN transactions t ON c.customer_id = t.customer_id """
LAG
AVG OVER
ROW_NUMBER
sql SELECT *, AVG(amount) OVER (PARTITION BY customer_id ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) AS amt_30d_avg, LAG(amount, 1) OVER (PARTITION BY customer_id ORDER BY date) AS amt_prev_day FROM base
sql SELECT customer_id, COUNT(*) AS txn_cnt, SUM(amount) AS total_spent, MAX(amount) AS max_txn, AVG(amount) AS avg_txn FROM enriched GROUP BY customer_id
HAVING total_spent > 0
python df = pd.read_sql(final_sql, con=engine) # engine = SQLAlchemy connection
Mistake: Using INNER JOIN when you need all customers, causing churn‑label rows to disappear. Correction: Switch to LEFT JOIN on the fact table so every customer appears, and fill missing metrics with 0 (e.g., COALESCE(SUM(amount),0)).
LEFT JOIN
0
COALESCE(SUM(amount),0)
Mistake: Applying WHERE after a window function, unintentionally discarding rows needed for the window calculation. Correction: Filter before the window or wrap the windowed query in a CTE/subquery, then apply WHERE on the outer layer.
Mistake: Forgetting to GROUP BY all non‑aggregated columns, leading to SQL errors or unintended Cartesian products. Correction: List every column that isn’t an aggregate in the GROUP BY clause, or move those columns into a subquery/CTE.
GROUP BY
Mistake: Using UNION when you actually need UNION ALL, causing duplicate rows to be removed silently. Correction: Choose UNION ALL for stacking logs (e.g., daily transaction tables) unless you truly need deduplication.
Mistake: Relying on DISTINCT to “dedupe” after a JOIN, which masks underlying data‑quality problems. Correction: Diagnose why duplicates appear (e.g., many‑to‑many joins) and resolve the join logic rather than masking it.
DISTINCT
Correlated subqueries reference outer‑query columns and are re‑evaluated per row; regular subqueries are computed once.
When would you prefer a window function over a GROUP BY aggregation?
When you need row‑level results and aggregated context (e.g., “running total” or “rolling average”) without collapsing rows.
How do you avoid “double counting” when joining a fact table to multiple dimension tables?
Use a “star schema” pattern: join each dimension separately in subqueries/CTEs, or aggregate the fact table first before joining.
What is the performance impact of LEFT JOIN vs. INNER JOIN and how can you mitigate it?
Scenario: You need the 7‑day rolling average spend per customer, but you also need to keep rows where a customer had no transactions in the last 7 days. Answer: Use a LEFT JOIN to the transactions table and compute AVG(amount) OVER (PARTITION BY customer_id ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW), then COALESCE the result to 0.
AVG(amount) OVER (PARTITION BY customer_id ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
COALESCE
Scenario: After joining orders to order_items you notice each order appears three times. What likely went wrong? Answer: You performed a many‑to‑many join (order ↔ items) without aggregating; fix by aggregating order_items first (e.g., SUM(quantity) GROUP BY order_id) then join.
order_items
SUM(quantity) GROUP BY order_id
Scenario: A model built on aggregated customer features shows a sudden drop in performance after adding a new data source. Answer: The new source probably introduced duplicate rows via an INNER JOIN; verify join keys and use DISTINCT or proper aggregation to eliminate duplicates.
INNER
LEFT
WITH ranked AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY key ORDER BY dt DESC) rn FROM tbl) SELECT * FROM ranked WHERE rn = 1
customer_id
EXPLAIN
SELECT *
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.