0% found this document useful (0 votes)
3 views21 pages

SQL Interview Questions Cleaned

The document contains a compilation of 300 SQL interview questions and solutions, primarily aimed at medium to advanced SQL users. It includes various SQL queries addressing common scenarios such as finding duplicates, calculating salaries, and analyzing employee data across different departments. The questions are designed to prepare candidates for interviews at major firms like PwC, Deloitte, and Accenture.

Uploaded by

mohkhaled6100
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views21 pages

SQL Interview Questions Cleaned

The document contains a compilation of 300 SQL interview questions and solutions, primarily aimed at medium to advanced SQL users. It includes various SQL queries addressing common scenarios such as finding duplicates, calculating salaries, and analyzing employee data across different departments. The questions are designed to prepare candidates for interviews at major firms like PwC, Deloitte, and Accenture.

Uploaded by

mohkhaled6100
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

SQL Interview Questions & Solutions Page 1 of 21

300 REAL SQL INTERVIEW QUESTIONS


Asked at PwC, Deloitte, EY, KPMG, Tredence, Persistent Systems, Accenture & More
Compiled by Krishna Singh

Medium to Advanced SQL Questions

1. Find the second highest salary from the Employee table.

SELECT MAX(salary) AS SecondHighestSalary


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

2. Find duplicate records in a table based on name.

SELECT name, COUNT(*)


FROM employees
GROUP BY name
HAVING COUNT(*) > 1;

3. Retrieve employees who earn more than their manager.

SELECT [Link] AS Employee, [Link], [Link] AS Manager, [Link] AS ManagerSalary


FROM employees e
JOIN employees m ON e.manager_id = [Link]
WHERE [Link] > [Link];

4. Count employees in each department having more than 5 employees.

SELECT department_id, COUNT(*) AS num_employees


FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;

5. Find employees who joined in the last 6 months.

SELECT *
FROM employees
WHERE join_date >= CURRENT_DATE - INTERVAL '6 months';
SQL Interview Questions & Solutions Page 2 of 21

6. Get departments with no employees.

SELECT d.department_name
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
WHERE [Link] IS NULL;

7. Write a query to find the median salary.

SELECT AVG(salary) AS median_salary


FROM (
SELECT salary
FROM employees
ORDER BY salary
LIMIT 2 - (SELECT COUNT(*) FROM employees) % 2
OFFSET (SELECT (COUNT(*) - 1) / 2 FROM employees)
) AS median_subquery;

8. Running total of salaries by department.

SELECT name, department_id, salary,


SUM(salary) OVER (PARTITION BY department_id ORDER BY id) AS running_total
FROM employees;

9. Find the longest consecutive streak of daily logins for each user.

WITH login_dates AS (
SELECT user_id, login_date,
login_date - INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY
login_date) DAY AS grp
FROM user_logins
)
SELECT user_id, COUNT(*) AS streak_length,
MIN(login_date) AS start_date, MAX(login_date) AS end_date
FROM login_dates
GROUP BY user_id, grp
ORDER BY streak_length DESC;
SQL Interview Questions & Solutions Page 3 of 21

10. Recursive query to find the full reporting chain for each employee.

WITH RECURSIVE reporting_chain AS (


SELECT id, name, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT [Link], [Link], e.manager_id, [Link] + 1
FROM employees e
JOIN reporting_chain rc ON e.manager_id = [Link]
)
SELECT * FROM reporting_chain ORDER BY level, id;

11. Write a query to find gaps in a sequence of numbers (missing IDs).

SELECT (id + 1) AS missing_id


FROM employees e1
WHERE NOT EXISTS (
SELECT 1 FROM employees e2 WHERE [Link] = [Link] + 1
)
ORDER BY missing_id;

12. Calculate cumulative distribution (CDF) of salaries.

SELECT name, salary,


CUME_DIST() OVER (ORDER BY salary) AS salary_cdf
FROM employees;

13. Compare two tables and find rows with differences in any column.

SELECT *
FROM table1 t1
FULL OUTER JOIN table2 t2 ON [Link] = [Link]
WHERE t1.col1 IS DISTINCT FROM t2.col1
OR t1.col2 IS DISTINCT FROM t2.col2
OR t1.col3 IS DISTINCT FROM t2.col3;

14. Write a query to rank employees based on salary with ties handled properly.

SELECT name, salary,


