SQL Basic Problems & Solutions
Q. report the first name, last name, city, and state of each person in the Person table. If the address of a personId is not present in the Address table, report null instead.
Section titled “Q. report the first name, last name, city, and state of each person in the Person table. If the address of a personId is not present in the Address table, report null instead.”Input
Person+----------+----------+-----------+| personId | lastName | firstName |+----------+----------+-----------+Address+-----------+----------+---------------+------------+| addressId | personId | city | state |+-----------+----------+---------------+------------+Output
+-----------+----------+---------------+----------+| firstName | lastName | city | state |+-----------+----------+---------------+----------+Solution.
Select p.firstName, p.lastName, a.city, a.state FROM Person p LEFT JOIN Address a ON p.personId=a.personId;-- ✅OR
Select p.firstName, p.lastName, a.city, a.state FROM Person p NATURAL LEFT JOIN Address a;-- ✅if FULL OUTER JOIN ❌ Extra Right Table Address data, for which Person not exist in Left Table if RIGHT JOIN ❌ Missed Left table Person data, for which Address not exist in Right Table IF LEFT JOIN ✅
Q. Write a solution to find the second highest distinct salary from the Employee table. If there is no second highest salary, return null (return None in Pandas).
Section titled “Q. Write a solution to find the second highest distinct salary from the Employee table. If there is no second highest salary, return null (return None in Pandas).”The result format is in the following example.
Example 1:
Input:
Employee table:+----+--------+| id | salary |+----+--------+| 1 | 100 || 2 | 200 || 3 | 300 |+----+--------+Output:
+---------------------+| SecondHighestSalary |+---------------------+| 200 |+---------------------+Solution:
Order by (sort) salaries in descending order, and skips the first (OFFSET 1), then Fetch the Top value (LIMIT 1) i.e. 2nd Largest
Select salary as SecondHighestSalary from EmployeeOrder by Salary DESCLIMIT 1 OFFSET 1 # Offset N-1 = 2nd -1 = 1
-- ❌ If Second Highest Salary Not Exist, It doesnot Return `NULL`-- ⬇️If N exceeds the number of rows, the subquery returns NULL.
Select (Select salary from EmployeeOrder by Salary DESCLIMIT 1 OFFSET 1) as SecondHighestSalary
-- ❌ It Doesn't considering Distinct value. for exam it return 100 for It salary = (100, 100, 50 , 10) not 50-- ⬇️use the DISTINCT keyword
Select (Select Distinct salary from EmployeeOrder by Salary DESCLIMIT 1 OFFSET 1) as SecondHighestSalary-- ✅Q. Write a solution to find the employees who earn more than their managers.
Section titled “Q. Write a solution to find the employees who earn more than their managers.”Input:
Employee table:+----+-------+--------+-----------+| id | name | salary | managerId |+----+-------+--------+-----------+| 1 | Joe | 70000 | 3 || 2 | Henry | 80000 | 4 || 3 | Sam | 60000 | Null || 4 | Max | 90000 | Null |+----+-------+--------+-----------+Output:
+----------+| Employee |+----------+| Joe |+----------+Solutions:
Without using join (My 😃)
Select name as Employee from employee e1 where salary > (Select salary from employee where id = e1.managerId);using join (GPT 🤖)
SELECT e1.name AS EmployeeFROM Employee e1JOIN Employee e2 ON e1.managerId = e2.idWHERE e1.salary > e2.salary;Q. Write a solution to report all the duplicate emails. Note that it’s guaranteed that the email field is not NULL.
Section titled “Q. Write a solution to report all the duplicate emails. Note that it’s guaranteed that the email field is not NULL.”Input:
Person table:+----+---------+| id | email |+----+---------+| 1 | a@b.com || 2 | c@d.com || 3 | a@b.com |+----+---------+**Output:**+---------+| Email |+---------+| a@b.com |+---------+Solution:
using Join (My 😃)
Select Distinct p1.email as Emailfrom Person p1join Person p2 on p1.id!=p2.idwhere p1.email=p2.email;Using Group and Having (GPT 🤖)
SELECT emailFROM PersonGROUP BY emailHAVING COUNT(email) > 1;Q. Write a solution to find all customers who never order anything.
Section titled “Q. Write a solution to find all customers who never order anything.”Left Join ⭐
Example 1:
Input:
Customers table:+----+-------+| id | name |+----+-------+| 1 | Joe || 2 | Henry || 3 | Sam || 4 | Max |+----+-------+Orders table:+----+------------+| id | customerId |+----+------------+| 1 | 3 || 2 | 1 |+----+------------+Output:
+-----------+| Customers |+-----------+| Henry || Max |+-----------+Solution:
My + gpt same 😃
Select name as Customersfrom customers cleft join orders o on c.id = o.customerId where customerId IS NULL; # or `o.id IS NULL`Learnings: customerId = NULL ❌ customerId IS NULL ✅
Q. Write a solution to delete all duplicate emails, keeping only one unique email with the smallest id. ⭐
Section titled “Q. Write a solution to delete all duplicate emails, keeping only one unique email with the smallest id. ⭐”
delete
Note: write a DELETE statement and not a SELECT one.
Example 1:
Input:
Person table:+----+------------------+| id | email |+----+------------------+| 1 | john@example.com || 2 | bob@example.com || 3 | john@example.com |+----+------------------+Output:
+----+------------------+| id | email |+----+------------------+| 1 | john@example.com || 2 | bob@example.com |+----+------------------+Solution:
using Conditional Join
DELETE p1FROM person p1JOIN person p2 ON p1.email = p2.email AND p1.id > p2.id;using Where on Cross Join
Delete p2from person p1Join person p2where p1.email=p2.email AND p2.id>p1.idIn case we have to write select statement
Select MIN(id), email from person group by emailQ. Write a solution to find all dates’ id with higher temperatures compared to its previous dates (yesterday).
Section titled “Q. Write a solution to find all dates’ id with higher temperatures compared to its previous dates (yesterday).”Example 1:
Input:
Weather table:+----+------------+-------------+| id | recordDate | temperature |+----+------------+-------------+| 1 | 2015-01-01 | 10 || 2 | 2015-01-02 | 25 || 3 | 2015-01-03 | 20 || 4 | 2015-01-04 | 30 |+----+------------+-------------+Output:
+----+| id |+----+| 2 || 4 |+----+Solutions:
Without using DATE_ADD() OR DATE_SUB (My Ans)
Select w2.id from weather w1join weather w2on (w1.recordDate=w2.recordDate - INTERVAL 1 day) AND w2.temperature>w1.temperature;Using DATE_SUB()
SELECT w1.idFROM Weather w1JOIN Weather w2 ON DATE_ADD(w2.recordDate, INTERVAL 1 DAY) = w1.recordDateWHERE w1.temperature > w2.temperature;Learnings ⭐
SELECT CURDATE()-1 ; # ERROR ❌Previous Day
SELECT CURDATE() - INTERVAL 1 DAY; # previous day ✅# orSELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY); # Using Subtract previous day ✅Next Day
SELECT CURDATE() + INTERVAL 1 DAY; # Next day ✅# orSELECT DATE_ADD(CURDATE(), INTERVAL 1 DAY); # Using Add Next day ✅Q. Write a solution to find, for each event_type registered more than once, the difference between the latest and second latest value (based on time). Return the result ordered by event_type. ⭐⭐
Section titled “Q. Write a solution to find, for each event_type registered more than once, the difference between the latest and second latest value (based on time). Return the result ordered by event_type. ⭐⭐”Table Schema:
CREATE TABLE events ( event_type INTEGER NOT NULL, value INTEGER NOT NULL, time TIMESTAMP NOT NULL, UNIQUE(event_type, time));Example Input:
+------------+-------+---------------------+| event_type | value | time |+------------+-------+---------------------+| 2 | 5 | 2015-05-09 12:42:00 || 4 | -42 | 2015-05-09 13:19:57 || 2 | 2 | 2015-05-09 14:48:30 || 2 | 7 | 2015-05-09 12:54:39 || 3 | 16 | 2015-05-09 13:19:57 || 3 | 20 | 2015-05-09 15:01:09 |+------------+-------+---------------------+Expected Output:
+------------+--------+| event_type | value |+------------+--------+| 2 | -5 || 3 | 4 |+------------+--------+Solution (Using ROW_NUMBER()):
Section titled “Solution (Using ROW_NUMBER()):”WITH ranked_events AS ( SELECT event_type, value, ROW_NUMBER() OVER (PARTITION BY event_type ORDER BY time DESC) AS rn FROM events),
filtered AS ( SELECT event_type, MAX(CASE WHEN rn = 1 THEN value END) AS latest, MAX(CASE WHEN rn = 2 THEN value END) AS second_latest FROM ranked_events GROUP BY event_type HAVING COUNT(*) > 1)SELECT event_type, latest - second_latest AS valueFROM filteredORDER BY event_type;Learnings ⭐
Section titled “Learnings ⭐”Row Ranking
ROW_NUMBER() OVER (PARTITION BY col ORDER BY col DESC); -- assigns 1,2,3,... within groupGroup Filtering
HAVING COUNT(*) > 1; -- ensures only event_type with more than one rowAggregating Conditionals
MAX(CASE WHEN rn = 1 THEN value END); -- pick latest valueMAX(CASE WHEN rn = 2 THEN value END); -- pick second latest valueThis ensures clean selection of top 2 values per group using window functions and conditional aggregation.