Career & Skills

Top 50 MySQL Queries for Experienced Developers – Interview & Practice Guide

Read the important current affairs of 15 July 2026 for SSC, Banking, UPSC, Railway and all competitive exams.

12 Aug 2024 5 Min Read Quizer Team 170 Views
Top 50 MySQL Queries for Experienced Developers – Interview & Practice Guide

12

August 2024

Master the Top 50 MySQL Queries for Experienced Developers with practical examples covering JOINs, subqueries, CTEs, window functions, ranking, duplicates, indexing, EXPLAIN and query optimization.


If you are preparing for a PHP Developer, Backend Developer, Full Stack Developer, Software Engineer, or Database Developer interview, these 50 MySQL queries are essential for experienced-level preparation.

The list covers JOINs, subqueries, aggregation, duplicate handling, CTEs, window functions, ranking, date queries, transactions, optimization, and real-world reporting queries.

Note: Queries using ROW_NUMBER(), RANK(), DENSE_RANK(), LAG(), LEAD(), and CTEs are intended for modern MySQL versions such as MySQL 8.x.


1. Find Duplicate Emails

SELECT email, COUNT(*) AS total
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

Use: Find duplicate email addresses.


2. Find Complete Duplicate User Records

SELECT *
FROM users
WHERE email IN (
    SELECT email
    FROM users
    GROUP BY email
    HAVING COUNT(*) > 1
)
ORDER BY email;

3. Find the Second Highest Salary

SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (
    SELECT MAX(salary)
    FROM employees
);

4. Find the Nth Highest Salary

SELECT salary
FROM (
    SELECT
        salary,
        DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
    FROM employees
) t
WHERE rnk = 5;

Change 5 to the required rank.


5. Find Highest Salary in Each Department

SELECT department_id, employee_id, salary
FROM (
    SELECT
        department_id,
        employee_id,
        salary,
        RANK() OVER (
            PARTITION BY department_id
            ORDER BY salary DESC
        ) AS rnk
    FROM employees
) t
WHERE rnk = 1;

6. Find Top 3 Salaries in Every Department

SELECT *
FROM (
    SELECT
        employee_id,
        department_id,
        salary,
        DENSE_RANK() OVER (
            PARTITION BY department_id
            ORDER BY salary DESC
        ) AS rnk
    FROM employees
) t
WHERE rnk <= 3;

7. Find Employees Earning More Than Department Average

SELECT e.*
FROM employees e
JOIN (
    SELECT
        department_id,
        AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
) d
ON e.department_id = d.department_id
WHERE e.salary > d.avg_salary;

8. Find Departments Having More Than 5 Employees

SELECT
    department_id,
    COUNT(*) AS employee_count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;

9. Find Employees Without a Department

SELECT e.*
FROM employees e
LEFT JOIN departments d
    ON e.department_id = d.id
WHERE d.id IS NULL;

10. Find Departments Without Employees

SELECT d.*
FROM departments d
LEFT JOIN employees e
    ON d.id = e.department_id
WHERE e.id IS NULL;

11. Get Latest Record for Each User

One of the most useful queries in real-world applications.

SELECT *
FROM (
    SELECT
        a.*,
        ROW_NUMBER() OVER (
            PARTITION BY user_id
            ORDER BY created_at DESC
        ) AS rn
    FROM user_attempts a
) t
WHERE rn = 1;

12. Get Latest Approved Record for Each User

SELECT *
FROM (
    SELECT
        a.*,
        ROW_NUMBER() OVER (
            PARTITION BY user_id
            ORDER BY approved_at DESC
        ) AS rn
    FROM applications a
    WHERE status = 'approved'
) t
WHERE rn = 1;

13. Find the First Order of Every Customer

SELECT *
FROM (
    SELECT
        o.*,
        ROW_NUMBER() OVER (
            PARTITION BY user_id
            ORDER BY created_at ASC
        ) AS rn
    FROM orders o
) t
WHERE rn = 1;