RANK() OVER (ORDER BY salary DESC) AS salary_rank
FROM employees;
SQL Interview Questions & Solutions Page 4 of 21

15. Find customers who have not made any purchase.

SELECT c.customer_id, [Link]


FROM customers c
LEFT JOIN sales s ON c.customer_id = s.customer_id
WHERE s.sale_id IS NULL;

16. Write a query to perform a conditional aggregation (count males and females in each department).

SELECT department_id,
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_id;

17. Write a query to calculate the difference between current row and previous row's salary (lag
function).

SELECT name, salary,


salary - LAG(salary) OVER (ORDER BY id) AS salary_diff
FROM employees;

18. Identify overlapping date ranges for bookings.

SELECT b1.booking_id AS booking1, b2.booking_id AS booking2


FROM bookings b1
JOIN bookings b2 ON b1.booking_id <> b2.booking_id
WHERE b1.start_date <= b2.end_date
AND b1.end_date >= b2.start_date;

19. Find employees with salary greater than average salary in the entire company, ordered by salary
descending.

SELECT name, salary


FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
ORDER BY salary DESC;

20. Aggregate JSON data to list all employee names in a department as a JSON array.

SELECT department_id, JSON_AGG(name) AS employee_names


FROM employees
GROUP BY department_id;
SQL Interview Questions & Solutions Page 5 of 21

21. Find employees who have the same salary as their manager.

SELECT [Link] AS Employee, [Link], [Link] AS Manager


FROM employees e
JOIN employees m ON e.manager_id = [Link]
WHERE [Link] = [Link];

22. Write a query to get the first and last purchase date for each customer.

SELECT customer_id,
MIN(purchase_date) AS first_purchase,
MAX(purchase_date) AS last_purchase
FROM sales
GROUP BY customer_id;

23. Find departments with the highest average salary.

WITH avg_salaries AS (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
)
SELECT *
FROM avg_salaries
WHERE avg_salary = (SELECT MAX(avg_salary) FROM avg_salaries);

24. Write a query to find the number of employees in each job title.

SELECT job_title, COUNT(*) AS num_employees


FROM employees
GROUP BY job_title;

25. Find employees who don't have a department assigned.

SELECT *
FROM employees
WHERE department_id IS NULL;

26. Write a query to find the difference in days between two dates in the same table.

SELECT id, DATEDIFF(day, start_date, end_date) AS days_difference


FROM projects;

Note: DATEDIFF syntax varies - replace accordingly (e.g., DATEDIFF('day', start_date, end_date) or simple subtraction in some
systems).
SQL Interview Questions & Solutions Page 6 of 21

27. Calculate the moving average of salaries over the last 3 employees ordered by hire date.

SELECT name, hire_date, salary,


AVG(salary) OVER (ORDER BY hire_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS
moving_avg_salary
FROM employees;

28. Find the most recent purchase per customer using window functions.

SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY purchase_date DESC) AS rn
FROM sales
) sub
WHERE rn = 1;

29. Detect hierarchical depth of each employee in the org chart.

WITH RECURSIVE employee_depth AS (


SELECT id, name, manager_id, 1 AS depth
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT [Link], [Link], e.manager_id, [Link] + 1
FROM employees e
JOIN employee_depth ed ON e.manager_id = [Link]
)
SELECT * FROM employee_depth;

30. Write a query to perform a self-join to find pairs of employees in the same department.

SELECT [Link] AS Employee1, [Link] AS Employee2, e1.department_id


FROM employees e1
JOIN employees e2 ON e1.department_id = e2.department_id AND [Link] < [Link];

31. Write a query to pivot rows into columns dynamically/statically.

SELECT department_id,
SUM(CASE WHEN job_title = 'Manager' THEN 1 ELSE 0 END) AS Managers,
SUM(CASE WHEN job_title = 'Developer' THEN 1 ELSE 0 END) AS Developers,
SUM(CASE WHEN job_title = 'Tester' THEN 1 ELSE 0 END) AS Testers
FROM employees
GROUP BY department_id;
SQL Interview Questions & Solutions Page 7 of 21

32. Find customers who made purchases in every category available.

SELECT customer_id
FROM sales s
GROUP BY customer_id
HAVING COUNT(DISTINCT category_id) = (SELECT COUNT(DISTINCT category_id) FROM sales);

33. Identify employees who haven’t received a salary raise in more than a year.

SELECT [Link]
FROM employees e
JOIN salary_history sh ON [Link] = sh.employee_id
GROUP BY [Link], [Link]
HAVING MAX(sh.raise_date) < CURRENT_DATE - INTERVAL '1 year';

34. Write a query to rank salespeople by monthly sales, resetting the rank every month.

SELECT salesperson_id, sale_month, total_sales,


RANK() OVER (PARTITION BY sale_month ORDER BY total_sales DESC) AS monthly_rank
FROM (
SELECT salesperson_id, DATE_TRUNC('month', sale_date) AS sale_month, SUM(amount) AS
total_sales
FROM sales
GROUP BY salesperson_id, sale_month
) AS monthly_sales;

35. Calculate the percentage change in sales compared to the previous month for each product.

SELECT product_id, sale_month, total_sales,


(total_sales - LAG(total_sales) OVER (PARTITION BY product_id ORDER BY sale_month))
* 100.0 /
LAG(total_sales) OVER (PARTITION BY product_id ORDER BY sale_month) AS pct_change
FROM (
SELECT product_id, DATE_TRUNC('month', sale_date) AS sale_month, SUM(amount) AS
total_sales
FROM sales
GROUP BY product_id, sale_month
) monthly_sales;
SQL Interview Questions & Solutions Page 8 of 21

36. Find employees who earn more than the average salary across the company but less than the
highest salary in their department.

SELECT *
FROM employees e
WHERE salary > (SELECT AVG(salary) FROM employees)
AND salary < (
SELECT MAX(salary)
FROM employees
WHERE department_id = e.department_id
);

37. Retrieve the last 5 orders for each customer.

SELECT *
FROM (
SELECT o.*, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) AS
rn
FROM orders o
) sub
WHERE rn <= 5;

38. Find employees with no salary changes in the last 2 years.

SELECT e.*
FROM employees e
LEFT JOIN salary_history sh ON [Link] = sh.employee_id AND sh.change_date >= CURRENT_DATE -
INTERVAL '2 years'
WHERE sh.employee_id IS NULL;

39. Find the department with the lowest average salary.

SELECT department_id, AVG(salary) AS avg_salary


FROM employees
GROUP BY department_id
ORDER BY avg_salary ASC
LIMIT 1;

40. List employees whose names start and end with the same letter.

SELECT *
FROM employees
WHERE LEFT(name, 1) = RIGHT(name, 1);
SQL Interview Questions & Solutions Page 9 of 21

41. Write a query to detect circular references in employee-manager hierarchy (cycles).

WITH RECURSIVE mgr_path (id, manager_id, path) AS (


SELECT id, manager_id, ARRAY[id]
FROM employees
WHERE manager_id IS NOT NULL
UNION ALL
SELECT [Link], e.manager_id, path || [Link]
FROM employees e
JOIN mgr_path mp ON e.manager_id = [Link]
WHERE NOT [Link] = ANY(path)
)
SELECT DISTINCT id
FROM mgr_path
WHERE id = ANY(path);

42. Write a query to get the running total of sales per customer, ordered by sale date.

SELECT customer_id, sale_date, amount,


SUM(amount) OVER (PARTITION BY customer_id ORDER BY sale_date) AS running_total
FROM sales;

43. Find the department-wise salary percentile (e.g., 90th percentile) using window functions.

SELECT department_id, salary,


PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY salary) OVER (PARTITION BY
department_id) AS pct_90_salary
FROM employees;

44. Find employees whose salary is a prime number.

WITH primes AS (
SELECT generate_series(2, (SELECT MAX(salary) FROM employees)) AS num
EXCEPT
SELECT num FROM (
SELECT num, UNNEST(ARRAY(
SELECT generate_series(2, FLOOR(SQRT(num))) AS divisor
)) AS divisor
WHERE num % divisor = 0
) AS composite
)
SELECT *
FROM employees
WHERE salary IN (SELECT num FROM primes);

Note: This is a conceptual approach—some databases may not support this exact syntax fully.
SQL Interview Questions & Solutions Page 10 of 21

45. Find employees who have worked for multiple departments over time.

SELECT employee_id
FROM employee_department_history
GROUP BY employee_id
HAVING COUNT(DISTINCT department_id) > 1;

46. Use window function to find the difference between current row’s sales and previous row’s sales
partitioned by product.

