SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

SQL MasteryAdvanced

Production patterns, performance, security hardening

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore SQL Mastery Team
Expert Content

SQL — Advanced

Hard LeetCode SQL Patterns

These patterns appear repeatedly in real interviews at product companies — each one below is a well-known, publicly documented problem (referenced by its common LeetCode number where applicable) rather than a one-off invented example, so you can find more practice on the same pattern easily.

Pattern 1: Finding Median

sql
-- LeetCode 571: Find Median Given Frequency of Numbers
-- Numbers table: Number (value), Frequency (how many times it appears)
-- Approach: expand numbers using cumulative frequency, find middle value

SELECT AVG(Number) AS median
FROM (
    SELECT
        Number,
        Frequency,
        SUM(Frequency) OVER (ORDER BY Number) AS cumulative,
        SUM(Frequency) OVER () AS total
    FROM Numbers
) t
WHERE cumulative >= total / 2
  AND cumulative - Frequency < total / 2;

-- Explanation:
-- If total = 12, median position is between rows 6 and 7
-- cumulative >= 6 AND cumulative - freq < 6
-- This selects the row(s) that contain positions 6 or 7

Pattern 2: Product & Project Sales Analysis

sql
-- LeetCode 1075: Project Employees I
-- Find average experience for each project
SELECT p.project_id,
       ROUND(AVG(e.experience_years), 2) AS average_years
FROM Project p
JOIN Employee e ON p.employee_id = e.employee_id
GROUP BY p.project_id;

-- LeetCode 1069: Product Sales Analysis II
-- Find total quantity sold for each product
SELECT product_id, SUM(quantity) AS total_quantity
FROM Sales
GROUP BY product_id;

-- Only products sold in Spring 2019 (exclusively)
SELECT DISTINCT s.product_id, p.product_name
FROM Sales s
LEFT JOIN Product p ON s.product_id = p.product_id
WHERE s.product_id NOT IN (
    SELECT product_id FROM Sales
    WHERE sale_date NOT BETWEEN '2019-01-01' AND '2019-03-31'
)
GROUP BY s.product_id;

-- Cleaner with HAVING + date filter — MySQL only: relies on MySQL's
-- implicit boolean-to-integer (1/0) coercion inside SUM(). PostgreSQL and
-- SQL Server both reject SUM() on a boolean expression directly; use CASE:
SELECT DISTINCT s.product_id, p.product_name
FROM Sales s
LEFT JOIN Product p ON p.product_id = s.product_id
GROUP BY s.product_id
HAVING SUM(sale_date < '2019-01-01') = 0        -- MySQL
   AND SUM(sale_date > '2019-03-31') = 0;

-- Portable version (PostgreSQL, SQL Server):
SELECT DISTINCT s.product_id, p.product_name
FROM Sales s
LEFT JOIN Product p ON p.product_id = s.product_id
GROUP BY s.product_id
HAVING SUM(CASE WHEN sale_date < '2019-01-01' THEN 1 ELSE 0 END) = 0
   AND SUM(CASE WHEN sale_date > '2019-03-31' THEN 1 ELSE 0 END) = 0;

Pattern 3: User Activity and Retention

sql
-- LeetCode 1083: User Activity First Login Date
-- Find first login date for each player
SELECT player_id, MIN(event_date) AS first_login
FROM Activity
GROUP BY player_id;

-- LeetCode 1141: User Activities in Past 30 Days I
SELECT activity_date AS day,
       COUNT(DISTINCT user_id) AS active_users
FROM Activity
WHERE activity_date > DATE_SUB('2019-07-27', INTERVAL 30 DAY)
  AND activity_date <= '2019-07-27'
GROUP BY activity_date;

-- Users who logged in within 90 days (LeetCode 1097)
SELECT login_date,
       COUNT(user_id) AS user_count
FROM (
    SELECT user_id, MIN(activity_date) AS login_date
    FROM Traffic
    WHERE activity = 'login'
    GROUP BY user_id
) t
WHERE login_date >= DATE_ADD('2019-06-30', INTERVAL -90 DAY)
GROUP BY login_date;

Pattern 4: Hierarchy and Tree Queries

sql
-- LeetCode 608: Tree Node Classification
-- Given a table with id and p_id (parent), classify each node:
-- Root (p_id IS NULL), Leaf (id not in p_ids), Inner (everything else)
SELECT id,
    CASE
        WHEN p_id IS NULL THEN 'Root'
        WHEN id NOT IN (SELECT DISTINCT p_id FROM tree WHERE p_id IS NOT NULL) THEN 'Leaf'
        ELSE 'Inner'
    END AS Type
