top of page

Top SQL Interview Questions for Freshers: Queries, Real-World Data, and Whiteboard Logic

Sep 16
4 min read

Technical screening rounds in 2026 evaluate whether you understand data behavior, null constraints, and table relationships before writing code. Below are the most critical SQL interview questions, structured with real input datasets, production query solutions, expected outputs, and whiteboard evaluation logic.


1. How do you find the second highest salary when salaries are duplicated?


Business Scenario: HR wants to identify the second highest compensation bracket, but multiple senior executives earn identical top salaries.


Input Table: employees

emp_id

emp_name

department

salary

101

Rohit

Engineering

95,000

102

Ananya

Engineering

95,000

103

Vikas

Product

82,000

104

Priya

Marketing

75,000

105

Aman

Analytics

82,000

SQL Query:

SQL

WITH RankedSalaries AS (
    SELECT 
        emp_name,
        salary,
        DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
    FROM employees
)
SELECT emp_name, salary
FROM RankedSalaries
WHERE rnk = 2;

Expected Output:

emp_name

salary

Vikas

82,000

Aman

82,000

The Whiteboard Defense:


  • If you use ROW_NUMBER(), it arbitrarily assigns ranks 1 and 2 to Rohit and Ananya, returning ₹95,000 as the second highest salary—which is incorrect.


  • If you use RANK(), ranks become 1, 1, 3 (skipping rank 2 entirely), returning zero rows.


  • DENSE_RANK() assigns ranks 1, 1, 2, 2, 3, ensuring the true second-highest salary (₹82,000) is returned along with all employees earning it.


To master relational schemas before tackling window functions, explore: Data Engineering with SQL: An Introductory Guide.


2. How do you find customers who signed up but never placed an order?


Business Scenario: The growth marketing team needs a list of registered users who have zero purchase activity for an activation discount campaign.


Input Tables:

customers Table:

customer_id

name

signup_date

1

Aarav

2026-01-10

2

Neha

2026-01-15

3

Kabir

2026-02-01

4

Simran

2026-02-12

orders Table:

order_id

customer_id

order_amount

5001

1

2,400

5002

1

1,100

5003

3

4,950

SQL Query:

SQL

SELECT 
    c.customer_id, 
    c.name, 
    c.signup_date
FROM customers c
LEFT JOIN orders o 
    ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

Expected Output:

customer_id

name

signup_date

2

Neha

2026-01-15

4

Simran

2026-02-12


The Whiteboard Defense:

A LEFT JOIN keeps all records from customers. For customers without matching orders, the columns from orders populate as NULL. Filtering by WHERE o.order_id IS NULL isolates unactivated users without expensive correlated subqueries.


If you are connecting your database outputs to automated Python scripts, check out: Why Python and MySQL Are Perfect for Data Science.



3. How do you calculate Month-over-Month (MoM) revenue growth?


Business Scenario: Finance requires executive reporting on whether monthly revenue is expanding or contracting, alongside the percentage change.


Input Table: monthly_revenue

sales_month

total_revenue

2026-01-01

1,00,000

2026-02-01

1,30,000

2026-03-01

1,17,000

SQL Query:

SQL

SELECT 
    sales_month,
    total_revenue,
    LAG(total_revenue, 1) OVER (ORDER BY sales_month) AS prev_month_revenue,
    ROUND(
        ((total_revenue - LAG(total_revenue, 1) OVER (ORDER BY sales_month)) * 100.0) / 
        LAG(total_revenue, 1) OVER (ORDER BY sales_month), 
        2
    ) AS mom_growth_pct
FROM monthly_revenue;

Expected Output:

sales_month

total_revenue

prev_month_revenue

mom_growth_pct

2026-01-01

1,00,000

NULL

NULL

2026-02-01

1,30,000

1,00,000

30.00

2026-03-01

1,17,000

1,30,000

-10.00

The Whiteboard Defense:


The LAG() window function inspects the previous chronological row without requiring a self-join. Multiplying the numerator by 100.0 prevents integer division truncation in database engines like PostgreSQL or SQL Server.


To integrate commercial metrics into visual KPI dashboards, read: What Is Power BI? A Beginner's Guide.


4. How do you remove duplicate rows while keeping only the earliest entry?


Business Scenario: A webhook sync error inserted duplicate lead entries with identical emails into the database.


Input Table: leads

lead_id

email

lead_source

created_at

1

Google Ads

2026-03-01 10:00:00

2

Organic

2026-03-01 10:15:00

3

Referral

2026-03-01 11:30:00

4

Direct

2026-03-01 12:00:00

SQL Query:

SQL

WITH RankedDuplicates AS (
    SELECT 
        lead_id,
        ROW_NUMBER() OVER (
            PARTITION BY email 
            ORDER BY created_at ASC
        ) AS row_num
    FROM leads
)
DELETE FROM leads
WHERE lead_id IN (
    SELECT lead_id 
    FROM RankedDuplicates 
    WHERE row_num > 1
);

Remaining Records in leads Table:

lead_id

email

lead_source

created_at

1

Google Ads

2026-03-01 10:00:00

3

Referral

2026-03-01 11:30:00

The Whiteboard Defense:


PARTITION BY email groups the records per unique email address, while ORDER BY created_at ASC assigns row_num = 1 to the first chronological submission.

Filtering for row_num > 1 safely targets only the redundant copies for deletion.


For data cleaning tasks conducted inside Python scripts, explore: How to Use Python for Data Analysis: A Beginner's Guide.


5. How do you compute a rolling 3-month average of active users?


Business Scenario: Product teams track smoothed engagement trends to remove weekend and seasonal spikes from daily counts.


Input Table: daily_active_users

activity_date

active_users

2026-01-01

1,200

2026-02-01

1,500

2026-03-01

1,800

2026-04-01

2,100

SQL Query:

SQL

SELECT 
    activity_date,
    active_users,
    ROUND(
        AVG(active_users) OVER (
            ORDER BY activity_date
            ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
        ), 1
    ) AS rolling_3_month_avg
FROM daily_active_users;

Expected Output:

activity_date

active_users

rolling_3_month_avg

Calculation Context

2026-01-01

1,200

1200.0

(1200 / 1)

2026-02-01

1,500

1350.0

(1200 + 1500) / 2

2026-03-01

1,800

1500.0

(1200 + 1500 + 1800) / 3

2026-04-01

2,100

1800.0

(1500 + 1800 + 2100) / 3

The Whiteboard Defense:


The framing clause ROWS BETWEEN 2 PRECEDING AND CURRENT ROW explicitly restricts the moving window to the current row plus the two preceding rows, preventing unbound default frame errors (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW).



Master Technical Whiteboard Interviews at IOTA Academy


Memorizing SQL templates on your own leaves you vulnerable when interviewers change column constraints or ask you to debug query joins live on a screen.


At IOTA Academy Indore, IIT alumni and industry data practitioners train freshers inside offline learning labs using uncurated production schemas[cite: 1, 2]:



Build verified technical problem-solving skills that pass corporate screenings: Explore IOTA Academy Courses & Book Your Free 1-on-1 Counseling Session Today.



 
 
 

Comments


bottom of page