Skip to content

Top 50 Most Asked SQL Interview Questions

The questions that appear most often across company-wise sets — master these first.

Why start here

We count how often each question appears across the 20 company-wise SQL practice sets on this site and show the 50 most common. They are the safest questions to master first.

Solved — top 50Start practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is the difference between SUM with CASE and filtering with WHERE?

Aggregation and GroupingIn 8 company setsMedium
Save to ▾
Show answer
WHERE removes rows from the entire query, so all aggregates see only filtered data. SUM(CASE WHEN condition THEN amount END) applies the condition to one aggregate only, letting you calculate several conditional totals in one pass, such as paid and refunded amounts per customer. Some databases support the cleaner FILTER clause: SUM(amount) FILTER (WHERE status = 'Paid').
02

A query with a correlated subquery in SELECT runs for every row and is slow. How do you improve it?

Subqueries and CTEsIn 8 company setsMedium
Save to ▾
Show answer
Rewrite the correlated scalar subquery as a join to a pre-aggregated derived table or CTE, for example aggregate order counts per customer once and LEFT JOIN it. Alternatively use a window function. Ensure the correlation column is indexed if you keep the subquery. Compare execution plans and timing before and after to confirm the improvement.
03

What is the difference between OLTP and OLAP databases?

Database DesignIn 8 company setsMedium
Save to ▾
Show answer
OLTP systems handle many short transactions such as orders and payments, with normalised schemas, row-based storage and focus on fast inserts and updates. OLAP systems support analysis over large history, using denormalised star or snowflake schemas, columnar storage and heavy aggregations. A bank's core system is OLTP, while its data warehouse used for monthly reports is OLAP.
04

How do you get the top 3 rows in different databases?

SQL BasicsIn 7 company setsMedium
Save to ▾
Show answer
MySQL and PostgreSQL: SELECT * FROM products ORDER BY price DESC LIMIT 3; SQL Server: SELECT TOP 3 * FROM products ORDER BY price DESC; Standard SQL: SELECT * FROM products ORDER BY price DESC FETCH FIRST 3 ROWS ONLY; Always use ORDER BY, otherwise the top rows are not guaranteed.
05

Match each employee's salary to a grade using a range table.

JoinsIn 7 company setsMedium
Save to ▾
Show answer
SELECT e.name, e.salary, g.grade FROM employees e JOIN salary_grades g ON e.salary BETWEEN g.min_salary AND g.max_salary; This is a non-equi join. Ensure grade ranges do not overlap, otherwise an employee matches more than one grade and appears twice.
06

Rewrite a nested query using CTEs for readability.

Subqueries and CTEsIn 7 company setsMedium
Save to ▾
Show answer
WITH order_totals AS ( SELECT customer_id, SUM(amount) AS total FROM orders GROUP BY customer_id ), ranked AS ( SELECT customer_id, total, NTILE(10) OVER (ORDER BY total DESC) AS decile FROM order_totals ) SELECT * FROM ranked WHERE decile = 1; Each CTE is a named step, making top 10 percent customer logic easy to read.
07

Find departments where every employee earns above 40000.

Subqueries and CTEsIn 7 company setsMedium
Save to ▾
Show answer
SELECT d.department_id, d.name FROM departments d WHERE NOT EXISTS ( SELECT 1 FROM employees e WHERE e.department_id = d.department_id AND e.salary <= 40000 ) AND EXISTS ( SELECT 1 FROM employees e WHERE e.department_id = d.department_id ); Double negation expresses for all; the EXISTS excludes empty departments.
08

Your running total jumps by large amounts on some dates instead of row by row. Why?

Window FunctionsIn 7 company setsMedium
Save to ▾
Show answer
With ORDER BY and no explicit frame, the default frame is RANGE UNBOUNDED PRECEDING, which treats all rows with the same order value as peers and includes them together. When several rows share the same date, the running total adds them all at once. Specify ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, or add a unique tiebreaker to ORDER BY.
09

What are referential actions such as ON DELETE CASCADE?

Database DesignIn 7 company setsMedium
Save to ▾
Show answer
Referential actions define what happens to child rows when a parent row is deleted or updated. CASCADE deletes or updates children automatically, SET NULL sets the foreign key to NULL, SET DEFAULT uses the default value, and RESTRICT or NO ACTION blocks the change. CASCADE is convenient for dependent data like order items but risky on important data, because one delete can remove many rows.
10

Add a foreign key and a check constraint to an existing table.

