├── 01-01821-find-customers-with-positive-revenue-this-year.sql ├── 02-00183-customers-who-never-order.sql ├── 03-01873-calculate-special-bonus.sql ├── 04-01398-customers-who-bought-products-A-and-B-but-not-C.sql ├── 05-01112-highest-grade-for-each-student.sql ├── 06-00175-combine-two-tables.sql ├── 07-01607-sellers-with-no-sales.sql ├── 08-01407-top-travellers.sql ├── 09-00607-sales-person.sql ├── 10-01440-evaluate-boolean-expression.sql ├── 11-01212-teams-scores-in-football-tournamant.sql ├── 12-01890-the-latest-login-in-2020.sql ├── 13-00511-game-play-analysis-i.sql ├── 14-01571-warehouse-manager.sql ├── 15-00586-customer-placing-the-largest-number-of-orders.sql ├── 16-01741-find-total-time-spent-by-each-employee.sql ├── 17-01173-immediate-food-delivery-i.sql ├── 18-01445-apples-&-oranges.sql ├── 19-01699-number-of-calls-between-two-persons.sql ├── 20-01587-bank-account-summary-ii.sql ├── 21-00182-duplicate-emails.sql ├── 22-01050-actors-and-director-who-cooperated-at-least-three-times.sql ├── 23-01511-customer_order-frequency.sql ├── 24-01693-daily_leads-and-partners.sql ├── 25-01495-friendly-movies-streamed-last-month.sql ├── 26-01501-countries-you-can-safely-invest-in.sql ├── 27-00603-consecutive-available-seats.sql ├── 28-01795-rearrange-products-table.sql ├── 29-00613-shortest-distance-in-a-line.sql ├── 30-01965-employees-with-missing-information.sql ├── 31-01264-page-recommendations.sql ├── 32-00608-tree-node.sql ├── 33-00534-game-play-analysis-iii.sql ├── 34-01783-grand-slam-titles.sql ├── 35-01747-leetflex-banned-accounts.sql ├── 36-01350-students-with-invalid-departments.sql ├── 37-01303-find-the-team-size.sql ├── 38-00512-game-play-analysis-ii.sql ├── 39-00184-department-highest-salary.sql ├── 40-01549-the-most-recent-orders-for-each-product.sql ├── 41-01532-the-most-recent-three-orders.sql ├── 42-01831-maximum-transaction-each-day.sql ├── 43-01077-project-employees-iii.sql ├── 44-01285-find-the-start-and-end-number-of-continuous-ranges.sql ├── 45-01596-the-most-frequently-ordered-products-for-each-customer.sql ├── 46-01709-biggest-window-between-visits.sql ├── 47-01270-all-people-report-to-the-given-manager.sql ├── 48-01412-find-the-quiet-students-in-all-exams.sql ├── 49-01767-find-the-subtasks-that-did-not-execute.sql ├── 50-01225-report-contiguous-dates.sql └── README.md /01-01821-find-customers-with-positive-revenue-this-year.sql: -------------------------------------------------------------------------------- 1 | -- simple WHERE clause 2 | 3 | select customer_id 4 | from Customers 5 | where year = '2021' and revenue > 0 6 | 7 | 8 | -- google- 1 9 | -------------------------------------------------------------------------------- /02-00183-customers-who-never-order.sql: -------------------------------------------------------------------------------- 1 | -- pick id from Orders, and do not select those ids 2 | 3 | select name as Customers 4 | from Customers 5 | where id not in 6 | (select distinct customerId 7 | from Orders) 8 | 9 | -- amazon- 3 10 | -- apple- 7 11 | -- bloomberg- 5 12 | -- adobe- 2 13 | -------------------------------------------------------------------------------- /03-01873-calculate-special-bonus.sql: -------------------------------------------------------------------------------- 1 | -- simple CASE statement 2 | 3 | select employee_id, 4 | (case when employee_id % 2 = 1 and name not like 'M%' then salary else 0 end) as bonus 5 | from Employees 6 | order by employee_id 7 | 8 | 9 | -- apple- 2 10 | -------------------------------------------------------------------------------- /04-01398-customers-who-bought-products-A-and-B-but-not-C.sql: -------------------------------------------------------------------------------- 1 | -- summing up all products, choosing those customers that only has A and B as > 0 and C = 0 2 | 3 | select o.customer_id, c.customer_name 4 | from 5 | (select order_id, customer_id, 6 | sum(product_name='A') as A, 7 | sum(product_name='B') as B, 8 | sum(product_name='C') as C 9 | from Orders 10 | group by customer_id) o 11 | left join Customers c 12 | on c.customer_id = o.customer_id 13 | where A > 0 and B > 0 and C = 0 14 | order by 1 15 | 16 | ------------------------------------------------------------------------------------------------------------------------------------------------- 17 | -- group_concat() approach- unique approach- my first thought 18 | -- group all products per customer, choose customers with only A and B but not c 19 | 20 | select customer_id, customer_name 21 | from 22 | ( 23 | select o.order_id, o.customer_id, c.customer_name, group_concat(o.product_name order by product_name) as group_products 24 | from Orders o left join Customers c 25 | on o.customer_id = c.customer_id 26 | group by c.customer_id 27 | ) temp1 28 | where group_products like '%A%B%' and group_products not like '%A%B%C%' 29 | 30 | ------------------------------------------------------------------------------------------------------------------------------------------------- 31 | -- longer version of the 1st one 32 | 33 | select o.customer_id, c.customer_name 34 | from 35 | (select order_id, customer_id, 36 | sum(case when product_name='A' then 1 else 0 end) as A, 37 | sum(case when product_name='B' then 1 else 0 end) as B, 38 | sum(case when product_name='C' then 1 else 0 end) as C 39 | from Orders 40 | group by customer_id) o 41 | left join Customers c 42 | on c.customer_id = o.customer_id 43 | where A > 0 and B > 0 and C = 0 44 | order by 1 45 | 46 | ------------------------------------------------------------------------------------------------------------------------------------------------- 47 | -- much simpler version of the 1st one 48 | 49 | select o.customer_id, c.customer_name 50 | from Orders o 51 | left join Customers c 52 | on c.customer_id = o.customer_id 53 | group by o.customer_id 54 | having sum(product_name='A') > 0 and sum(product_name='B') > 0 and sum(product_name='C') = 0 55 | order by 1 56 | 57 | 58 | -- amazon- 2 59 | -- facebook- 1 60 | -------------------------------------------------------------------------------- /05-01112-highest-grade-for-each-student.sql: -------------------------------------------------------------------------------- 1 | -- use RANK() and pull results where rank = 1 2 | 3 | select student_id, course_id, grade 4 | from 5 | (select student_id, course_id, grade, dense_rank() over(partition by student_id order by grade desc, course_id asc) as rnk 6 | from Enrollments) temp1 7 | where rnk = 1 8 | order by 1 9 | 10 | -------------------------------------------------------------------------------------------------------------------------------------------------------------- 11 | -- nested 12 | -- first get id and highest grade, then get min course_id 13 | 14 | select student_id, min(course_id) as course_id, grade 15 | from Enrollments 16 | where (student_id, grade) in 17 | (select student_id, max(grade) as grade 18 | from Enrollments 19 | group by student_id) 20 | group by student_id 21 | order by student_id 22 | 23 | -- amazon- 2 24 | -- coursera- 1 25 | -------------------------------------------------------------------------------- /06-00175-combine-two-tables.sql: -------------------------------------------------------------------------------- 1 | -- simple LEFT JOIN 2 | 3 | select p.firstName, p.lastName, a.city, a.state 4 | from Person p 5 | left join Address a 6 | using(personId) 7 | 8 | 9 | -- apple- 4 10 | -- bloomberg- 2 11 | -- amazon- 2 12 | -- microsoft- 2 13 | -- adobe- 3 14 | -- google- 3 15 | -------------------------------------------------------------------------------- /07-01607-sellers-with-no-sales.sql: -------------------------------------------------------------------------------- 1 | -- select sellers from Orders table 2 | -- then select Sellers from Sellers table who are not in temp 3 | 4 | select seller_name 5 | from Seller s 6 | where seller_id not in 7 | (select seller_id 8 | from Orders 9 | where sale_date like '2020%') 10 | order by seller_name 11 | 12 | -------------------------------------------------------------------------------------------------------------------------------------------- 13 | -- using JOIN with conditions 14 | 15 | select s.seller_name 16 | from Seller s 17 | left join Orders o 18 | on o.seller_id = s.seller_id and sale_date like '2020%' 19 | where o.seller_id is null 20 | order by seller_name 21 | 22 | -- no companies listed 23 | -------------------------------------------------------------------------------- /08-01407-top-travellers.sql: -------------------------------------------------------------------------------- 1 | -- using ifnull around sum()- can also use coalesce 2 | 3 | select u.name, ifnull(sum(r.distance), 0) as travelled_distance 4 | from Users u 5 | left join Rides r 6 | on u.id = r.user_id 7 | group by u.id 8 | order by 2 desc, 1 asc 9 | 10 | 11 | -- point72- 1 12 | -------------------------------------------------------------------------------- /09-00607-sales-person.sql: -------------------------------------------------------------------------------- 1 | -- nested query 2 | -- select all salesPerson with company RED 3 | -- select all salesPerson from SalesPerson not in the above table 4 | 5 | select sp.name 6 | from SalesPerson sp 7 | where sales_id not in 8 | (select o.sales_id 9 | from Orders o 10 | where o.com_id in 11 | (select c.com_id 12 | from Company c 13 | where c.name = 'RED')) 14 | 15 | ------------------------------------------------------------------------------------------------------------------------------------------------ 16 | -- JOIN Company c and Ordered o 17 | -- pick all sales_id with company = 'RED' 18 | -- pick all salesPerson from SalesPerson not in temp table above 19 | 20 | select sp.name 21 | from SalesPerson sp 22 | where sales_id not in 23 | (select o.sales_id 24 | from Orders o 25 | inner join Company c 26 | on c.com_id = o.com_id 27 | where c.name = 'RED') 28 | 29 | 30 | -- no companies listed 31 | -------------------------------------------------------------------------------- /10-01440-evaluate-boolean-expression.sql: -------------------------------------------------------------------------------- 1 | -- create 2 value tables- l for left operand, r for right operand 2 | -- use join to join it to the main table 3 | -- write case statements using l.value and r.value 4 | 5 | select e.left_operand, e.operator, e.right_operand, 6 | (case when operator = '>' and l.value > r.value then 'true' 7 | when operator = '<' and l.value < r.value then 'true' 8 | when operator = '=' and l.value = r.value then 'true' 9 | else 'false' end) as value 10 | from Expressions e 11 | join Variables l 12 | on l.name = e.left_operand 13 | join Variables r 14 | on r.name = right_operand 15 | 16 | -- point72-1 17 | -------------------------------------------------------------------------------- /11-01212-teams-scores-in-football-tournamant.sql: -------------------------------------------------------------------------------- 1 | -- union all- one for host(when that team was host)- count host score, 2nd for guest(when that team was guest)- count guest score 2 | -- calculate sum of points 3 | -- group by team_id 4 | 5 | select t.team_id, t.team_name, coalesce(sum(u.points), 0) as num_points 6 | from Teams t 7 | left join 8 | (select match_id, host_team as team_id, (case when host_goals > guest_goals then 3 9 | when host_goals = guest_goals then 1 10 | else 0 end) as points 11 | from Matches 12 | union all 13 | select match_id, guest_team as team_id, 14 | (case when host_goals < guest_goals then 3 15 | when host_goals = guest_goals then 1 16 | else 0 end) as points 17 | from Matches) u 18 | on u.team_id = t.team_id 19 | group by team_id 20 | order by 3 desc, 1 asc 21 | 22 | ------------------------------------------------------------------------------------------------------------------------- 23 | -- without using 'UNION ALL'- only used JOIN 24 | 25 | select t.team_id, t.team_name, coalesce( 26 | sum(case when t.team_id = m.host_team and m.host_goals > m.guest_goals then 3 27 | when t.team_id = m.guest_team and m.guest_goals > m.host_goals then 3 28 | when host_goals = guest_goals then 1 end), 0) as num_points 29 | from Teams t 30 | left join Matches m 31 | on m.host_team = t.team_id or m.guest_team = t.team_id 32 | group by team_id 33 | order by 3 desc, 1 asc 34 | 35 | 36 | -- wayfair- 1 37 | -------------------------------------------------------------------------------- /12-01890-the-latest-login-in-2020.sql: -------------------------------------------------------------------------------- 1 | -- simple aggregate(), like 2 | 3 | select user_id, max(time_stamp) as last_stamp 4 | from Logins 5 | where time_stamp like '2020%' 6 | group by 1 7 | 8 | ---------------------------------------------------------------------------------------------------------------- 9 | -- using year() for getting 2020 instead of like 10 | 11 | select user_id, max(time_stamp) as last_stamp 12 | from Logins 13 | where year(time_stamp) = '2020' 14 | group by 1 15 | 16 | ---------------------------------------------------------------------------------------------------------------- 17 | -- using first_value() 18 | 19 | select distinct user_id, first_value(time_stamp) over(partition by user_id order by time_stamp desc) as last_stamp 20 | from Logins 21 | where year(time_stamp) = '2020' 22 | 23 | -- no companies listed 24 | -------------------------------------------------------------------------------- /13-00511-game-play-analysis-i.sql: -------------------------------------------------------------------------------- 1 | -- simple aggregate function 2 | 3 | select player_id, min(event_date) as first_login 4 | from Activity 5 | group by 1 6 | 7 | -- adobe- 2 8 | -- amazon- 4 9 | -- bloomberg- 4 10 | -- gsn games- 1 11 | -------------------------------------------------------------------------------- /14-01571-warehouse-manager.sql: -------------------------------------------------------------------------------- 1 | -- multiple units, width, length, height, then calculate sum() of those 2 | 3 | select w.name as warehouse_name, 4 | sum(units * Width * Length * Height) as volume 5 | from Warehouse w 6 | left join Products p 7 | on w.product_id = p.product_id 8 | group by 1 9 | 10 | ------------------------------------------------------------------------------------------------------------- 11 | -- breaking down the above one 12 | 13 | with CTE as ( 14 | select product_id, (Width * Length * Height) as size 15 | from Products) 16 | 17 | select name as warehouse_name, sum(units * size) as volume 18 | from Warehouse w 19 | left join CTE c 20 | on c.product_id = w.product_id 21 | group by name 22 | 23 | -- amazon- 1 24 | -------------------------------------------------------------------------------- /15-00586-customer-placing-the-largest-number-of-orders.sql: -------------------------------------------------------------------------------- 1 | -- the the cusotmer with maximum order count, order by, limit 2 | 3 | select customer_number 4 | from Orders 5 | group by 1 6 | order by count(order_number) desc 7 | limit 1 8 | 9 | 10 | -- adobe- 2 11 | -- google- 3 12 | -- apple- 2 13 | -- uber- 2 14 | -- twitter- 1 15 | -------------------------------------------------------------------------------- /16-01741-find-total-time-spent-by-each-employee.sql: -------------------------------------------------------------------------------- 1 | -- simple aggregation- we need total sum of the diff between out and in time 2 | 3 | select event_day as day, emp_id, sum(out_time-in_time) as total_time 4 | from Employees 5 | group by 1, 2 6 | 7 | 8 | -- adobe- 2 9 | -- amazon- 1 10 | -------------------------------------------------------------------------------- /17-01173-immediate-food-delivery-i.sql: -------------------------------------------------------------------------------- 1 | -- simple condition in aggregate function- count immediate, divide by total rows in the table 2 | 3 | select round(sum(order_date = customer_pref_delivery_date) / count(*) * 100, 2) as immediate_percentage 4 | from Delivery 5 | --------------------------------------------------------------------------------------------------------------------------------------------- 6 | -- same as above but using case 7 | 8 | select round(sum( case when order_date = customer_pref_delivery_date then 1 else 0 end) / count(*) * 100, 2) as immediate_percentage 9 | from Delivery 10 | 11 | 12 | -- doordash- 2 13 | -------------------------------------------------------------------------------- /18-01445-apples-&-oranges.sql: -------------------------------------------------------------------------------- 1 | -- simple aggregate with condition 2 | 3 | select sale_date, (sum(case when fruit = 'apples' then sold_num else 0 end) - 4 | sum(case when fruit = 'oranges' then sold_num else 0 end)) as diff 5 | from Sales 6 | group by 1 7 | order by 1 8 | 9 | --------------------------------------------------------------------------------------------------------------- 10 | -- using join- 1 table for apples, 1 for oranges, join on sales date 11 | 12 | select sa.sale_date, (ifnull(sum(sa.sold_num),0)-ifnull(sum(so.sold_num), 0)) as diff 13 | from Sales sa 14 | join Sales so 15 | on sa.sale_date = so.sale_date and sa.fruit = 'apples' and so.fruit = 'oranges' 16 | group by 1 17 | order by 1 18 | 19 | 20 | -- facebook- 1 21 | -------------------------------------------------------------------------------- /19-01699-number-of-calls-between-two-persons.sql: -------------------------------------------------------------------------------- 1 | -- union all- this gets all calls, then we put condition p1 < p2 2 | 3 | select from_id as person1, to_id as person2, count(*) as call_count, sum(duration) as total_duration 4 | from 5 | (select from_id, to_id, duration 6 | from Calls 7 | union all 8 | select to_id, from_id, duration 9 | from Calls) t 10 | where from_id < to_id 11 | group by 1, 2 12 | 13 | ----------------------------------------------------------------------------------------------------------------------------- 14 | -- without using union all 15 | -- make p1 < p2, then do calculations 16 | 17 | select 18 | (case when from_id < to_id then from_id else to_id end) as person1, 19 | (case when from_id < to_id then to_id else from_id end) as person2, 20 | count(*) as call_count, 21 | sum(duration) as total_duration 22 | from Calls 23 | group by 1, 2 24 | 25 | 26 | -- facebook- 2 27 | -- amazon- 1 28 | -------------------------------------------------------------------------------- /20-01587-bank-account-summary-ii.sql: -------------------------------------------------------------------------------- 1 | -- simple aggregate with JOIN and HAVING 2 | 3 | select u.name, sum(t.amount) as balance 4 | from Users u 5 | left join Transactions t 6 | on u.account = t.account 7 | group by u.account 8 | having sum(t.amount) > 10000 9 | 10 | -- uber- 2 11 | -------------------------------------------------------------------------------- /21-00182-duplicate-emails.sql: -------------------------------------------------------------------------------- 1 | -- use group by for aggregate 2 | 3 | select email as Email 4 | from Person 5 | group by email 6 | having count(email) > 1 7 | 8 | 9 | -- amazon- 2 10 | -- uber- 2 11 | -------------------------------------------------------------------------------- /22-01050-actors-and-director-who-cooperated-at-least-three-times.sql: -------------------------------------------------------------------------------- 1 | -- aggregate- group by 2 columns, count 2 | 3 | select actor_id, director_id 4 | from ActorDirector 5 | group by 1, 2 6 | having count(*) >= 3 7 | 8 | 9 | -- amazon- 3 10 | -------------------------------------------------------------------------------- /23-01511-customer_order-frequency.sql: -------------------------------------------------------------------------------- 1 | -- we need customer ids from 2 separate tables using 'and' condition 2 | -- 1st table- get sum of expenditures of all customers in June 2020, filter by customers whose sum >= 100 3 | -- 2nd table- get sum of expenditures of all customers in July 2020, filter by customers whose sum >= 100 4 | -- pull all customers who are in table1 AND table 2 5 | 6 | select c.customer_id, c.name 7 | from Customers 8 | where customer_id in 9 | (select customer_id 10 | from Orders o 11 | join Product p 12 | on o.product_id = p.product_id 13 | where left(order_date, 7) = '2020-06' 14 | group by customer_id 15 | having sum(quantity*price) >= 100) 16 | and customer_id in 17 | (select customer_id, sum(quantity*price) 18 | from Orders o 19 | join Product p 20 | on o.product_id = p.product_id 21 | where left(order_date, 7) = '2020-07' 22 | group by customer_id 23 | having sum(quantity*price) >= 100) 24 | 25 | --------------------------------------------------------------------------------------------------------------------- 26 | 27 | -- create a temp table- join all tables 28 | -- create 2 additional columns- expenditure in June and in July- CASE, AGGREGATE 29 | -- in the main query, pull customer ids where expenditure in both columns are >= 100 30 | 31 | with CTE as(select c.customer_id, c.name, 32 | sum(case when left(o.order_date, 7) = '2020-06' then p.price*o.quantity else 0 end) june_spent, 33 | sum(case when left(o.order_date, 7) = '2020-07' then p.price*o.quantity else 0 end) july_spent 34 | from Customers c 35 | join Orders o 36 | on c.customer_id = o.customer_id 37 | join Product p 38 | on p.product_id = o.product_id 39 | group by 1) 40 | 41 | select customer_id, name 42 | from CTE 43 | where june_spent >= 100 and july_spent >= 100 44 | 45 | 46 | -- amazon- 1 47 | -------------------------------------------------------------------------------- /24-01693-daily_leads-and-partners.sql: -------------------------------------------------------------------------------- 1 | -- basic aggregate function- count distinct, group by 2 variables 2 | 3 | select date_id, make_name, 4 | count(distinct lead_id) unique_leads, 5 | count(distinct partner_id) unique_partners 6 | from DailySales 7 | group by date_id, make_name 8 | 9 | 10 | -- no companies listed 11 | -------------------------------------------------------------------------------- /25-01495-friendly-movies-streamed-last-month.sql: -------------------------------------------------------------------------------- 1 | -- use DISTINCT because we want distinct titles 2 | -- use where condition for filter 3 | 4 | select distinct title 5 | from Content c join TVProgram t 6 | on c.content_id = t.content_id 7 | where c.Kids_content = 'Y' and c.content_type = 'Movies' and t.program_date like '2020-06%' 8 | 9 | 10 | -- amazon- 1 11 | -------------------------------------------------------------------------------- /26-01501-countries-you-can-safely-invest-in.sql: -------------------------------------------------------------------------------- 1 | -- id_country- get country name for each person by joining on country code 2 | -- id_duration- duration for each person on each call- each person can have multiple rows 3 | -- final query- join these 2 to calculate avg for each country- group by country 4 | -- use having clause to filter avg for country > global avg (calculated using id_duration cte) 5 | 6 | 7 | with id_country as 8 | (select p.id, c.name as country 9 | from Person p 10 | join Country c 11 | on left(p.phone_number, 3) = c.country_code), 12 | 13 | id_duration as 14 | (select caller_id, duration 15 | from Calls 16 | union all 17 | select callee_id, duration 18 | from Calls) 19 | 20 | select c.country 21 | from id_country c 22 | join id_duration d 23 | on c.id = d.caller_id 24 | group by c.country 25 | having avg(duration) > (select avg(duration) 26 | from id_duration) 27 | 28 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 29 | -- same as above but concise 30 | -- first cte as above, 31 | -- then join on Calls using OR 32 | 33 | select c.name as country 34 | from Country c 35 | join Person p 36 | on c.country_code = left(p.phone_number, 3) 37 | join calls cl 38 | on cl.caller_id = p.id or cl.callee_id = p.id 39 | group by c.name 40 | having avg(duration) > (select avg(duration) 41 | from Calls) 42 | 43 | 44 | -- no companies listed 45 | -------------------------------------------------------------------------------- /27-00603-consecutive-available-seats.sql: -------------------------------------------------------------------------------- 1 | -- lag and lead will give the rows above and below 2 | -- if free = 1 and either of lag_free or lead_free is 1, it means we have 2 consecutive free seats. 3 | -- just pick those rows 4 | 5 | with CTE as( 6 | select seat_id, free, 7 | lag(free, 1) over(order by seat_id) as lag_free, 8 | lead(free, 1) over(order by seat_id) as lead_free 9 | from Cinema) 10 | 11 | select seat_id 12 | from CTE 13 | where (free = 1 and lag_free = 1) or (free = 1 and lead_free = 1) 14 | order by 1 15 | 16 | ------------------------------------------------------------------------------------------------------------------------------------------------------------ 17 | -- if seat = free AND seat + 1 or seat - 1 have free = 1, then pull that seat 18 | 19 | select seat_id 20 | from Cinema 21 | where free = 1 and 22 | (seat_id - 1 in (select seat_id 23 | from Cinema 24 | where free = 1) 25 | or 26 | seat_id + 1 in (select seat_id 27 | from Cinema 28 | where free = 1)) 29 | 30 | 31 | -- amazon- 4 32 | -------------------------------------------------------------------------------- /28-01795-rearrange-products-table.sql: -------------------------------------------------------------------------------- 1 | -- beginner solution- using unions 2 | -- create a table without nulls 3 | 4 | select product_id, 'store1' as store, store1 as price 5 | from Products 6 | where store1 is not null 7 | union 8 | select product_id, 'store2' as store, store2 as price 9 | from Products 10 | where store2 is not null 11 | union 12 | select product_id, 'store3' as store, store3 as price 13 | from Products 14 | where store3 is not null 15 | 16 | --------------------------------------------------------------------------------------------------------------------------------------------------------- 17 | -- create a table with nulls, then filter out rows without nulls 18 | 19 | select product_id, store, price 20 | from 21 | (select product_id, 'store1' as store, store1 as price 22 | from Products 23 | union 24 | select product_id, 'store2' as store, store2 as price 25 | from Products 26 | union 27 | select product_id, 'store3' as store, store3 as price 28 | from Products) t 29 | where price is not null 30 | 31 | 32 | -- bloomberg- 2 33 | -- apple- 2 34 | -- amazon- 1 35 | -------------------------------------------------------------------------------- /29-00613-shortest-distance-in-a-line.sql: -------------------------------------------------------------------------------- 1 | -- cross joining all the points from 2 tables, except the ones where they are same 2 | -- find the min of absolute distance 3 | 4 | select min(abs(a - b)) as shortest 5 | from 6 | (select p1.x as a, p2.x as b 7 | from Point p1 cross join Point p2 8 | where p1.x != p2.x) temp 9 | 10 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 11 | -- concise version of the above 12 | 13 | select min(abs(p1.x - p2.x)) as shortest 14 | from Point p1 cross join Point p2 15 | where p1.x != p2.x 16 | 17 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 18 | -- pull min distance with a where condition 19 | 20 | select min(p1.x - p2.x) as shortest 21 | from Point p1, Point p2 22 | where p1.x > p2.x 23 | 24 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 25 | -- sort the table, and do lag. Now diff between current and lag- because difference between the sorted will always be lesser than difference between the larger ones 26 | -- pull the min distance 27 | 28 | with CTE as 29 | (select x - lag(x) over(order by x) as distance 30 | from Point) 31 | 32 | select min(distance) as shortest from CTE 33 | 34 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 35 | -- picking the lowest distance, 1st row will always be null hence use offset 36 | 37 | select x - lag(x) over(order by x) as shortest 38 | from Point 39 | order by 1 asc 40 | limit 1 offset 1 41 | 42 | 43 | -- no companies listed 44 | -------------------------------------------------------------------------------- /30-01965-employees-with-missing-information.sql: -------------------------------------------------------------------------------- 1 | -- select all employees from Employees not in Salaries, UNION select all employees from Salaries not in Employees 2 | 3 | select employee_id 4 | from Employees 5 | where employee_id not in 6 | (select employee_id 7 | from Salaries) 8 | union 9 | select employee_id 10 | from Salaries 11 | where employee_id not in 12 | (select employee_id 13 | from Employees) 14 | order by 1 15 | 16 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- 17 | -- first get a table of all employees bu doing a UNION on the 2 tables 18 | -- then select those emeployees which are in above table but not in respective tables- UNION 19 | 20 | with all_employees as 21 | (select employee_id 22 | from Employees 23 | union 24 | select employee_id 25 | from Salaries) 26 | 27 | select employee_id 28 | from all_employees 29 | where employee_id not in (select employee_id from Employees) 30 | union 31 | select employee_id 32 | from all_employees 33 | 34 | -- adobe- 2 35 | 36 | -- alternate 37 | where employee_id not in (select employee_id from Salaries) 38 | order by 1 39 | 40 | 41 | -------------------------------------------------------------------------------- /31-01264-page-recommendations.sql: -------------------------------------------------------------------------------- 1 | -- got user1=id = 1 friends in t0 and t1 2 | -- joined t1 with Likes on 1's friends 3 | -- where condition- page shouldn't be liked by 1 4 | 5 | with t0 as 6 | (select user1_id, user2_id 7 | from Friendship 8 | union 9 | select user2_id, user1_id 10 | from Friendship), 11 | t1 as 12 | (select user1_id, user2_id 13 | from t0 14 | where user1_id = 1) 15 | 16 | select distinct l.page_id as recommended_page 17 | from t1 join Likes l 18 | on t1.user2_id = l.user_id 19 | where page_id not in 20 | (select page_id 21 | from Likes 22 | where user_id = 1) 23 | 24 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 25 | -- same as above but 1 less CTE and added where condition 26 | 27 | with t1 as 28 | (select user1_id, user2_id 29 | from Friendship 30 | union 31 | select user2_id, user1_id 32 | from Friendship) 33 | 34 | select distinct l.page_id as recommended_page 35 | from t1 join Likes l 36 | on t1.user2_id = l.user_id 37 | where t1.user1_id = 1 38 | and page_id not in 39 | (select page_id 40 | from Likes 41 | where user_id = 1) 42 | 43 | 44 | -- facebook- 1 45 | -------------------------------------------------------------------------------- /32-00608-tree-node.sql: -------------------------------------------------------------------------------- 1 | -- 3 cases- use CASE WHEN 2 | 3 | select id, 4 | (case when p_id is null then 'Root' 5 | when id in (select p_id from Tree) then 'Inner' 6 | else 'Leaf' end) as type 7 | from Tree 8 | 9 | 10 | -- twitter- 1 11 | -------------------------------------------------------------------------------- /33-00534-game-play-analysis-iii.sql: -------------------------------------------------------------------------------- 1 | -- running total of games played 2 | -- sum() over() 3 | 4 | select player_id, event_date, 5 | sum(games_played) over(partition by player_id order by event_date) as games_played_so_far 6 | from Activity 7 | 8 | -- gsn games 9 | -------------------------------------------------------------------------------- /34-01783-grand-slam-titles.sql: -------------------------------------------------------------------------------- 1 | -- beginner level solution 2 | -- all player ids in a single column, count those, join with Players for name 3 | 4 | with CTE as 5 | (select Wimbledon as id 6 | from Championships 7 | union all 8 | select Fr_open as id 9 | from Championships 10 | union all 11 | select US_open as id 12 | from Championships 13 | union all 14 | select Au_open as id 15 | from Championships) 16 | 17 | select c.id as player_id, p.player_name, count(c.id) as grand_slams_count 18 | from CTE c 19 | join Players p 20 | on c.id = p.player_id 21 | group by 1 22 | 23 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ 24 | -- using cross join 25 | -- using aggregate function because we want to group by each player 26 | -- using cross join, we are getting all players and all championships 27 | -- so we use having to filter only those players who have won at least 1 28 | 29 | select p.player_id, p.player_name, 30 | sum(case when p.player_id = c.Wimbledon then 1 else 0 end + 31 | case when p.player_id = c.Fr_open then 1 else 0 end + 32 | case when p.player_id = c.US_open then 1 else 0 end + 33 | case when p.player_id = c.Au_open then 1 else 0 end) as grand_slams_count 34 | from Players p 35 | cross join Championships c 36 | group by p.player_id 37 | having grand_slams_count > 0 38 | 39 | 40 | -- amazon- 1 41 | -------------------------------------------------------------------------------- /35-01747-leetflex-banned-accounts.sql: -------------------------------------------------------------------------------- 1 | -- join 2 | 3 | select distinct l1.account_id 4 | from LogInfo l1 5 | join LogInfo l2 6 | on l1.account_id = l2.account_id 7 | and l1.ip_address != l2.ip_address 8 | and l1.login between l2.login and l2.logout 9 | 10 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 11 | -- self join- more popular answer on LC 12 | 13 | select distinct l1.account_id 14 | from LogInfo l1, LogInfo l2 15 | where l1.account_id = l2.account_id 16 | and l1.ip_address != l2.ip_address 17 | and l1.login between l2.login and l2.logout 18 | 19 | 20 | -- amazon- 1 21 | 22 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 23 | 24 | -- NOT WORKING FOR THIS CASE: 25 | 26 | -- | account_id | ip_address | login | logout | 27 | -- | ---------- | ---------- | ------------------- | ------------------- | 28 | -- | 1 | 1 | 2021-02-01 09:00:00 | 2021-02-01 15:00:00 | 29 | -- | 1 | 1 | 2021-02-01 10:00:00 | 2021-02-01 11:00:00 | 30 | -- | 1 | 6 | 2021-02-01 12:00:00 | 2021-02-01 13:00:00 | 31 | 32 | -- HERE 1ST AND THIRD OVERLAPS, BUT LEAD() DOESN'T CATCH THAT 33 | 34 | with CTE as 35 | ( 36 | select account_id, ip_address, login, logout, 37 | lead(login) over(partition by account_id order by login) as next_login, 38 | lead(ip_address) over(partition by account_id order by login) as next_ip 39 | from LogInfo 40 | ) 41 | 42 | select distinct account_id 43 | from CTE 44 | where next_login between login and logout 45 | and next_ip != ip_address 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /36-01350-students-with-invalid-departments.sql: -------------------------------------------------------------------------------- 1 | -- subquery- use WHERE 2 | 3 | select id, name 4 | from Students 5 | where department_id not in 6 | (select id 7 | from Departments) 8 | 9 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 10 | 11 | -- join- use WHERE id is null 12 | 13 | select s.id, s.name 14 | from Students s 15 | left join Departments d 16 | on d.id = s.department_id 17 | where d.id is null 18 | 19 | 20 | -- amazon- 1 21 | -------------------------------------------------------------------------------- /37-01303-find-the-team-size.sql: -------------------------------------------------------------------------------- 1 | -- if we do not use order by in over(), we do not get running total, just normal aggregate for all rows within that partition 2 | 3 | select employee_id, count(*) over(partition by team_id) as team_size 4 | from Employee 5 | order by 1 6 | 7 | -- amazon- 1 8 | -------------------------------------------------------------------------------- /38-00512-game-play-analysis-ii.sql: -------------------------------------------------------------------------------- 1 | -- using subquery 2 | 3 | select player_id, device_id 4 | from Activity 5 | where (player_id, event_date) in 6 | (select player_id, min(event_date) 7 | from Activity 8 | group by player_id) 9 | 10 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 11 | -- using window function 12 | 13 | with CTE as 14 | (select player_id, device_id, 15 | row_number() over(partition by player_id order by event_date) as rn 16 | from Activity) 17 | 18 | select player_id, device_id 19 | from CTE 20 | where rn = 1 21 | 22 | -- gsn games- 1 23 | -------------------------------------------------------------------------------- /39-00184-department-highest-salary.sql: -------------------------------------------------------------------------------- 1 | -- using subquery 2 | 3 | select d.name as Department, e.name as Employee, e.salary 4 | from Department d join Employee e 5 | on d.id = e.departmentId 6 | where (e.departmentId, e.salary) in 7 | (select departmentId, max(salary) 8 | from Employee 9 | group by departmentId) 10 | 11 | ----------------------------------------------------------------------------------------------------------------------------------------------------------- 12 | 13 | -- using window function 14 | 15 | with CTE as 16 | (select departmentId, id, name, salary, 17 | dense_rank() over(partition by departmentId order by salary desc) as rnk 18 | from Employee) 19 | 20 | select d.name as Department, e.name as Employee, e.salary 21 | from Department d join CTE e 22 | on d.id = e.departmentId 23 | where e.rnk = 1 24 | 25 | 26 | -- amazon- 2 27 | -- microsoft- 3 28 | -- apple- 2 29 | -- facebook- 2 30 | -- google- 2 31 | -------------------------------------------------------------------------------- /40-01549-the-most-recent-orders-for-each-product.sql: -------------------------------------------------------------------------------- 1 | -- using window function- dense_rank() to get most recent orders by date, partition by product_id 2 | 3 | with CTE as 4 | (select p.product_name, o.product_id, o.order_id, o.order_date, 5 | dense_rank() over(partition by o.product_id order by o.order_date desc) as rnk 6 | from Orders o 7 | left join Products p 8 | on o.product_id = p.product_id) 9 | 10 | select product_name, product_id, order_id, order_date 11 | from CTE 12 | where rnk = 1 13 | order by 1, 2, 3 14 | 15 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 16 | -- using subquery 17 | 18 | select p.product_name, o.product_id, o.order_id, o.order_date 19 | from Products p 20 | join Orders o 21 | on p.product_id = o.product_id 22 | where (o.product_id, o.order_date) in (select product_id, max(order_date) 23 | from Orders 24 | group by product_id) 25 | order by 1, 2, 3 26 | 27 | 28 | -- no companies listed 29 | -------------------------------------------------------------------------------- /41-01532-the-most-recent-three-orders.sql: -------------------------------------------------------------------------------- 1 | -- we needed top 3, so subquery won't be possible without window function 2 | -- used dense_rank() 3 | 4 | with CTE as 5 | (select *, dense_rank() over(partition by customer_id order by order_date desc) as rnk 6 | from Orders) 7 | 8 | select c.name as customer_name, CTE.customer_id, CTE.order_id, CTE.order_date 9 | from CTE 10 | join Customers c 11 | on CTE.customer_id = c.customer_id 12 | where rnk <= 3 13 | order by name, customer_id, order_date desc 14 | 15 | -- no companies listed 16 | -------------------------------------------------------------------------------- /42-01831-maximum-transaction-each-day.sql: -------------------------------------------------------------------------------- 1 | -- using subquery 2 | 3 | select transaction_id 4 | from Transactions 5 | where (day, amount) in (select date(day), max(amount) 6 | from Transactions 7 | group by 1) 8 | order by 1 9 | 10 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 11 | -- using window function 12 | 13 | with CTE as 14 | (select transaction_id, dense_rank() over(partition by date(day) order by amount desc) as rnk 15 | from Transactions) 16 | 17 | select transaction_id 18 | from CTE 19 | where rnk = 1 20 | order by 1 21 | 22 | 23 | -- no companies listed 24 | -------------------------------------------------------------------------------- /43-01077-project-employees-iii.sql: -------------------------------------------------------------------------------- 1 | -- use dense_rank(), partition by project, order by years desc 2 | 3 | with CTE as 4 | (select p.project_id, p.employee_id, e.experience_years, 5 | dense_rank() over(partition by p.project_id order by e.experience_years desc) as rnk 6 | from Project p 7 | left join Employee e 8 | on p.employee_id = e.employee_id) 9 | 10 | select project_id, employee_id 11 | from CTE 12 | where rnk = 1 13 | 14 | -- facebook- 1 15 | -------------------------------------------------------------------------------- /44-01285-find-the-start-and-end-number-of-continuous-ranges.sql: -------------------------------------------------------------------------------- 1 | -- row number- created just to look at what it looks like 2 | -- continuous ranges have same differences from row number 3 | -- so pick min as start, max as end and group by diff 4 | 5 | select min(log_id) as start_id, max(log_id) as end_id 6 | from 7 | (select log_id, 8 | row_number() over(order by log_id) as rn, 9 | log_id - row_number() over(order by log_id) as diff 10 | from Logs) temp 11 | group by diff 12 | 13 | 14 | -- microsoft- 1 15 | -------------------------------------------------------------------------------- /45-01596-the-most-frequently-ordered-products-for-each-customer.sql: -------------------------------------------------------------------------------- 1 | -- first create cte1 with count 2 | -- then cte2 with rank using that count 3 | -- then fetch rows with rnk = 1, join for product name 4 | 5 | with cte1 as 6 | (select customer_id, product_id, count(product_id) as count_product 7 | from Orders 8 | group by customer_id, product_id), 9 | cte2 as 10 | (select customer_id, product_id, 11 | dense_rank() over(partition by customer_id order by count_product desc) as rnk 12 | from cte1) 13 | 14 | select c.customer_id, c.product_id, p.product_name 15 | from cte2 c 16 | join Products p 17 | on p.product_id = c.product_id 18 | where rnk = 1 19 | 20 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 21 | 22 | -- same as above, but combined cte1 and cte2 into 1 table- used count() directly inside rank() 23 | 24 | with cte2 as 25 | (select customer_id, product_id, 26 | dense_rank() over(partition by customer_id order by count(product_id) desc) as rnk 27 | from Orders 28 | group by 1, 2) 29 | 30 | select c.customer_id, c.product_id, p.product_name 31 | from cte2 c 32 | join Products p 33 | on p.product_id = c.product_id 34 | where rnk = 1 35 | 36 | 37 | -- no companies listed 38 | -------------------------------------------------------------------------------- /46-01709-biggest-window-between-visits.sql: -------------------------------------------------------------------------------- 1 | -- use lead() to get next date 2 | -- if there's no date, difference has to be calculated with 2021-1-1, so put this value in lead() 3 | 4 | with CTE as 5 | (select user_id, visit_date, 6 | lead(visit_date, 1, '2021-1-1') over(partition by user_id order by visit_date) as next_date 7 | from UserVisits) 8 | 9 | select user_id, max(datediff(next_date, visit_date)) as biggest_window 10 | from CTE 11 | group by user_id 12 | 13 | 14 | -- no companies listed 15 | -------------------------------------------------------------------------------- /47-01270-all-people-report-to-the-given-manager.sql: -------------------------------------------------------------------------------- 1 | -- innermost layer will give- 2, 77 because they directly report to 1 2 | -- second layer will give- 4 because he reports to 2 3 | -- outermost layer will give 7 because he reports to 4 4 | -- so first table- 7 5 | -- 2nd table- 4 6 | -- 3rd table- 2, 77 7 | 8 | select employee_id 9 | from Employees 10 | where manager_id in 11 | (select employee_id 12 | from Employees 13 | where manager_id in 14 | (select employee_id 15 | from Employees 16 | where manager_id = 1 and employee_id != 1)) 17 | union 18 | select employee_id 19 | from Employees 20 | where manager_id in 21 | (select employee_id 22 | from Employees 23 | where manager_id = 1 and employee_id != 1) 24 | union 25 | select employee_id 26 | from Employees 27 | where manager_id = 1 and employee_id != 1 28 | 29 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 30 | -- using join 31 | -- tier1 is immediate reportees of 1- 2, 77 32 | -- tier 2 has 1 layer between them and 1- tier1.employee_id = Employee.manager_id- 4 33 | -- tier3 has 2 layers between them and 1- tier2.emplpoyee_id = Employee.manager_id- 7 34 | 35 | with tier1 as 36 | (select e.employee_id 37 | from Employees e 38 | where manager_id = 1 and e.employee_id != 1), 39 | tier2 as 40 | (select e.employee_id 41 | from Employees e 42 | join tier1 t1 43 | on t1.employee_id = e.manager_id), 44 | tier3 as 45 | (select e.employee_id 46 | from Employees e 47 | join tier2 t2 48 | on t2.employee_id = e.manager_id) 49 | 50 | select employee_id 51 | from tier1 52 | union 53 | select employee_id 54 | from tier2 55 | union 56 | select employee_id 57 | from tier3 58 | 59 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 60 | -- using 2 joins 61 | 62 | select e1.employee_id 63 | from Employees e1 64 | join Employees e2 65 | on e1.manager_id = e2.employee_id 66 | join Employees e3 67 | on e2.manager_id = e3.employee_id 68 | where e3.manager_id = 1 and e1.employee_id != 1 69 | 70 | 71 | -- adobe- 2 72 | -- google- 1 73 | 74 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 75 | -- NOT A SOLUTION- ONLY EXPLANATION- JOINS 76 | 77 | select e1.employee_id as e1emp, e1.manager_id as e1man, e2.employee_id as e2emp, e2.manager_id as e2man, e3.employee_id as e3emp, e3.manager_id as e3man 78 | from Employees e1 79 | join Employees e2 80 | on e1.manager_id = e2.employee_id 81 | join Employees e3 82 | on e2.manager_id = e3.employee_id 83 | 84 | -- logic- o/p e1emp 85 | -- e1man = e2emp, e2man = e3emp, e3man = 1, e1emp != 1 86 | -- we are outputting employee != 1 and ultimate manager = 1 87 | 88 | | e1emp | e1man | e2emp | e2man | e3emp | e3man | 89 | | ----- | ----- | ----- | ----- | ----- | ----- | 90 | | 4 | 2 | 2 | 1 | 1 | 1 | 91 | | 1 | 1 | 1 | 1 | 1 | 1 | 92 | | 2 | 1 | 1 | 1 | 1 | 1 | 93 | | 77 | 1 | 1 | 1 | 1 | 1 | 94 | | 9 | 8 | 8 | 3 | 3 | 3 | 95 | | 3 | 3 | 3 | 3 | 3 | 3 | 96 | | 8 | 3 | 3 | 3 | 3 | 3 | 97 | | 7 | 4 | 4 | 2 | 2 | 1 | 98 | 99 | -------------------------------------------------------------------------------- /48-01412-find-the-quiet-students-in-all-exams.sql: -------------------------------------------------------------------------------- 1 | -- CTE1- find highest rank and lowest rank in 2 separate columns using dense_rank() 2 | -- CTE2- get the list of students in CTE1 3 | -- CTE3- get the list of students who took exams but are not in CTE2 4 | -- final query- output id and name of students in CTE3 5 | 6 | with CTE1 as 7 | (select exam_id, student_id, score, 8 | dense_rank() over(partition by exam_id order by score desc) rank_highest, 9 | dense_rank() over(partition by exam_id order by score asc) rank_lowest 10 | from Exam), 11 | CTE2 as 12 | (select student_id 13 | from CTE1 14 | where rank_highest = 1 or rank_lowest = 1), 15 | CTE3 as 16 | (select distinct student_id 17 | from Exam 18 | where student_id not in (select * from CTE2)) 19 | 20 | select student_id, student_name 21 | from Student 22 | where student_id in (select * from CTE3) 23 | order by 1 24 | 25 | -------------------------------------------------------------------------------------------------------------------------------------------------------- 26 | -- CTE- find highest rank and lowest rank in 2 separate columns using dense_rank() 27 | -- pull student_id from Exam table- note that student_id is not primary key, so use distnct 28 | -- pull name from Student table 29 | -- use Exam as left table because we don't want students who didn't take any exams 30 | -- use WHERE condition not in-> CTE 31 | 32 | with CTE as 33 | (select exam_id, student_id, score, 34 | dense_rank() over(partition by exam_id order by score desc) rank_highest, 35 | dense_rank() over(partition by exam_id order by score asc) rank_lowest 36 | from Exam) 37 | 38 | select distinct e.student_id, s.student_name 39 | from Exam e 40 | left join Student s 41 | on e.student_id = s.student_id 42 | where e.student_id not in 43 | (select student_id 44 | from CTE 45 | where rank_highest = 1 or rank_lowest = 1) 46 | order by 1 47 | 48 | 49 | -- no companies listed 50 | -------------------------------------------------------------------------------- /49-01767-find-the-subtasks-that-did-not-execute.sql: -------------------------------------------------------------------------------- 1 | -- using recursive CTE 2 | -- calculate subtask_count starting from given number, subtracting 1 till it reaches 1 3 | -- so subtasks count shouldn't be less than 2, because 2-1 = 1, and 1-1 will become 0 4 | -- use recursive cte to get all subtaks 5 | -- in the final query, pull all rows from cte, except the rows in Executed table 6 | 7 | with recursive cte as 8 | (select task_id, subtasks_count 9 | from Tasks 10 | 11 | union all 12 | 13 | select task_id, subtasks_count-1 14 | from cte 15 | where subtasks_count > 1) 16 | 17 | select task_id, subtasks_count as subtask_id 18 | from cte 19 | where (task_id, subtasks_count) not in (select * 20 | from Executed) 21 | 22 | -- google- 1 23 | -------------------------------------------------------------------------------- /50-01225-report-contiguous-dates.sql: -------------------------------------------------------------------------------- 1 | -- cte1- unioned both tables and arranged in ascending order of dates 2 | -- cte2- calculated rn and rnk and diff between them 3 | -- final query- picked min date as start date, max date as end date, grouped by status and diff 4 | -- rank()- gave them ranking based on their status ascending order date 5 | -- row_number()- ordered by date asc 6 | -- diff between them will be consistent if they are contiguous, hence group by diff 7 | -- when the status changes, again diff between them will be contiguous hence group by status to get different records for same status 8 | 9 | with cte1 as 10 | ((select fail_date as event_date, 'failed' as status 11 | from Failed) 12 | union all 13 | (select success_date as event_date, 'succeeded' as status 14 | from Succeeded)), 15 | cte2 as 16 | (select *, 17 | row_number() over(order by event_date) as rn, 18 | dense_rank() over (partition by status order by event_date) as rnk, 19 | row_number() over(order by event_date) - dense_rank() over (partition by status order by event_date) as diff 20 | from cte1 21 | where event_date between '2019-01-01' and '2019-12-31' 22 | order by 1) 23 | 24 | select status as period_state, min(event_date) as start_date, max(event_date) as end_date 25 | from cte2 26 | group by status, diff 27 | order by 2 28 | 29 | -- facebook- 1 30 | 31 | ------------------------------------------------------------------------------------------------------------------------------------------------------------ 32 | 33 | -- o/p of cte2 34 | 35 | | event_date | status | rn | rnk | diff | 36 | | ---------- | --------- | -- | --- | ---- | 37 | | 2019-01-01 | succeeded | 1 | 1 | 0 | 38 | | 2019-01-02 | succeeded | 2 | 2 | 0 | 39 | | 2019-01-03 | succeeded | 3 | 3 | 0 | 40 | | 2019-01-04 | failed | 4 | 1 | 3 | 41 | | 2019-01-05 | failed | 5 | 2 | 3 | 42 | | 2019-01-06 | succeeded | 6 | 4 | 2 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |