Last Updated on: 25th March 2026, 08:21 pm
If you are learning SQL and still feel confused solving questions, then honestly you are not alone. Most people read theory, but when real query comes… mind just goes blank little bit.
Why Practicing SQL Questions is Important
SQL is not something you “memorize”. It’s something you practice, mess up, fix, repeat again. If you only read SELECT, WHERE, JOIN — you think you understand… but when question comes, confusion start happens. So best way is solving questions.
Database Setup (Used in All Questions)
Students(id, name, marks, city, dept_id)Departments(id, dept_name)Employees(id, name, salary, dept_id)SECTION 1: Basic SQL Questions (1–25)
Start simple. Build confidence first. These questions cover SELECT, WHERE, ORDER BY, basic functions and filters.
SELECT * FROM Students;
* means “all columns”. This returns every row and column from the Students table. Perfect for initial data inspection.SELECT name FROM Students;
name column. Useful when you need specific attributes.SELECT * FROM Students WHERE marks > 80;
>, <, =, >=, <=.SELECT * FROM Students WHERE city = 'Lahore';
SELECT * FROM Students WHERE marks BETWEEN 60 AND 90;
marks >= 60 AND marks <= 90. Great for range filters.SELECT * FROM Students WHERE name LIKE 'A%';
% matches any sequence of characters. 'A%' finds names beginning with ‘A’. Case‑sensitive depends on database collation.SELECT * FROM Students WHERE name LIKE '%n';
'%n' → any characters before the final letter ‘n’.SELECT * FROM Students ORDER BY marks;
ASC explicitly if needed.SELECT * FROM Students ORDER BY marks DESC;
DESC keyword reverses order → highest marks first.SELECT COUNT(*) FROM Students;
COUNT(*) returns the total number of rows in the table.SELECT MAX(marks) FROM Students;
MAX() returns the highest value in the column.SELECT MIN(marks) FROM Students;
MIN() returns the lowest value.SELECT AVG(marks) FROM Students;
AVG() calculates arithmetic mean (ignores NULLs).SELECT SUM(marks) FROM Students;
SUM() adds all numeric values in the column.SELECT DISTINCT city FROM Students;
SELECT * FROM Students WHERE city != 'Karachi';
!= (or <>) means “not equal”. Excludes a specific city.SELECT * FROM Students WHERE dept_id IS NULL;
IS NULL (not = NULL). NULL means missing/unknown value.SELECT * FROM Students WHERE dept_id IS NOT NULL;
IS NOT NULL keeps rows where department is assigned.SELECT * FROM Students WHERE marks >= 90;
>= includes the boundary value.SELECT * FROM Students WHERE marks != 50;
SELECT * FROM Students LIMIT 5;
LIMIT restricts output rows (MySQL/PostgreSQL). In SQL Server use TOP 5.SELECT * FROM Students ORDER BY name;
SELECT COUNT(DISTINCT city) FROM Students;
COUNT(DISTINCT column) counts unique non‑NULL values.SELECT * FROM Students WHERE marks < 40;
SELECT * FROM Students WHERE marks IN (50,60,70);
OR conditions.SECTION 2: Intermediate SQL Questions (26–60)
Now things start getting little tricky… but don't worry. GROUP BY, HAVING, subqueries, string functions.
SELECT * FROM Students WHERE marks > 70 AND city='Lahore';
SELECT * FROM Students WHERE marks > 70 OR city='Karachi';
SELECT city, COUNT(*) FROM Students GROUP BY city;
COUNT(*) counts each group.SELECT city, AVG(marks) FROM Students GROUP BY city;
SELECT city, AVG(marks) FROM Students GROUP BY city HAVING AVG(marks) > 70;
SELECT city, COUNT(*) FROM Students GROUP BY city HAVING COUNT(*) > 1;
SELECT MAX(marks) FROM Students WHERE marks < (SELECT MAX(marks) FROM Students);
SELECT * FROM Students WHERE marks > (SELECT AVG(marks) FROM Students);
SELECT * FROM Students WHERE marks < (SELECT AVG(marks) FROM Students);
SELECT UPPER(name) FROM Students;
UPPER() converts text to all caps.SELECT LOWER(name) FROM Students;
LOWER() converts to lowercase (useful for case‑insensitive comparisons).SELECT CONCAT(name,' - ',city) FROM Students;
CONCAT() joins strings; creates a formatted label like "Ali - Lahore".SELECT * FROM Students WHERE LENGTH(name) > 5;
LENGTH() returns number of characters; filter on that.SELECT REPLACE(city,'Lahore','LHR') FROM Students;
REPLACE() substitutes substrings (does not modify original data).SELECT SUBSTRING(name,1,3) FROM Students;
SUBSTRING(name, start, length) extracts prefix (e.g., "Ali" → "Ali", "Ahmed" → "Ahm").SELECT * FROM Students WHERE marks % 5 = 0;
% gives remainder. Remainder zero → divisible by 5.SELECT * FROM Students ORDER BY marks DESC LIMIT 3;
SELECT name FROM Students ORDER BY LENGTH(name) DESC LIMIT 1;
SELECT * FROM Students WHERE city <> 'Lahore';
<> is the standard SQL not‑equal operator (same as !=).SELECT city, COUNT(*) FROM Students GROUP BY city HAVING COUNT(*) > 2;
SELECT dept_id, COUNT(*) FROM Students GROUP BY dept_id;
SELECT * FROM Students ORDER BY city, marks DESC;
SELECT * FROM Students WHERE marks > 60 AND city != 'Karachi';
SELECT * FROM Students WHERE name LIKE '%a%';
SELECT COUNT(*) FROM Students WHERE marks > 60;
SELECT city, MAX(marks) FROM Students GROUP BY city;
SELECT city, MIN(marks) FROM Students GROUP BY city;
SELECT dept_id, AVG(marks) FROM Students GROUP BY dept_id;
SELECT * FROM Students WHERE marks = (SELECT MAX(marks) FROM Students);
SELECT * FROM Students WHERE marks = (SELECT MIN(marks) FROM Students);
SELECT name FROM Students ORDER BY LENGTH(name);
SELECT DISTINCT dept_id FROM Students;
SELECT * FROM Students WHERE marks BETWEEN 40 AND 60;
SELECT * FROM Students WHERE name LIKE '_a%';
_ matches exactly one character, then 'a', then anything.SELECT * FROM Students ORDER BY marks DESC, name ASC;
SECTION 3: JOIN Queries (61–90)
Joins = most important topic (and most confusing also sometimes). These combine data from multiple tables.
SELECT s.name, d.dept_name FROM Students s INNER JOIN Departments d ON s.dept_id = d.id;
s and d make query shorter.SELECT s.name, d.dept_name FROM Students s LEFT JOIN Departments d ON s.dept_id = d.id;
SELECT s.name FROM Students s LEFT JOIN Departments d ON s.dept_id = d.id WHERE d.id IS NULL;
SELECT d.dept_name, COUNT(*) FROM Students s JOIN Departments d ON s.dept_id = d.id GROUP BY d.dept_name;
SELECT e.name, d.dept_name FROM Employees e JOIN Departments d ON e.dept_id = d.id;
SELECT dept_id, MAX(salary) FROM Employees GROUP BY dept_id;
SELECT dept_id, AVG(salary) FROM Employees GROUP BY dept_id;
SELECT * FROM Employees WHERE salary > (SELECT AVG(salary) FROM Employees);
SELECT dept_id, COUNT(*) FROM Employees GROUP BY dept_id ORDER BY COUNT(*) DESC LIMIT 1;
SELECT * FROM Employees WHERE dept_id IS NULL;
SELECT d.dept_name FROM Departments d LEFT JOIN Employees e ON d.id=e.dept_id WHERE e.id IS NULL;
SELECT name, salary FROM Employees ORDER BY salary DESC;
SELECT dept_id, COUNT(*) FROM Employees GROUP BY dept_id HAVING COUNT(*) > 2;
SELECT e.name, d.dept_name FROM Employees e JOIN Departments d ON e.dept_id = d.id;
SELECT s.name, e.name FROM Students s JOIN Employees e ON s.dept_id = e.dept_id;
SELECT DISTINCT dept_id FROM Employees;
SELECT * FROM Employees ORDER BY dept_id;
SELECT COUNT(*) FROM Employees;
SELECT AVG(salary) FROM Employees;
SELECT MAX(salary) FROM Employees;
SELECT MIN(salary) FROM Employees;
SELECT * FROM Employees WHERE salary BETWEEN 20000 AND 50000;
SELECT * FROM Employees WHERE name LIKE 'S%';
SELECT * FROM Employees WHERE salary > 30000;
SELECT dept_id, SUM(salary) FROM Employees GROUP BY dept_id;
SELECT name FROM Employees ORDER BY name;
SELECT * FROM Employees LIMIT 10;
SELECT * FROM Employees WHERE dept_id IN (1,2);
SELECT * FROM Employees WHERE dept_id NOT IN (1,2);
SELECT COUNT(DISTINCT dept_id) FROM Employees;
SECTION 4: Advanced SQL Queries (91–110)
Now real interview level things start… window functions, ranking, complex subqueries, duplicates removal.
SELECT MAX(salary) FROM Employees WHERE salary < (SELECT MAX(salary) FROM Employees);
SELECT DISTINCT salary FROM Employees ORDER BY salary DESC LIMIT 1 OFFSET 2;
OFFSET 2 skips first two distinct salary values → third highest.SELECT name, salary, RANK() OVER (ORDER BY salary DESC) FROM Employees;
SELECT name, salary, DENSE_RANK() OVER (ORDER BY salary DESC) FROM Employees;
SELECT name, ROW_NUMBER() OVER () FROM Employees;
SELECT salary, SUM(salary) OVER (ORDER BY id) FROM Employees;
SELECT salary, COUNT(*) FROM Employees GROUP BY salary HAVING COUNT(*) > 1;
SELECT * FROM (SELECT e.*, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) rn FROM Employees e) t WHERE rn <= 3;
PARTITION BY resets ranking per department, outer filter keeps top 3.DELETE FROM Students WHERE id NOT IN (SELECT MIN(id) FROM Students GROUP BY name, city);
SELECT a.name, b.name, a.salary FROM Employees a JOIN Employees b ON a.salary = b.salary AND a.id != b.id;
WITH RECURSIVE nums(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM nums WHERE n<10) SELECT * FROM nums;
SELECT city, SUM(CASE WHEN marks>=80 THEN 1 ELSE 0 END) as high_scorers FROM Students GROUP BY city;
SELECT name, salary, LAG(salary) OVER (ORDER BY id) FROM Employees;
SELECT name, salary, LEAD(salary) OVER (ORDER BY id) FROM Employees;
SELECT salary, AVG(salary) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM Employees;
How to Solve Any SQL Question (Real Trick)
- 1️⃣ What data needed? (columns)
- 2️⃣ From which table(s)? (JOINs)
- 3️⃣ Conditions? (WHERE / HAVING)
- 4️⃣ Grouping? (GROUP BY)
- 5️⃣ Sorting / limit? (ORDER BY / LIMIT)
Break it… then solve.
Common Mistakes (Everyone Does 😅)
- Forget GROUP BY with aggregations
- Wrong JOIN condition (cartesian product)
- Mixing WHERE and HAVING
- Missing NULL handling (
IS NULLvs= NULL)
FAQs (Most Asked SQL Questions)
Final Thoughts
SQL is not about syntax… it is about thinking clearly. At start you struggle… then suddenly everything starts making sense. Just keep practicing… even if query is wrong, its okay. That is how real learning happens.