Database DesignIn 7 company setsMedium
Save to ▾
Show answer
ALTER TABLE orders ADD CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(customer_id); ALTER TABLE orders ADD CONSTRAINT chk_amount_positive CHECK (amount > 0); First clean existing rows that violate the rule, otherwise the ALTER fails. Naming constraints makes errors easier to read.
11

A table stores phone numbers as 'ph1, ph2, ph3' in one column. What is wrong and how do you fix it?

Database DesignIn 7 company setsMedium
Save to ▾
Show answer
The column violates first normal form because it stores multiple values in one field, making search, validation and updates difficult. Create a separate customer_phones table with customer_id, phone and type columns, one row per number, with a foreign key to customers. Migrate data by splitting the strings, then drop the old column after applications are updated.
12

A COUNT(DISTINCT) query on a huge events table is very slow. What options do you have?

Aggregation and GroupingIn 7 company setsMedium
Save to ▾
Show answer
Exact distinct counts need sorting or hashing all values, which is expensive. Options are filtering the date range tightly, pre-aggregating daily distinct users into a summary table, indexing the columns involved, or using approximate functions such as APPROX_COUNT_DISTINCT or HyperLogLog where small error is acceptable. Explain the accuracy trade-off to stakeholders before switching to approximations.
13

A search on name LIKE '%sharma%' is very slow on a 20 million row table. What can you do?

SQL BasicsIn 6 company setsMedium
Save to ▾
Show answer
A leading wildcard cannot use a normal B-tree index, so the database scans the table. Options are full-text indexing, trigram indexes in PostgreSQL, a reversed or computed column if the pattern is a suffix, or a search engine for heavy text search. Also limit the result, filter on other indexed columns first, and check whether users really need contains search.
14

A LEFT JOIN is returning fewer rows than the left table. Why could that happen?

JoinsIn 6 company setsMedium
Save to ▾
Show answer
A LEFT JOIN never removes left rows by itself, so a WHERE condition on the right table is likely filtering out rows where it is NULL. For example WHERE o.status = 'Paid' drops customers without orders. Move the condition into the ON clause or add OR o.status IS NULL. Another cause is a later INNER JOIN in the chain that removes rows.
15

What is the difference between an index scan and an index seek?

Indexes and PerformanceIn 6 company setsMedium
Save to ▾
Show answer
An index seek navigates the B-tree directly to the matching keys, reading only the needed rows, which is efficient for selective filters. An index scan reads the whole index or a large range of it. A table scan reads every row. Scans are not always bad; for queries returning a large share of rows, a scan can be cheaper than many seeks.
16

What are transaction isolation levels?

Transactions and Advanced SQLIn 6 company setsMedium
Save to ▾
Show answer
Isolation levels balance consistency and concurrency. Read Uncommitted allows dirty reads. Read Committed, the default in PostgreSQL and SQL Server, prevents dirty reads but allows non-repeatable reads. Repeatable Read, the default in MySQL InnoDB, prevents non-repeatable reads, and InnoDB also prevents most phantoms with gap locks. Serializable prevents all anomalies but reduces concurrency. Choose based on business correctness needs.
17

What is a deadlock and how do databases handle it?

Transactions and Advanced SQLIn 6 company setsMedium
Save to ▾
Show answer
A deadlock occurs when two transactions each hold a lock the other needs, so both wait forever. For example, T1 locks account A and wants B, while T2 locks B and wants A. The database detects the cycle and kills one transaction as the victim, rolling it back with an error. Applications should retry the victim and access resources in a consistent order.
18

You need to update 50 million rows in production. How do you do it safely?

Transactions and Advanced SQLIn 6 company setsMedium
Save to ▾
Show answer
Avoid one huge transaction that locks the table and fills the log. Test on a copy first, take a backup, and update in batches of a few thousand rows using a key range, committing each batch and pausing briefly to reduce load. Run during low traffic, monitor replication lag and locks, keep a rollback script, and verify counts after completion.
19

What are DDL, DML, DCL and TCL commands?

SQL BasicsIn 5 company setsEasy
Save to ▾
Show answer
DDL (Data Definition Language) defines structure: CREATE, ALTER, DROP, TRUNCATE. DML (Data Manipulation Language) changes data: INSERT, UPDATE, DELETE, and SELECT is often grouped here or as DQL. DCL (Data Control Language) manages access: GRANT and REVOKE. TCL (Transaction Control Language) manages transactions: COMMIT, ROLLBACK and SAVEPOINT. Knowing the categories helps explain behaviour such as auto-commit of DDL in some databases.
20

Someone ran an UPDATE without WHERE on production. What would you do?

SQL BasicsIn 5 company setsMedium
Save to ▾
Show answer
Stop further changes and inform the lead and DBA immediately. If the session is still in an open transaction, roll back. Otherwise, restore affected rows from the latest backup or point-in-time recovery to a separate database and update the production table from it, or use audit or history tables if available. Afterwards, add safeguards such as safe-update mode, reviews and restricted write access.
21

What is the difference between INNER JOIN and LEFT JOIN?

JoinsIn 5 company setsEasy
Save to ▾
Show answer
INNER JOIN keeps only rows where the join condition matches in both tables. LEFT JOIN keeps every row from the left table and fills columns from the right with NULL when there is no match. For customers and orders, INNER JOIN shows only customers who ordered, while LEFT JOIN shows all customers, including those with no orders, which is useful for finding inactive customers.
22

What are equi joins, non-equi joins and natural joins?

JoinsIn 5 company setsMedium
Save to ▾
Show answer
An equi join uses equality in the condition, such as a.id = b.id, the most common case. A non-equi join uses other operators like BETWEEN or greater than, for example matching salary to a grade range table. A natural join automatically joins on columns with the same names, which is risky because adding a column can silently change results, so explicit ON is preferred.
23

Join three tables to get total sales by product category.

JoinsIn 5 company setsMedium
Save to ▾
Show answer
SELECT cat.category_name, SUM(oi.quantity * oi.unit_price) AS revenue FROM order_items oi JOIN products p ON oi.product_id = p.product_id JOIN categories cat ON p.category_id = cat.category_id GROUP BY cat.category_name ORDER BY revenue DESC; Join from the most detailed table outward and aggregate at the end.
24

What is a subquery and where can it be used?

Subqueries and CTEsIn 5 company setsEasy
Save to ▾
Show answer
A subquery is a query nested inside another statement. It can appear in WHERE, such as salary > (SELECT AVG(salary) FROM employees), in FROM as a derived table, in SELECT as a scalar value, and in HAVING. It can return a single value, a list for IN, or a table. Subqueries break complex logic into smaller steps.
25

What is the difference between a correlated and a non-correlated subquery?

Subqueries and CTEsIn 5 company setsEasy
Save to ▾
Show answer
A non-correlated subquery runs independently and returns a result once, such as the overall average salary. A correlated subquery references columns from the outer query and logically runs for each outer row, such as comparing each employee's salary with the average of their own department. Correlated subqueries are powerful but may be slow without good indexes, although optimisers often rewrite them as joins.
26

An interviewer asks for the Nth highest salary in a reusable way. How do you answer?

Subqueries and CTEsIn 5 company setsMedium
Save to ▾
Show answer
Use DENSE_RANK so ties share a rank: SELECT salary FROM (SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS r FROM employees) t WHERE r = :n. Alternatively use ORDER BY salary DESC with OFFSET n-1 ROWS FETCH NEXT 1 ROW ONLY on distinct salaries. Mention how ties are handled and that per-department versions add PARTITION BY department_id.
27

What is the difference between ROWS and RANGE frames?

Window FunctionsIn 5 company setsMedium
Save to ▾
Show answer
ROWS counts physical rows, so 2 PRECEDING means exactly two rows before. RANGE works on values of the ORDER BY column, so rows with the same value are treated together, and value ranges like INTERVAL '7 days' PRECEDING are possible in some databases. With duplicate dates, a RANGE running total jumps for all ties at once, while ROWS increases row by row.
28

Calculate a 7-day moving average of daily active users.

Window FunctionsIn 5 company setsMedium
Save to ▾
Show answer
SELECT activity_date, dau, ROUND(AVG(dau) OVER ( ORDER BY activity_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ), 1) AS dau_7d_avg FROM daily_users ORDER BY activity_date; This assumes one row per day; fill missing dates with a calendar table first, or ROWS will span more than seven days.
29

An interviewer asks to show each employee's salary next to their department's average. How do you do it?

Window FunctionsIn 5 company setsMedium
Save to ▾
Show answer
Use a window aggregate: SELECT name, department_id, salary, AVG(salary) OVER (PARTITION BY department_id) AS dept_avg, salary - AVG(salary) OVER (PARTITION BY department_id) AS diff FROM employees. Unlike GROUP BY, every employee row is kept. Mention that a join with a grouped subquery produces the same result but is longer.
30

Assign each customer to a spending quartile.

Window FunctionsIn 5 company setsMedium
Save to ▾
Show answer
WITH spend AS ( SELECT customer_id, SUM(amount) AS total FROM orders GROUP BY customer_id ) SELECT customer_id, total, NTILE(4) OVER (ORDER BY total DESC) AS quartile FROM spend; Quartile 1 contains the highest spenders. Use this for targeted offers or loyalty tiers.
31