SELECT product_id, sale_date, amount,


amount - LAG(amount) OVER (PARTITION BY product_id ORDER BY sale_date) AS
sales_diff
FROM sales;

47. Write a query to find all employees who are at the lowest level in the hierarchy (no subordinates).

SELECT *
FROM employees e
WHERE NOT EXISTS (
SELECT 1 FROM employees sub WHERE sub.manager_id = [Link]
);

48. Find average order value per month and product category.

SELECT DATE_TRUNC('month', order_date) AS order_month, category_id, AVG(order_value) AS


avg_order_value
FROM orders
GROUP BY order_month, category_id;

49. Write a query to create a running count of how many employees joined in each year.

SELECT join_year, COUNT(*) AS yearly_hires,


SUM(COUNT(*)) OVER (ORDER BY join_year) AS running_total_hires
FROM (
SELECT EXTRACT(YEAR FROM hire_date) AS join_year
FROM employees
) sub
GROUP BY join_year
ORDER BY join_year;
SQL Interview Questions & Solutions Page 11 of 21

50. Write a query to find the second most recent order date per customer.

SELECT customer_id, order_date


FROM (
SELECT customer_id, order_date,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) AS rn
FROM orders
) sub
WHERE rn = 2;

51. Find employees who have never made a sale.

SELECT [Link], [Link]


FROM employees e
LEFT JOIN sales s ON [Link] = s.employee_id
WHERE s.sale_id IS NULL;

52. Find the average tenure of employees by department.

SELECT department_id, AVG(DATE_PART('year', CURRENT_DATE - hire_date)) AS avg_tenure_years


FROM employees
GROUP BY department_id;

53. Get employees with salary in the top 10% in their department.

SELECT *
FROM (
SELECT e.*, NTILE(10) OVER (PARTITION BY department_id ORDER BY salary DESC) AS decile
FROM employees e
) sub
WHERE decile = 1;

54. Find customers who purchased more than once in the same day.

SELECT customer_id, purchase_date, COUNT(*) AS purchase_count


FROM sales
GROUP BY customer_id, purchase_date
HAVING COUNT(*) > 1;

55. List all departments and their employee counts, including departments with zero employees.

SELECT d.department_id, d.department_name, COUNT([Link]) AS employee_count


FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
SQL Interview Questions & Solutions Page 12 of 21

56. Write a query to find duplicate rows based on multiple columns.

SELECT column1, column2, COUNT(*)


FROM table_name
GROUP BY column1, column2
HAVING COUNT(*) > 1;

57. Write a recursive query to calculate factorial of a number (e.g., 5).

WITH RECURSIVE factorial(n, fact) AS (


SELECT 1, 1
UNION ALL
SELECT n + 1, fact * (n + 1)
FROM factorial
WHERE n < 5
)
SELECT fact FROM factorial WHERE n = 5;

58. Write a query to calculate the cumulative percentage of total sales per product.

SELECT product_id, sale_amount,


SUM(sale_amount) OVER (ORDER BY sale_amount DESC) * 100.0 / SUM(sale_amount) OVER
() AS cumulative_pct
FROM sales;

59. Write a query to get employees who reported directly or indirectly to a given manager (hierarchy
traversal).

WITH RECURSIVE reporting AS (


SELECT id, name, manager_id
FROM employees
WHERE manager_id = 101 -- replace 101 with manager's id
UNION ALL
SELECT [Link], [Link], e.manager_id
FROM employees e
INNER JOIN reporting r ON e.manager_id = [Link]
)
SELECT * FROM reporting;

60. Find the average number of orders per customer and standard deviation.

SELECT AVG(order_count) AS avg_orders, STDDEV(order_count) AS stddev_orders


FROM (
SELECT customer_id, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
) sub;
SQL Interview Questions & Solutions Page 13 of 21

Advanced-Level SQL Questions

61. Find gaps in date sequences for each customer (missing days).

WITH dates AS (
SELECT customer_id, purchase_date,
LAG(purchase_date) OVER (PARTITION BY customer_id ORDER BY purchase_date) AS
prev_date
FROM sales
)
SELECT customer_id, prev_date + INTERVAL '1 day' AS missing_date
FROM dates
WHERE purchase_date > prev_date + INTERVAL '1 day';

62. Rank employees by salary within their department, and calculate percent rank.

SELECT name, department_id, salary,


RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS salary_rank,
PERCENT_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS
salary_percent_rank
FROM employees;

63. Find products that have never been sold.

SELECT p.product_id, p.product_name


FROM products p
LEFT JOIN sales s ON p.product_id = s.product_id
WHERE s.sale_id IS NULL;

64. Write a query to find consecutive days where sales were above a threshold.

WITH flagged_sales AS (
SELECT sale_date, amount,
CASE WHEN amount > 1000 THEN 1 ELSE 0 END AS flag
FROM sales
),
groups AS (
SELECT sale_date, amount, flag,
sale_date - INTERVAL ROW_NUMBER() OVER (ORDER BY sale_date) DAY AS grp
FROM flagged_sales
WHERE flag = 1
)
SELECT MIN(sale_date) AS start_date, MAX(sale_date) AS end_date, COUNT(*) AS
consecutive_days
FROM groups
GROUP BY grp
ORDER BY consecutive_days DESC;
SQL Interview Questions & Solutions Page 14 of 21

65. Write a query to concatenate employee names in each department (string aggregation).

SELECT department_id, STRING_AGG(name, ', ') AS employee_names


FROM employees
GROUP BY department_id;

66. Find employees whose salary is above the average salary of their department but below the
company-wide average.

SELECT *
FROM employees e
WHERE salary > (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id)
AND salary < (SELECT AVG(salary) FROM employees);

67. List the customers who purchased all products in a specific category.

SELECT customer_id
FROM sales
WHERE category_id = 10
GROUP BY customer_id
HAVING COUNT(DISTINCT product_id) = (
SELECT COUNT(DISTINCT product_id) FROM products WHERE category_id = 10
);

68. Retrieve the Nth highest salary from the employees table.

SELECT DISTINCT salary


FROM employees
ORDER BY salary DESC
LIMIT 1 OFFSET N-1;

69. Find employees with no corresponding entries in the salary_history table.

SELECT e.*
FROM employees e
LEFT JOIN salary_history sh ON [Link] = sh.employee_id
WHERE sh.employee_id IS NULL;

70. Show the department with the highest number of employees and the count.

SELECT department_id, COUNT(*) AS employee_count


FROM employees
GROUP BY department_id
ORDER BY employee_count DESC
LIMIT 1;
SQL Interview Questions & Solutions Page 15 of 21

71. Write a recursive query to list all ancestors (managers) of a given employee.

WITH RECURSIVE ancestors AS (


SELECT id, name, manager_id
FROM employees
WHERE id = 123
UNION ALL
SELECT [Link], [Link], e.manager_id
FROM employees e
JOIN ancestors a ON [Link] = a.manager_id
)
SELECT * FROM ancestors WHERE id != 123;

72. Calculate the median salary by department using window functions.

SELECT DISTINCT department_id,


PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) OVER (PARTITION BY
department_id) AS median_salary
FROM employees;

73. Find the first purchase date and last purchase date for each customer, including customers who
never purchased anything.

SELECT c.customer_id,
MIN(s.purchase_date) AS first_purchase,
MAX(s.purchase_date) AS last_purchase
FROM customers c
LEFT JOIN sales s ON c.customer_id = s.customer_id
GROUP BY c.customer_id;

74. Find the percentage difference between each month’s total sales and the previous month’s total
sales.

WITH monthly_sales AS (
SELECT DATE_TRUNC('month', sale_date) AS month, SUM(amount) AS total_sales
FROM sales
GROUP BY month
)
SELECT month, total_sales,
(total_sales - LAG(total_sales) OVER (ORDER BY month)) * 100.0 / LAG(total_sales)
OVER (ORDER BY month) AS pct_change
FROM monthly_sales;
SQL Interview Questions & Solutions Page 16 of 21

75. Write a query to find employees who have the longest tenure within their department.

WITH tenure AS (
SELECT *,
RANK() OVER (PARTITION BY department_id ORDER BY hire_date ASC) AS tenure_rank
FROM employees
)
SELECT *
FROM tenure
WHERE tenure_rank = 1;

76. Generate a report that shows sales and sales growth percentage compared to the same month
last year.

WITH monthly_sales AS (
SELECT DATE_TRUNC('month', sale_date) AS month, SUM(amount) AS total_sales
FROM sales
GROUP BY month
)
SELECT [Link], ms1.total_sales,
((ms1.total_sales - ms2.total_sales) * 100.0 / ms2.total_sales) AS growth_pct
FROM monthly_sales ms1
LEFT JOIN monthly_sales ms2 ON [Link] = [Link] + INTERVAL '1 year';

77. Write a query to identify overlapping shifts for employees.

SELECT s1.employee_id, s1.shift_id AS shift1, s2.shift_id AS shift2


FROM shifts s1
JOIN shifts s2 ON s1.employee_id = s2.employee_id AND s1.shift_id <> s2.shift_id
WHERE s1.start_time < s2.end_time AND s1.end_time > s2.start_time;

78. Calculate the total revenue for each customer, and rank them from highest to lowest spender.

SELECT customer_id, SUM(amount) AS total_revenue,


RANK() OVER (ORDER BY SUM(amount) DESC) AS revenue_rank
FROM sales
GROUP BY customer_id;

79. Write a query to find the employee(s) who have never received a promotion.

SELECT e.*
FROM employees e
LEFT JOIN promotions p ON [Link] = p.employee_id
WHERE p.employee_id IS NULL;
SQL Interview Questions & Solutions Page 17 of 21

80. Write a query to find the top 3 products with the highest total sales amount each month.

WITH monthly_product_sales AS (
SELECT product_id, DATE_TRUNC('month', sale_date) AS month, SUM(amount) AS total_sales
FROM sales
GROUP BY product_id, month
),
ranked_sales AS (
SELECT *, RANK() OVER (PARTITION BY month ORDER BY total_sales DESC) AS sales_rank
FROM monthly_product_sales
)
SELECT product_id, month, total_sales
FROM ranked_sales
WHERE sales_rank <= 3
ORDER BY month, sales_rank;

81. Find the customers who placed orders only in the last 30 days.

SELECT DISTINCT customer_id


FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days'
AND customer_id NOT IN (
SELECT DISTINCT customer_id
FROM orders
WHERE order_date < CURRENT_DATE - INTERVAL '30 days'
);

82. Find products that have never been ordered.

SELECT p.product_id, p.product_name


FROM products p
LEFT JOIN orders o ON p.product_id = o.product_id
WHERE o.order_id IS NULL;

83. Calculate the total sales amount and number of orders per customer in the last year.

SELECT customer_id, COUNT(*) AS total_orders, SUM(amount) AS total_sales


FROM sales
WHERE sale_date >= CURRENT_DATE - INTERVAL '1 year'
GROUP BY customer_id;

84. List the top 5 highest-paid employees per department.

SELECT *
FROM (
SELECT e.*, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
FROM employees e
) sub
WHERE rn <= 5;
SQL Interview Questions & Solutions Page 18 of 21

85. Write a query to identify “gaps and islands” in attendance records (consecutive dates present).

WITH attendance_groups AS (
SELECT employee_id, attendance_date,
attendance_date - INTERVAL ROW_NUMBER() OVER (PARTITION BY employee_id ORDER BY
attendance_date) DAY AS grp
FROM attendance
)
SELECT employee_id, MIN(attendance_date) AS start_date, MAX(attendance_date) AS end_date,
COUNT(*) AS consecutive_days
FROM attendance_groups
GROUP BY employee_id, grp
ORDER BY employee_id, start_date;

86. Write a recursive query to list all descendants of a manager in an organizational hierarchy.

WITH RECURSIVE descendants AS (


SELECT id, name, manager_id
FROM employees
WHERE manager_id = 100
UNION ALL
SELECT [Link], [Link], e.manager_id
FROM employees e
INNER JOIN descendants d ON e.manager_id = [Link]
)
SELECT * FROM descendants;

87. Calculate a 3-month moving average of monthly sales per product.

WITH monthly_sales AS (
SELECT product_id, DATE_TRUNC('month', sale_date) AS month, SUM(amount) AS total_sales
FROM sales
GROUP BY product_id, month
)
SELECT product_id, month, total_sales,
AVG(total_sales) OVER (PARTITION BY product_id ORDER BY month ROWS BETWEEN 2
PRECEDING AND CURRENT ROW) AS moving_avg
FROM monthly_sales;

88. Write a query to find employees who have the same hire date as their managers.

SELECT [Link] AS employee_name, [Link] AS manager_name, e.hire_date