14. Find the Second Order of Every Customer

SELECT *
FROM (
    SELECT
        o.*,
        ROW_NUMBER() OVER (
            PARTITION BY user_id
            ORDER BY created_at ASC
        ) AS order_number
    FROM orders o
) t
WHERE order_number = 2;

15. Find Users Who Never Placed an Order

SELECT u.*
FROM users u
LEFT JOIN orders o
    ON u.id = o.user_id
WHERE o.id IS NULL;

16. Find Users Who Placed More Than 3 Orders

SELECT
    user_id,
    COUNT(*) AS total_orders
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 3;

17. Calculate Total Purchase per Customer

SELECT
    user_id,
    SUM(amount) AS total_purchase
FROM orders
GROUP BY user_id;

18. Find Customers Spending More Than ₹50,000

SELECT
    user_id,
    SUM(amount) AS total_purchase
FROM orders
GROUP BY user_id
HAVING SUM(amount) > 50000;

19. Monthly Sales Report

SELECT
    YEAR(created_at) AS year,
    MONTH(created_at) AS month,
    SUM(amount) AS total_sales
FROM orders
GROUP BY
    YEAR(created_at),
    MONTH(created_at)
ORDER BY year DESC, month DESC;

20. Daily Sales Report

SELECT
    DATE(created_at) AS sale_date,
    SUM(amount) AS total_sales,
    COUNT(*) AS total_orders
FROM orders
GROUP BY DATE(created_at)
ORDER BY sale_date DESC;

21. Find Records Created in Last 7 Days

SELECT *
FROM orders
WHERE created_at >= NOW() - INTERVAL 7 DAY;

22. Find Records Created in Current Month

SELECT *
FROM orders
WHERE created_at >= DATE_FORMAT(
    CURRENT_DATE,
    '%Y-%m-01'
);

This form can be preferable to wrapping the indexed created_at column in a function.


23. Find Records Between Two Dates

SELECT *
FROM orders
WHERE created_at >= '2026-09-01'
  AND created_at < '2026-10-01';

Using a half-open date range is especially useful when created_at is a DATETIME.


24. Conditional Aggregation

SELECT
    COUNT(*) AS total_users,
    SUM(status = 'active') AS active_users,
    SUM(status = 'inactive') AS inactive_users,
    SUM(status = 'blocked') AS blocked_users
FROM users;

25. Count Pass and Fail Students

SELECT
    COUNT(*) AS total_students,
    SUM(CASE
        WHEN marks >= 60 THEN 1
        ELSE 0
    END) AS passed,
    SUM(CASE
        WHEN marks < 60>

26. Calculate Running Total

SELECT
    id,
    order_date,
    amount,
    SUM(amount) OVER (
        ORDER BY order_date, id
    ) AS running_total
FROM orders;

Window functions calculate values across related rows while retaining individual result rows.


27. Calculate Running Total per Customer

SELECT
    user_id,
    order_date,
    amount,
    SUM(amount) OVER (
        PARTITION BY user_id
        ORDER BY order_date, id
    ) AS running_total
FROM orders;

28. Compare Current Value with Previous Value

SELECT
    employee_id,
    effective_date,
    salary,
    LAG(salary) OVER (
        PARTITION BY employee_id
        ORDER BY effective_date
    ) AS previous_salary
FROM employee_salary_history;

29. Find Salary Changes

SELECT *
FROM (
    SELECT
        employee_id,
        effective_date,
        salary,
        LAG(salary) OVER (
            PARTITION BY employee_id
            ORDER BY effective_date
        ) AS previous_salary
    FROM employee_salary_history
) t
WHERE previous_salary IS NOT NULL
  AND salary <> previous_salary;

30. Calculate Salary Increase Percentage

SELECT
    employee_id,
    salary,
    previous_salary,
    ROUND(
        ((salary - previous_salary)
        / previous_salary) * 100,
        2
    ) AS increase_percentage
FROM (
    SELECT
        employee_id,
        salary,
        LAG(salary) OVER (
            PARTITION BY employee_id
            ORDER BY effective_date
        ) AS previous_salary
    FROM employee_salary_history
) t
WHERE previous_salary IS NOT NULL
  AND previous_salary <> 0;

31. Find Status Changes

SELECT *
FROM (
    SELECT
        user_id,
        status,
        updated_at,
        LAG(status) OVER (
            PARTITION BY user_id
            ORDER BY updated_at
        ) AS previous_status
    FROM user_status
) t
WHERE previous_status IS NOT NULL
  AND status <> previous_status;

32. Find Duplicate Records Using ROW_NUMBER()

SELECT *
FROM (
    SELECT
        u.*,
        ROW_NUMBER() OVER (
            PARTITION BY email
            ORDER BY id
        ) AS rn
    FROM users u
) t
WHERE rn > 1;

33. Delete Duplicate Records

Keep the smallest ID.

DELETE u1
FROM users u1
JOIN users u2
    ON u1.email = u2.email
   AND u1.id > u2.id;

⚠️ Always take a backup and test the corresponding SELECT before running a DELETE in production.


34. Find Missing IDs

SELECT t1.id + 1 AS missing_id
FROM numbers t1
LEFT JOIN numbers t2
    ON t2.id = t1.id + 1
WHERE t2.id IS NULL;

35. Use CTE for Better Query Structure

WITH department_avg AS (
    SELECT
        department_id,
        AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT
    e.employee_id,
    e.department_id,
    e.salary,
    d.avg_salary
FROM employees e
JOIN department_avg d
    ON e.department_id = d.department_id
WHERE e.salary > d.avg_salary;

A CTE is a named temporary result set available within the scope of a single statement.


36. Recursive CTE for Number Generation

WITH RECURSIVE numbers AS (
    SELECT 1 AS n

    UNION ALL

    SELECT n + 1
    FROM numbers
    WHERE n < 10>

Recursive CTEs can be useful for generating sequences and traversing hierarchical data.


37. Recursive Employee Hierarchy

WITH RECURSIVE employee_tree AS (

    SELECT
        id,
        name,
        manager_id,
        1 AS level
    FROM employees
    WHERE manager_id IS NULL

    UNION ALL

    SELECT
        e.id,
        e.name,
        e.manager_id,
        et.level + 1
    FROM employees e
    JOIN employee_tree et
        ON e.manager_id = et.id
)
SELECT *
FROM employee_tree
ORDER BY level, id;

38. Find Employees with Same Salary

SELECT salary, COUNT(*) AS total
FROM employees
GROUP BY salary
HAVING COUNT(*) > 1;

39. Find Employees with Same Name

SELECT
    name,
    COUNT(*) AS total
FROM employees
GROUP BY name
HAVING COUNT(*) > 1;

40. Find Maximum Salary Without MAX()

SELECT salary
FROM employees
ORDER BY salary DESC
LIMIT 1;

41. Find Second Highest Salary Using LIMIT

SELECT DISTINCT salary
FROM employees
ORDER BY salary DESC
LIMIT 1 OFFSET 1;

42. Find Employees Whose Salary Is Between Two Values

SELECT *
FROM employees
WHERE salary BETWEEN 50000 AND 100000;

43. Find Employees Joined in the Current Year

SELECT *
FROM employees
WHERE joined_at >= MAKEDATE(YEAR(CURRENT_DATE), 1)
  AND joined_at < MAKEDATE>

44. Find the Percentage of Active Users

SELECT
    ROUND(
        100 * SUM(status = 'active') / COUNT(*),
        2
    ) AS active_percentage
FROM users;

45. Find Products Never Ordered

SELECT p.*
FROM products p
LEFT JOIN order_items oi
    ON p.id = oi.product_id
WHERE oi.product_id IS NULL;

46. Find Best-Selling Products

SELECT
    product_id,
    SUM(quantity) AS total_quantity
FROM order_items
GROUP BY product_id
ORDER BY total_quantity DESC
LIMIT 10;

47. Find Customers with More Than One Order

SELECT
    user_id,
    COUNT(*) AS total_orders
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 1;

48. Find Records Existing in One Table but Not Another

Using NOT EXISTS:

SELECT u.*
FROM users u
WHERE NOT EXISTS (
    SELECT 1
    FROM payments p
    WHERE p.user_id = u.id
);

This is useful when checking missing related records.


49. Use EXPLAIN to Analyze a Query

EXPLAIN
SELECT *
FROM orders
WHERE user_id = 1001
  AND status = 'completed';

For performance troubleshooting, experienced developers should understand execution plans, indexes, joins, row estimates, and access methods. MySQL's documentation has dedicated sections for index usage, multiple-column indexes, verifying index usage, and query optimization.


50. Create a Composite Index

CREATE INDEX idx_orders_user_status
ON orders (user_id, status);

Then analyze the query:

EXPLAIN
SELECT *
FROM orders
WHERE user_id = 1001
  AND status = 'completed';

The right index depends on the actual query workload and data distribution—don't add indexes blindly.


???? Top MySQL Concepts for Experienced Developers

TopicImportance
JOINs⭐⭐⭐⭐⭐
GROUP BY & HAVING⭐⭐⭐⭐⭐
Subqueries⭐⭐⭐⭐⭐
CTE⭐⭐⭐⭐⭐
Window Functions⭐⭐⭐⭐⭐
ROW_NUMBER()⭐⭐⭐⭐⭐
RANK()⭐⭐⭐⭐⭐
DENSE_RANK()⭐⭐⭐⭐⭐
LAG() / LEAD()⭐⭐⭐⭐⭐
Duplicate Handling⭐⭐⭐⭐⭐
Indexing⭐⭐⭐⭐⭐
EXPLAIN⭐⭐⭐⭐⭐
Query Optimization⭐⭐⭐⭐⭐
Transactions⭐⭐⭐⭐⭐
Stored Procedures⭐⭐⭐⭐
Views⭐⭐⭐⭐
Triggers⭐⭐⭐
Recursive CTE⭐⭐⭐⭐

???? Interview Preparation Strategy

For an experienced MySQL developer, don't simply memorize these queries.

Understand:

1. What problem does the query solve?

2. Why is JOIN used instead of a subquery?

3. When should EXISTS be preferred?

4. How does ROW_NUMBER() differ from RANK() and DENSE_RANK()?

5. Which columns should be indexed?

6. How do you identify a slow query using EXPLAIN?

7. How do transactions and COMMIT/ROLLBACK work?

8. How does the query behave when the table contains millions of records?

Quick Revision Formula

SELECT → JOIN → GROUP BY → HAVING → Subquery → CTE → Window Functions → Index → EXPLAIN → Optimization → Transactions

Master these concepts and you'll be much better prepared for experienced-level MySQL interviews and real-world backend development.

Important

Some queries above use MySQL 8.x features, particularly CTEs and window functions. Check your production MySQL version before using them. MySQL's current 8.4 reference documents these features and the associated syntax.

Why Quizer.in is Important?

Quizer.in is your complete one-stop platform for daily current affairs, interactive quizzes, and exam-focused study material. Whether you are preparing for SSC, Banking, Railway, UPSC, State PSC or Teaching exams, regular practice on Quizer.in helps you:

  • Stay updated with the latest current affairs
  • Improve accuracy and speed through daily quizzes
  • Strengthen your General Awareness section
  • Build consistency and stay ahead of the competition
Quizer Team
About the Author

Quizer Team

Passionate about current affairs, competitive exams, and helping aspirants succeed.

📢 Join Our WhatsApp Channel

Get Daily GK, Current Affairs, Amazing Facts & Quiz Updates.

🚀 Join Now

Related Articles

View All
Career & Skills
29 Aug 2025 66
Read More
Career & Skills
4 Jun 2025 81
Read More
Career & Skills
22 Aug 2024 295
Read More