FROM tree;

-- Finding employees under a manager
-- All direct + indirect reports of a manager
-- PostgreSQL, MySQL 8+, SQLite: the RECURSIVE keyword is required.
-- SQL Server: drop RECURSIVE entirely (plain WITH ... AS) — SQL Server
-- infers recursion from the query structure and treats RECURSIVE as a
-- syntax error if included.
WITH RECURSIVE Hierarchy AS (
    SELECT id, name, managerId
    FROM employees
    WHERE managerId IS NULL  -- start at top

    UNION ALL

    SELECT e.id, e.name, e.managerId
    FROM employees e
    JOIN Hierarchy h ON e.managerId = h.id  -- join to previous level
)
SELECT * FROM Hierarchy;

Pattern 5: Pivot Tables

sql
-- Convert rows to columns (MySQL doesn't have PIVOT, use CASE)
-- Sales by quarter
SELECT
    product,
    SUM(CASE WHEN quarter = 'Q1' THEN sales ELSE 0 END) AS Q1,
    SUM(CASE WHEN quarter = 'Q2' THEN sales ELSE 0 END) AS Q2,
    SUM(CASE WHEN quarter = 'Q3' THEN sales ELSE 0 END) AS Q3,
    SUM(CASE WHEN quarter = 'Q4' THEN sales ELSE 0 END) AS Q4
FROM sales_data
GROUP BY product;

-- Transpose gender count by department
SELECT department,
    COUNT(CASE WHEN gender = 'M' THEN 1 END) AS male_count,
    COUNT(CASE WHEN gender = 'F' THEN 1 END) AS female_count
FROM employees
GROUP BY department;

Pattern 6: The N-th Highest Pattern

sql
-- Employee table: Id, Name, Salary, ManagerId (same shape used throughout this tab)
-- Nth highest salary — three approaches

-- Approach 1: MySQL function with LIMIT OFFSET. Needs a DELIMITER change to
-- run as-is — the semicolons inside BEGIN...END would otherwise be read as
-- statement terminators by the client before CREATE FUNCTION completes:
DELIMITER //
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
    DECLARE offset_n INT;
    SET offset_n = N - 1;
    RETURN (
        SELECT DISTINCT Salary
        FROM Employee
        ORDER BY Salary DESC
        LIMIT 1 OFFSET offset_n
    );
END //
DELIMITER ;

-- Approach 2: Window function (works in all modern DBs)
SELECT DISTINCT salary AS getNthHighestSalary
FROM (
    SELECT salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
    FROM Employee
) ranked
WHERE rnk = N;

-- Approach 3: Correlated subquery
SELECT DISTINCT Salary
FROM Employee e1
WHERE N - 1 = (
    SELECT COUNT(DISTINCT Salary)
    FROM Employee e2
    WHERE e2.Salary > e1.Salary
);
-- "Find salary where exactly N-1 salaries are greater than it"

Pattern 7: Finding Missing / Extra Data

sql
-- Delete duplicates, keep row with lowest id (LeetCode 196)
-- MySQL-only multi-table DELETE syntax:
DELETE p1 FROM Person p1, Person p2
WHERE p1.Email = p2.Email
  AND p1.Id > p2.Id;

-- Portable equivalent (PostgreSQL, SQL Server):
DELETE FROM Person
WHERE Id NOT IN (SELECT MIN(Id) FROM Person GROUP BY Email);

-- Find duplicate emails
SELECT Email FROM Person
GROUP BY Email HAVING COUNT(*) > 1;

-- Customers who never ordered (LeetCode 183)
SELECT Name AS Customers
FROM Customers
WHERE Id NOT IN (SELECT CustomerId FROM Orders);

-- Using LEFT JOIN (often faster)
SELECT c.Name AS Customers
FROM Customers c
LEFT JOIN Orders o ON c.Id = o.CustomerId
WHERE o.Id IS NULL;

Pattern 8: Running Totals and Lag/Lead

sql
-- LAG: access previous row value
SELECT
    emp_no,
    salary,
    LAG(salary) OVER (PARTITION BY emp_no ORDER BY from_date) AS prev_salary,
    salary - LAG(salary) OVER (PARTITION BY emp_no ORDER BY from_date) AS increase
FROM salaries;

-- LEAD: access next row value
SELECT
    date,
    revenue,
    LEAD(revenue) OVER (ORDER BY date) AS next_day_revenue,
    LEAD(revenue) OVER (ORDER BY date) - revenue AS change
FROM daily_revenue;

-- First and Last value in partition
SELECT
    department,
    employee,
    salary,
    FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS highest_in_dept,
    LAST_VALUE(salary)  OVER (PARTITION BY department ORDER BY salary DESC
                               ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS lowest_in_dept
FROM salaries;

Performance Optimization

sql
-- Use indexes effectively
-- Index on columns used in WHERE, JOIN ON, ORDER BY, GROUP BY

-- CHECK if index is being used
EXPLAIN SELECT * FROM Employee WHERE DepartmentId = 1;
-- type: 'ref' = index used, 'ALL' = full scan (bad for large tables)

-- Covering index: index contains all columns needed by query
-- No table lookup needed — faster
CREATE INDEX idx_emp_dept_sal ON Employee(DepartmentId, Salary);
-- Now this query uses index only (no table access):
SELECT Salary FROM Employee WHERE DepartmentId = 1;

-- Avoid functions on indexed columns in WHERE — disables index
-- BAD:
WHERE YEAR(created_at) = 2019
-- GOOD:
WHERE created_at >= '2019-01-01' AND created_at < '2020-01-01'

-- Use LIMIT when you only need N rows
SELECT * FROM large_table WHERE status = 'pending'
ORDER BY created_at
LIMIT 100;  -- much faster than returning all rows

-- Avoid SELECT * in production
-- Only select columns you need
SELECT id, name, email FROM users WHERE active = 1;

SQL Interview Problem: Cancellation Rate (Hard)

sql
-- LeetCode 262: Trips and Users — one of the hardest SQL problems
-- Find cancellation rate per day for unbanned users

SELECT t.Request_at AS Day,
       ROUND(
           SUM(CASE WHEN t.Status != 'completed' THEN 1 ELSE 0 END) * 1.0 /
           COUNT(*),
           2
       ) AS "Cancellation Rate"
FROM Trips t
WHERE t.Client_Id NOT IN (
    SELECT Users_Id FROM Users WHERE Banned = 'Yes'
)
AND t.Driver_Id NOT IN (
    SELECT Users_Id FROM Users WHERE Banned = 'Yes'
)
AND t.Request_at BETWEEN '2013-10-01' AND '2013-10-03'
GROUP BY t.Request_at;

-- Key insight: filter out banned users for BOTH client AND driver
-- Then count cancelled (status != 'completed') / total per day
-- The "* 1.0" matters on PostgreSQL and SQL Server: integer / integer
-- truncates to an integer there (silently returning 0 for every row),
-- unlike MySQL's "/" which always produces a decimal result.

SQL Interview Problem: Third Highest Salary with CTEs

sql
-- Find employee with 3rd maximum salary — portable (PostgreSQL, MySQL 8+, SQL Server)
WITH RankedSalaries AS (
    SELECT Salary,
           DENSE_RANK() OVER (ORDER BY Salary DESC) AS rnk
    FROM Employee
),
ThirdHighest AS (
    SELECT MAX(Salary) AS third_salary
    FROM RankedSalaries
    WHERE rnk = 3
)
SELECT a.* FROM Employee a
JOIN ThirdHighest t ON a.Salary = t.third_salary;

-- Alternative using the ROWNUM pattern (Oracle). ROWNUM is assigned to rows
-- BEFORE any ORDER BY in the same query block -- so filtering on ROWNUM
-- and ordering in one flat query does NOT reliably give you "top N by
-- salary." The ordering has to happen in an inner subquery first, with
-- ROWNUM applied only in the outer query against the already-sorted result:
WITH TEMP AS (
    SELECT MAX(salary) AS salary
    FROM Employee
    WHERE salary NOT IN (
        SELECT salary FROM (
            SELECT salary FROM Employee ORDER BY salary DESC
        )
        WHERE ROWNUM < 3
    )
)
SELECT a.* FROM Employee a JOIN TEMP b ON a.salary = b.salary;
Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Quick Check — SQL Mastery
1 / 1

What is the first step when optimizing a production system?

Up Next
🗺️
SQL MasteryRoadmap
Step-by-step structured learning path from zero to expert
Also Worth Exploring
← Back to all SQL Mastery modules
IntermediateRoadmap