FROM employees e
JOIN employees m ON e.manager_id = [Link]
WHERE e.hire_date = m.hire_date;
SQL Interview Questions & Solutions Page 19 of 21

89. Write a query to find products with increasing sales over the last 3 months.

WITH monthly_sales AS (
SELECT product_id, DATE_TRUNC('month', sale_date) AS month, SUM(amount) AS total_sales
FROM sales
GROUP BY product_id, month
),
ranked_sales AS (
SELECT product_id, month, total_sales,
ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY month DESC) AS rn
FROM monthly_sales
)
SELECT ms1.product_id
FROM ranked_sales ms1
JOIN ranked_sales ms2 ON ms1.product_id = ms2.product_id AND [Link] = 1 AND [Link] = 2
JOIN ranked_sales ms3 ON ms1.product_id = ms3.product_id AND [Link] = 3
WHERE ms3.total_sales < ms2.total_sales AND ms2.total_sales < ms1.total_sales;

90. Write a query to get the nth highest salary per department.

SELECT department_id, salary


FROM (
SELECT department_id, salary, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY
salary DESC) AS rn
FROM employees
) sub
WHERE rn = N;

91. Find employees who have managed more than 3 projects.

SELECT manager_id, COUNT(DISTINCT project_id) AS project_count


FROM projects
GROUP BY manager_id
HAVING COUNT(DISTINCT project_id) > 3;

92. Write a query to calculate the difference in days between each employee's hire date and their
manager’s hire date.

SELECT [Link] AS employee, [Link] AS manager,


DATEDIFF(day, m.hire_date, e.hire_date) AS days_difference
FROM employees e
JOIN employees m ON e.manager_id = [Link];
SQL Interview Questions & Solutions Page 20 of 21

93. Write a query to find the department with the highest average years of experience.

SELECT department_id, AVG(EXTRACT(year FROM CURRENT_DATE - hire_date)) AS


avg_experience_years
FROM employees
GROUP BY department_id
ORDER BY avg_experience_years DESC
LIMIT 1;

94. Identify employees who had overlapping project assignments.

SELECT p1.employee_id, p1.project_id AS project1, p2.project_id AS project2


FROM project_assignments p1
JOIN project_assignments p2 ON p1.employee_id = p2.employee_id AND p1.project_id <>
p2.project_id
WHERE p1.start_date < p2.end_date AND p1.end_date > p2.start_date;

95. Find customers who made purchases in every month of the current year.

WITH customer_months AS (
SELECT customer_id, EXTRACT(MONTH FROM purchase_date) AS month
FROM sales
WHERE EXTRACT(YEAR FROM purchase_date) = EXTRACT(YEAR FROM CURRENT_DATE)
GROUP BY customer_id, EXTRACT(MONTH FROM purchase_date)
)
SELECT customer_id
FROM customer_months
GROUP BY customer_id
HAVING COUNT(DISTINCT month) = 12;

96. List employees who earn more than all their subordinates.

SELECT [Link], [Link], [Link]


FROM employees e
WHERE [Link] > ALL (
SELECT salary FROM employees sub WHERE sub.manager_id = [Link]
);

97. Get the product with the highest sales for each category.

WITH category_sales AS (
SELECT category_id, product_id, SUM(amount) AS total_sales,
RANK() OVER (PARTITION BY category_id ORDER BY SUM(amount) DESC) AS sales_rank
FROM sales
GROUP BY category_id, product_id
)
SELECT category_id, product_id, total_sales
FROM category_sales
WHERE sales_rank = 1;
SQL Interview Questions & Solutions Page 21 of 21

98. Find customers who haven’t ordered in the last 6 months.

SELECT customer_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id
HAVING MAX(o.order_date) < CURRENT_DATE - INTERVAL '6 months' OR MAX(o.order_date) IS
NULL;

99. Find the maximum salary gap between any two employees within the same department.

SELECT department_id, MAX(salary) - MIN(salary) AS salary_gap


FROM employees
GROUP BY department_id;

100. Write a recursive query to compute the total budget under each manager (including
subordinates).

WITH RECURSIVE manager_budget AS (


SELECT id, manager_id, budget
FROM departments
UNION ALL
SELECT [Link], d.manager_id, [Link]
FROM departments d
JOIN manager_budget mb ON d.manager_id = [Link]
)
SELECT manager_id, SUM(budget) AS total_budget
FROM manager_budget
GROUP BY manager_id;

You might also like