Explain 1NF, 2NF and 3NF with simple examples.

Database DesignIn 5 company setsEasy
Save to ▾
Show answer
1NF: each column holds atomic values and there are no repeating groups, so no comma-separated phone numbers. 2NF: in 1NF and every non-key column depends on the whole composite key, so product name should not sit in an order_items table keyed by order and product. 3NF: in 2NF with no transitive dependency, so city should not determine state inside the employees table.
32

What is denormalisation and when is it used?

Database DesignIn 5 company setsMedium
Save to ▾
Show answer
Denormalisation intentionally adds redundancy, such as storing customer name in an orders reporting table, to reduce joins and speed up reads. It is common in data warehouses, reporting tables and high-read applications. The cost is extra storage and the need to keep copies consistent through ETL, triggers or application logic. Use it when read performance matters more than write simplicity.
33

Your team debates using UUIDs or auto-increment integers as primary keys. What do you advise?

Database DesignIn 5 company setsHard
Save to ▾
Show answer
Auto-increment integers are compact, fast to index and naturally ordered, but expose counts and are hard to generate across distributed systems. UUIDs are globally unique and good for distributed inserts and merging data, but larger and random, causing index fragmentation. Time-ordered UUIDs such as UUIDv7 reduce fragmentation. Choose based on scale, distribution and security needs.
34

A reporting team wants to query the production OLTP database directly. What are the risks and alternatives?

Database DesignIn 5 company setsMedium
Save to ▾
Show answer
Heavy analytical queries can lock rows, use CPU and slow customer transactions, and normalised schemas make reporting complex. Alternatives are a read replica for reporting, a data warehouse loaded by ETL or CDC with a star schema, or materialised summary tables. Grant read-only access with limits if direct access is unavoidable, and schedule heavy jobs off-peak.
35

What is an index in a database?

Indexes and PerformanceIn 5 company setsEasy
Save to ▾
Show answer
An index is a separate data structure, usually a B-tree, that stores column values in sorted order with pointers to rows, so the database can find matching rows without scanning the whole table, like a book index. Indexes speed up WHERE, JOIN, ORDER BY and GROUP BY, but use storage and slow down inserts, updates and deletes because the index must be maintained.
36

What is a SARGable query and why does it matter?

Indexes and PerformanceIn 5 company setsMedium
Save to ▾
Show answer
A SARGable (Search ARGument able) predicate lets the optimiser use an index seek. Wrapping an indexed column in a function, such as WHERE YEAR(order_date) = 2025 or WHERE LOWER(email) = 'x', usually prevents index use. Rewrite as WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01'. Leading wildcards and implicit type conversions also make predicates non-SARGable.
37

A query uses SELECT * on a table with 80 columns. Why is that a problem?

Indexes and PerformanceIn 5 company setsMedium
Save to ▾
Show answer
SELECT * fetches every column, increasing disk reads, memory, network transfer and application processing. It prevents covering indexes from being used and can break applications when columns are added or reordered. Select only required columns, which lets the optimiser use narrower indexes and makes the intent clear. SELECT * is acceptable only for quick exploration, not production code.
38

How do you prevent SQL injection in applications?

Transactions and Advanced SQLIn 5 company setsMedium
Save to ▾
Show answer
Never build SQL by concatenating user input. Use parameterised queries or prepared statements, where input is sent separately from the SQL text, or ORMs that do this automatically. Validate and whitelist inputs such as sort column names, give application users least privilege, and avoid dynamic SQL in procedures unless parameters are bound. Input like ' OR 1=1 -- then cannot change the query logic.
39

What is the difference between DELETE, TRUNCATE and DROP?

SQL BasicsIn 4 company setsEasy
Save to ▾
Show answer
DELETE removes selected rows using a WHERE clause, is logged row by row, fires triggers and can be rolled back inside a transaction. TRUNCATE removes all rows quickly by deallocating pages, usually resets identity values and cannot use WHERE. DROP removes the whole table including structure, indexes and permissions. Use DELETE for selective removal, TRUNCATE to empty staging tables and DROP to remove objects.
40

Tell me about a time you automated a manual data task with SQL.

SQL BasicsIn 4 company setsMedium
Save to ▾
Show answer
Situation: the operations team spent four hours every Monday merging Excel files for a weekly report. Task: reduce the effort. Action: I loaded the files into staging tables, wrote SQL with joins and aggregations to produce the report, and scheduled it as a job. Result: the report was ready automatically at 8 AM, saving about 16 hours a month and removing copy-paste errors.
41

What is a self join? Give an example.

JoinsIn 4 company setsEasy
Save to ▾
Show answer
A self join joins a table to itself using aliases, used for hierarchical or comparative data in one table. Example: SELECT e.name AS employee, m.name AS manager FROM employees e LEFT JOIN employees m ON e.manager_id = m.emp_id. Each employee row is matched with the row of its manager. LEFT JOIN keeps the top manager whose manager_id is NULL.
42

What is the difference between a join and a union?

JoinsIn 4 company setsMedium
Save to ▾
Show answer
A join combines columns from different tables side by side based on a matching condition, making rows wider. A union stacks results of queries with the same column structure vertically, making the result longer. Use a join to bring customer names next to orders, and a union to combine 2024 and 2025 order tables into one list.
43

What is the difference between putting a condition in ON versus WHERE in a LEFT JOIN?

JoinsIn 4 company setsMedium
Save to ▾
Show answer
In a LEFT JOIN, a condition in ON filters the right table before matching, so all left rows are still kept. A condition on the right table in WHERE runs after the join and removes rows where the right side is NULL, effectively turning it into an inner join. To get all customers with only their 2025 orders, put the date condition in ON.
44

Show all dates in a month with sales, including days with zero sales.

JoinsIn 4 company setsHard
Save to ▾
Show answer
WITH days AS ( SELECT generate_series(DATE '2025-01-01', DATE '2025-01-31', INTERVAL '1 day')::date AS d ) SELECT d.d, COALESCE(SUM(s.amount), 0) AS sales FROM days d LEFT JOIN sales s ON s.sale_date = d.d GROUP BY d.d ORDER BY d.d; This PostgreSQL example uses a date series; other databases use a calendar table.
45

What are ROLLUP, CUBE and GROUPING SETS?

Aggregation and GroupingIn 4 company setsMedium
Save to ▾
Show answer
They produce multiple grouping levels in one query. ROLLUP(region, city) gives city totals, region subtotals and a grand total. CUBE(region, product) gives all combinations of subtotals. GROUPING SETS lets you list exact combinations, such as (region), (product) and (). The GROUPING function identifies subtotal rows, which is useful for labelling them in reports.
46

Find cities with more than 100 customers.

Aggregation and GroupingIn 4 company setsEasy
Save to ▾
Show answer
SELECT city, COUNT(*) AS customers FROM customers GROUP BY city HAVING COUNT(*) > 100 ORDER BY customers DESC; HAVING is needed because the condition uses an aggregate. A WHERE clause could still filter rows first, for example only active customers.
47

Calculate the median salary per department.

Aggregation and GroupingIn 4 company setsHard
Save to ▾
Show answer
PostgreSQL and standard SQL: SELECT department_id, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) AS median_salary FROM employees GROUP BY department_id; SQL Server uses PERCENTILE_CONT as a window function with OVER (PARTITION BY department_id). Median resists outliers better than average for salary analysis.
48

Average order value looks too low in a report. What could be wrong?

Aggregation and GroupingIn 4 company setsMedium
Save to ▾
Show answer
Check the grain: if the query averages order items instead of orders, each line counts separately and the average drops. Joins can also duplicate rows. Verify whether cancelled or zero-value orders are included and how NULL amounts are treated. Compute SUM(amount) / COUNT(DISTINCT order_id) at order level and compare with business definitions before changing the report.
49

Management wants the percentage of each category in total sales. How do you write it?

Aggregation and GroupingIn 4 company setsMedium
Save to ▾
Show answer
Use a window aggregate over the grouped result: SELECT category, SUM(sales) AS sales, ROUND(100.0 * SUM(sales) / SUM(SUM(sales)) OVER (), 2) AS pct FROM sales GROUP BY category. The inner SUM is per category and the outer SUM over an empty window gives the grand total. Multiplying by 100.0 avoids integer division in some databases.
50

What is the difference between MIN/MAX on numbers and on strings or dates?

Aggregation and GroupingIn 4 company setsEasy
Save to ▾
Show answer
MIN and MAX work on any comparable type. On numbers they return smallest and largest values, on dates the earliest and latest, and on strings the first and last in alphabetical order based on collation. MAX(order_date) gives the latest order, and MIN(name) gives the alphabetically first name, which is useful but not a meaningful business metric by itself.

Frequently asked questions

How is this list made?

We count how often each question appears across the 20 company-wise SQL practice sets on this site and show the 50 most common. They are the safest questions to master first.

Is this enough to clear an interview?

It is the best starting point, not the finish line. After these, practise the company pages for your target employers and the sheets for your weaker topics.