├── Basics ├── 1050_Actors_and_Directors_Who_Cooperated_At_Least_Three_Times.sql ├── 1069_Product_Sales_Analysis_II.sql ├── 1076_Project_Employees_II.sql ├── 1082_Sales_Analysis_I.sql ├── 1141_User_Activity_for_the_Past_30_Days_I.sql ├── 1148_Article_Views_I.sql ├── 1149_Article_Views_II.sql ├── 182_Duplicate_Emails.sql ├── 511_Game_Play_Analysis_I.sql ├── 578_Get_Highest_Answer_Rate_Question.sql ├── 584_Find_Customer_Referee.sql ├── 586_Customer_Placing_the_Largest_Number_of_Orders.sql ├── 595_Big_Countries.sql ├── 596_Classes_More_Than_5_Students.sql ├── 619_Biggest_Single_Number.sql └── 620_Not_Boring_Movies.sql ├── CASE-WHEN ├── 1126_Active_Businesses.sql ├── 1142_User_Activity_for_the_Past_30_Days_II.sql ├── 1158_Market_Analysis_I.sql ├── 1159_Market_Analysis_II.sql ├── 1173_Immediate_Food_Delivery_I.sql ├── 1174_Immediate_Food_Delivery_II.sql ├── 1193_Monthly_Transactions_I.sql ├── 1194_Tournament_Winners.sql ├── 1211_Queries_Quality_and_Percentage.sql ├── 1212_Team_Scores_in_Football_Tournament.sql ├── 1264_Page_Recommendations.sql ├── 1294_Weather_Type_in_Each_Country.sql ├── 1322_Ads_Performance.sql ├── 1393_Capital_Gain_Loss.sql ├── 1398_Customers_Who_Bought_Products_A_and_B_but_Not_C.sql ├── 262_Trips_and_Users.sql ├── 597_Friend_Requests_I_Overall_Acceptance_Rate.sql ├── 608_Tree_Node.sql ├── 610_Triangle_Judgement.sql ├── 615_Average_Salary_Departments_VS_Company.sql ├── 618_Students_Report_By_Geography.sql ├── 626_Exchange_Seats.sql └── 627_Swap_Salary.sql ├── Join ├── Advanced-Join │ ├── 1097_Game_Play_Analysis_V.sql │ ├── 1126_Active_Businesses.sql │ ├── 1127_User_Purchase_Platform.sql │ ├── 1159_Market_Analysis_II.sql │ ├── 1194_Tournament_Winners.sql │ ├── 1212_Team_Scores_in_Football_Tournament.sql │ ├── 1225_Report_Contiguous_Dates.sql │ ├── 1251_Average_Selling_Price.sql │ ├── 1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql │ ├── 1308_Running_Total_for_Different_Genders.sql │ ├── 1321_Restaurant_Growth.sql │ ├── 1369_Get_the_Second_Most_Recent_Activity.sql │ ├── 180_Consecutive_Numbers.sql │ ├── 196_Delete_Duplicate_Emails.sql │ ├── 534_Game_Play_Analysis_III.sql │ ├── 569_Median_Employee_Salary.sql │ ├── 579_Find_Cumulative_Salary_of_an_Employee.sql │ ├── 601_Human_Traffic_of_Stadium.sql │ ├── 603_Consecutive_Available_Seats.sql │ ├── 612_Shortest_Distance_in_a_Plane.sql │ └── 613_Shortest_Distance_in_a_Line.sql ├── Join.md └── Simple-Join │ ├── 1068_Product_Sales_Analysis_I.sql │ ├── 1070_Product_Sales_Analysis_III.sql │ ├── 1075_Project_Employees_I.sql │ ├── 1077_Project_Employees_III.sql │ ├── 1083_Sales_Analysis_II.sql │ ├── 1112_Highest_Grade_For_Each_Student.sql │ ├── 1132_Reported_Posts_II.sql │ ├── 1158_Market_Analysis_I.sql │ ├── 1164_Product_Price_at_a_Given_Date.sql │ ├── 1204_Last_Person_to_Fit_in_the_Elevator.sql │ ├── 1205_Monthly_Transactions_II.sql │ ├── 1241_Number_of_Comments_per_Post.sql │ ├── 1270_All_People_Report_to_the_Given_Manager.sql │ ├── 1280_Students_and_Examinations.sql │ ├── 1294_Weather_Type_in_Each_Country.sql │ ├── 1303_Find_the_Team_Size.sql │ ├── 1327_List_the_Products_Ordered_in_a_Period.sql │ ├── 1336_Number_of_Transactions_per_Visit.sql │ ├── 1350_Students_With_Invalid_Departments.sql │ ├── 1364_Number_of_Trusted_Contacts_of_a_Customer.sql │ ├── 1378_Replace_Employee_ID_With_The_Unique_Identifier.sql │ ├── 1384_Total_Sales_Amount_by_Year.sql │ ├── 1407_Top_Travellers.sql │ ├── 175_Combine_Two_Tables.sql │ ├── 181_Employees_Earning_More_Than_Their_Managers.sql │ ├── 183_Customers_Who_Never_Order.sql │ ├── 184_Department_Highest_Salary.sql │ ├── 197_Rising_Temperature.sql │ ├── 262_Trips_and_Users.sql │ ├── 512_Game_Play_Analysis_II.sql │ ├── 550_Game_Play_Analysis_IV.sql │ ├── 570_Managers_with_at_Least_5_Direct_Reports.sql │ ├── 574_Winning_Candidate.sql │ ├── 577_Employee_Bonus.sql │ ├── 580_Count_Student_Number_in_Departments.sql │ ├── 607_Sales_Person.sql │ ├── 614_Second_Degree_Follower.sql │ └── 615_Average_Salary_Departments_VS_Company.sql ├── OFFSET-FETCH ├── 1321_Restaurant_Growth.sql ├── 176_Second_Highest_Salary.sql ├── 177_Nth_Highest_Salary.sql └── OFFSET-FETCH.md ├── PIVOT-UNPIVOT ├── 1179_Reformat_Department_Table.sql ├── 1322_Ads_Performance.sql ├── 602_Friend_Requests_II_Who_Has_the_Most_Friends.sql └── 618_Students_Report_By_Geography.sql ├── Questions_by_ID ├── 1045_Customers_Who_Bought_All_Products.sql ├── 1050_Actors_and_Directors_Who_Cooperated_At_Least_Three_Times.sql ├── 1068_Product_Sales_Analysis_I.sql ├── 1069_Product_Sales_Analysis_II.sql ├── 1070_Product_Sales_Analysis_III.sql ├── 1075_Project_Employees_I.sql ├── 1076_Project_Employees_II.sql ├── 1077_Project_Employees_III.sql ├── 1082_Sales_Analysis_I.sql ├── 1083_Sales_Analysis_II.sql ├── 1084_Sales_Analysis_III.sql ├── 1097_Game_Play_Analysis_V.sql ├── 1098_Unpopular_Books.sql ├── 1107_New_Users_Daily_Count.sql ├── 1112_Highest_Grade_For_Each_Student.sql ├── 1113_Reported_Posts.sql ├── 1126_Active_Businesses.sql ├── 1127_User_Purchase_Platform.sql ├── 1132_Reported_Posts_II.sql ├── 1141_User_Activity_for_the_Past_30_Days_I.sql ├── 1142_User_Activity_for_the_Past_30_Days_II.sql ├── 1148_Article_Views_I.sql ├── 1149_Article_Views_II.sql ├── 1158_Market_Analysis_I.sql ├── 1159_Market_Analysis_II.sql ├── 1164_Product_Price_at_a_Given_Date.sql ├── 1173_Immediate_Food_Delivery_I.sql ├── 1174_Immediate_Food_Delivery_II.sql ├── 1179_Reformat_Department_Table.sql ├── 1193_Monthly_Transactions_I.sql ├── 1194_Tournament_Winners.sql ├── 1204_Last_Person_to_Fit_in_the_Elevator.sql ├── 1205_Monthly_Transactions_II.sql ├── 1211_Queries_Quality_and_Percentage.sql ├── 1212_Team_Scores_in_Football_Tournament.sql ├── 1225_Report_Contiguous_Dates.sql ├── 1241_Number_of_Comments_per_Post.sql ├── 1251_Average_Selling_Price.sql ├── 1264_Page_Recommendations.sql ├── 1270_All_People_Report_to_the_Given_Manager.sql ├── 1280_Students_and_Examinations.sql ├── 1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql ├── 1294_Weather_Type_in_Each_Country.sql ├── 1303_Find_the_Team_Size.sql ├── 1308_Running_Total_for_Different_Genders.sql ├── 1321_Restaurant_Growth.sql ├── 1322_Ads_Performance.sql ├── 1327_List_the_Products_Ordered_in_a_Period.sql ├── 1336_Number_of_Transactions_per_Visit.sql ├── 1341_Movie_Rating.sql ├── 1350_Students_With_Invalid_Departments.sql ├── 1355_Activity_Participants.sql ├── 1364_Number_of_Trusted_Contacts_of_a_Customer.sql ├── 1369_Get_the_Second_Most_Recent_Activity.sql ├── 1378_Replace_Employee_ID_With_The_Unique_Identifier.sql ├── 1384_Total_Sales_Amount_by_Year.sql ├── 1393_Capital_Gain_Loss.sql ├── 1398_Customers_Who_Bought_Products_A_and_B_but_Not_C.sql ├── 1407_Top_Travellers.sql ├── 1412_Find_The_Quiet_Students_in_All_Exams.sql ├── 175_Combine_Two_Tables.sql ├── 176_Second_Highest_Salary.sql ├── 177_Nth_Highest_Salary.sql ├── 178_Rank_Scores.sql ├── 180_Consecutive_Numbers.sql ├── 181_Employees_Earning_More_Than_Their_Managers.sql ├── 182_Duplicate_Emails.sql ├── 183_Customers_Who_Never_Order.sql ├── 184_Department_Highest_Salary.sql ├── 185_Department_Top_Three_Salaries.sql ├── 196_Delete_Duplicate_Emails.sql ├── 197_Rising_Temperature.sql ├── 262_Trips_and_Users.sql ├── 511_Game_Play_Analysis_I.sql ├── 512_Game_Play_Analysis_II.sql ├── 534_Game_Play_Analysis_III.sql ├── 550_Game_Play_Analysis_IV.sql ├── 569_Median_Employee_Salary.sql ├── 570_Managers_with_at_Least_5_Direct_Reports.sql ├── 571_Find_Median_Given_Frequency_of_Numbers.sql ├── 574_Winning_Candidate.sql ├── 577_Employee_Bonus.sql ├── 578_Get_Highest_Answer_Rate_Question.sql ├── 579_Find_Cumulative_Salary_of_an_Employee.sql ├── 580_Count_Student_Number_in_Departments.sql ├── 584_Find_Customer_Referee.sql ├── 585_Investments_in_2016.sql ├── 586_Customer_Placing_the_Largest_Number_of_Orders.sql ├── 595_Big_Countries.sql ├── 596_Classes_More_Than_5_Students.sql ├── 597_Friend_Requests_I_Overall_Acceptance_Rate.sql ├── 601_Human_Traffic_of_Stadium.sql ├── 602_Friend_Requests_II_Who_Has_the_Most_Friends.sql ├── 603_Consecutive_Available_Seats.sql ├── 607_Sales_Person.sql ├── 608_Tree_Node.sql ├── 610_Triangle_Judgement.sql ├── 612_Shortest_Distance_in_a_Plane.sql ├── 613_Shortest_Distance_in_a_Line.sql ├── 614_Second_Degree_Follower.sql ├── 615_Average_Salary_Departments_VS_Company.sql ├── 618_Students_Report_By_Geography.sql ├── 619_Biggest_Single_Number.sql ├── 620_Not_Boring_Movies.sql ├── 626_Exchange_Seats.sql └── 627_Swap_Salary.sql ├── Readme.md ├── SQL-Command ├── 196_Delete_Duplicate_Emails.sql └── 627_Swap_Salary.sql ├── Subquery ├── Advanced-Subquery │ ├── 1077_Project_Employees_III.sql │ ├── 1127_User_Purchase_Platform.sql │ ├── 1159_Market_Analysis_II.sql │ ├── 1164_Product_Price_at_a_Given_Date.sql │ ├── 1194_Tournament_Winners.sql │ ├── 1205_Monthly_Transactions_II.sql │ ├── 1270_All_People_Report_to_the_Given_Manager.sql │ ├── 1398_Customers_Who_Bought_Products_A_and_B_but_Not_C.sql │ ├── 262_Trips_and_Users.sql │ ├── 550_Game_Play_Analysis_IV.sql │ ├── 569_Median_Employee_Salary.sql │ ├── 585_Investments_in_2016.sql │ ├── 597_Friend_Requests_I_Overall_Acceptance_Rate.sql │ └── 601_Human_Traffic_of_Stadium.sql ├── Recursive-CTE │ ├── 1270_All_People_Report_to_the_Given_Manager.sql │ ├── 1336_Number_of_Transactions_per_Visit.sql │ └── 1384_Total_Sales_Amount_by_Year.sql ├── Simple-Subquery │ ├── 1045_Customers_Who_Bought_All_Products.sql │ ├── 1070_Product_Sales_Analysis_III.sql │ ├── 1083_Sales_Analysis_II.sql │ ├── 1084_Sales_Analysis_III.sql │ ├── 1097_Game_Play_Analysis_V.sql │ ├── 1098_Unpopular_Books.sql │ ├── 1107_New_Users_Daily_Count.sql │ ├── 1112_Highest_Grade_For_Each_Student.sql │ ├── 1126_Active_Businesses.sql │ ├── 1132_Reported_Posts_II.sql │ ├── 1142_User_Activity_for_the_Past_30_Days_II.sql │ ├── 1158_Market_Analysis_I.sql │ ├── 1174_Immediate_Food_Delivery_II.sql │ ├── 1204_Last_Person_to_Fit_in_the_Elevator.sql │ ├── 1225_Report_Contiguous_Dates.sql │ ├── 1264_Page_Recommendations.sql │ ├── 1280_Students_and_Examinations.sql │ ├── 1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql │ ├── 1294_Weather_Type_in_Each_Country.sql │ ├── 1321_Restaurant_Growth.sql │ ├── 1322_Ads_Performance.sql │ ├── 1336_Number_of_Transactions_per_Visit.sql │ ├── 1341_Movie_Rating.sql │ ├── 1350_Students_With_Invalid_Departments.sql │ ├── 1355_Activity_Participants.sql │ ├── 1364_Number_of_Trusted_Contacts_of_a_Customer.sql │ ├── 1369_Get_the_Second_Most_Recent_Activity.sql │ ├── 176_Second_Highest_Salary.sql │ ├── 183_Customers_Who_Never_Order.sql │ ├── 184_Department_Highest_Salary.sql │ ├── 196_Delete_Duplicate_Emails.sql │ ├── 197_Rising_Temperature.sql │ ├── 512_Game_Play_Analysis_II.sql │ ├── 569_Median_Employee_Salary.sql │ ├── 570_Managers_with_at_Least_5_Direct_Reports.sql │ ├── 571_Find_Median_Given_Frequency_of_Numbers.sql │ ├── 574_Winning_Candidate.sql │ ├── 579_Find_Cumulative_Salary_of_an_Employee.sql │ ├── 580_Count_Student_Number_in_Departments.sql │ ├── 602_Friend_Requests_II_Who_Has_the_Most_Friends.sql │ ├── 603_Consecutive_Available_Seats.sql │ ├── 607_Sales_Person.sql │ ├── 608_Tree_Node.sql │ ├── 613_Shortest_Distance_in_a_Line.sql │ ├── 614_Second_Degree_Follower.sql │ ├── 615_Average_Salary_Departments_VS_Company.sql │ ├── 618_Students_Report_By_Geography.sql │ └── 626_Exchange_Seats.sql └── Subquery.md ├── Variable ├── 1098_Unpopular_Books.sql ├── 1107_New_Users_Daily_Count.sql ├── 1113_Reported_Posts.sql └── 597_Friend_Requests_I_Overall_Acceptance_Rate.sql └── Window-Function ├── 1070_Product_Sales_Analysis_III.sql ├── 1077_Project_Employees_III.sql ├── 1107_New_Users_Daily_Count.sql ├── 1112_Highest_Grade_For_Each_Student.sql ├── 1126_Active_Businesses.sql ├── 1127_User_Purchase_Platform.sql ├── 1159_Market_Analysis_II.sql ├── 1164_Product_Price_at_a_Given_Date.sql ├── 1174_Immediate_Food_Delivery_II.sql ├── 1194_Tournament_Winners.sql ├── 1204_Last_Person_to_Fit_in_the_Elevator.sql ├── 1225_Report_Contiguous_Dates.sql ├── 1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql ├── 1303_Find_the_Team_Size.sql ├── 1308_Running_Total_for_Different_Genders.sql ├── 1321_Restaurant_Growth.sql ├── 1355_Activity_Participants.sql ├── 1369_Get_the_Second_Most_Recent_Activity.sql ├── 1412_Find_The_Quiet_Students_in_All_Exams.sql ├── 176_Second_Highest_Salary.sql ├── 177_Nth_Highest_Salary.sql ├── 178_Rank_Scores.sql ├── 180_Consecutive_Numbers.sql ├── 184_Department_Highest_Salary.sql ├── 185_Department_Top_Three_Salaries.sql ├── 197_Rising_Temperature.sql ├── 512_Game_Play_Analysis_II.sql ├── 534_Game_Play_Analysis_III.sql ├── 550_Game_Play_Analysis_IV.sql ├── 569_Median_Employee_Salary.sql ├── 571_Find_Median_Given_Frequency_of_Numbers.sql ├── 579_Find_Cumulative_Salary_of_an_Employee.sql ├── 585_Investments_in_2016.sql ├── 601_Human_Traffic_of_Stadium.sql ├── 603_Consecutive_Available_Seats.sql ├── 613_Shortest_Distance_in_a_Line.sql ├── 615_Average_Salary_Departments_VS_Company.sql ├── 618_Students_Report_By_Geography.sql └── Window-Function.md /Basics/1050_Actors_and_Directors_Who_Cooperated_At_Least_Three_Times.sql: -------------------------------------------------------------------------------- 1 | SELECT actor_id, director_id 2 | FROM ActorDirector 3 | GROUP BY actor_id, director_id 4 | HAVING COUNT(*) >= 3; 5 | -------------------------------------------------------------------------------- /Basics/1069_Product_Sales_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | SELECT product_id, SUM(quantity) AS total_quantity 2 | FROM Sales 3 | GROUP BY product_id; 4 | -------------------------------------------------------------------------------- /Basics/1076_Project_Employees_II.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 WITH TIES project_id 2 | FROM Project 3 | GROUP BY project_id 4 | ORDER BY COUNT(employee_id) DESC; 5 | -------------------------------------------------------------------------------- /Basics/1082_Sales_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 WITH TIES seller_id 2 | FROM Sales 3 | GROUP BY seller_id 4 | ORDER BY SUM(price) DESC; 5 | -------------------------------------------------------------------------------- /Basics/1141_User_Activity_for_the_Past_30_Days_I.sql: -------------------------------------------------------------------------------- 1 | SELECT activity_date AS day, COUNT(DISTINCT user_id) AS active_users 2 | FROM Activity 3 | GROUP BY activity_date 4 | HAVING activity_date BETWEEN DATEADD(day,-29,'2019-07-27') and '2019-07-27'; 5 | -------------------------------------------------------------------------------- /Basics/1148_Article_Views_I.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT author_id AS id 2 | FROM Views 3 | WHERE author_id = viewer_id 4 | ORDER BY id; 5 | -------------------------------------------------------------------------------- /Basics/1149_Article_Views_II.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT viewer_id AS id 2 | FROM Views 3 | GROUP BY viewer_id, view_date 4 | -- When viewer viewed the same article more than once in the same day, using DISTINCT could avoid count that article twice 5 | HAVING COUNT(DISTINCT article_id) > 1 6 | ORDER BY id; 7 | -------------------------------------------------------------------------------- /Basics/182_Duplicate_Emails.sql: -------------------------------------------------------------------------------- 1 | SELECT email 2 | FROM person 3 | GROUP BY email 4 | HAVING COUNT(*) > 1; 5 | -------------------------------------------------------------------------------- /Basics/511_Game_Play_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | SELECT player_id, MIN(event_date) AS first_login 2 | FROM activity 3 | GROUP BY player_id; 4 | -------------------------------------------------------------------------------- /Basics/578_Get_Highest_Answer_Rate_Question.sql: -------------------------------------------------------------------------------- 1 | -- Note: answer rate = answer actions / total non-answer actions 2 | -- If LeetCode change answer for the test case, plz let me know 3 | 4 | SELECT TOP 1 question_id AS survey_log 5 | FROM survey_log 6 | GROUP BY question_id 7 | ORDER BY COUNT(answer_id)*1.0/(COUNT(*)-COUNT(answer_id)) DESC; 8 | -------------------------------------------------------------------------------- /Basics/584_Find_Customer_Referee.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Basics 2 | SELECT name 3 | FROM customer 4 | WHERE ISNULL(referee_id,0) != 2; 5 | 6 | 7 | 8 | -- Solution 2: Basics 9 | SELECT name 10 | FROM customer 11 | WHERE COALESCE(referee_id,0) != 2; 12 | 13 | 14 | 15 | -- Solution 3: Basics 16 | SELECT name 17 | FROM customer 18 | WHERE referee_id != 2 OR referee_id IS NULL; 19 | -------------------------------------------------------------------------------- /Basics/586_Customer_Placing_the_Largest_Number_of_Orders.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 customer_number 2 | FROM orders 3 | GROUP BY customer_number 4 | ORDER BY COUNT(*) DESC; 5 | -------------------------------------------------------------------------------- /Basics/595_Big_Countries.sql: -------------------------------------------------------------------------------- 1 | SELECT name, population, area 2 | FROM World 3 | WHERE area > 3000000 OR population > 25000000; 4 | -------------------------------------------------------------------------------- /Basics/596_Classes_More_Than_5_Students.sql: -------------------------------------------------------------------------------- 1 | SELECT class 2 | FROM courses 3 | GROUP BY class 4 | HAVING COUNT(DISTINCT student) >= 5; 5 | -------------------------------------------------------------------------------- /Basics/619_Biggest_Single_Number.sql: -------------------------------------------------------------------------------- 1 | SELECT MAX(num) AS num 2 | FROM ( 3 | -- Select numbers appear only once 4 | SELECT num 5 | FROM my_numbers 6 | GROUP BY num 7 | HAVING COUNT(*) = 1 8 | ) tb1; 9 | -------------------------------------------------------------------------------- /Basics/620_Not_Boring_Movies.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM cinema 3 | WHERE id % 2 = 1 AND description != 'boring' 4 | ORDER BY rating DESC; 5 | -------------------------------------------------------------------------------- /CASE-WHEN/1126_Active_Businesses.sql: -------------------------------------------------------------------------------- 1 | -- calculate average occurences of event types amont all business 2 | WITH tb1 AS ( 3 | SELECT *, 4 | AVG(occurences*1.0) OVER (PARTITION BY event_type) AS avg_oc 5 | FROM Events 6 | ) 7 | 8 | SELECT business_id 9 | FROM tb1 10 | GROUP BY business_id 11 | -- count number of event types of a business with occurences 12 | -- greater than the average occurences of that event type among all businesses 13 | HAVING SUM(CASE WHEN occurences > avg_oc THEN 1 ELSE 0 END) > 1; 14 | -------------------------------------------------------------------------------- /CASE-WHEN/1142_User_Activity_for_the_Past_30_Days_II.sql: -------------------------------------------------------------------------------- 1 | SELECT CAST( 2 | COUNT(DISTINCT session_id)*1.0 3 | / 4 | IIF(COUNT(DISTINCT user_id) > 0,COUNT(DISTINCT user_id) ,1) 5 | AS DECIMAL(10,2) 6 | ) AS average_sessions_per_user 7 | FROM Activity 8 | WHERE activity_date BETWEEN DATEADD(day,-29,'2019-07-27') and '2019-07-27'; 9 | -------------------------------------------------------------------------------- /CASE-WHEN/1158_Market_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | SELECT u.user_id AS buyer_id, u.join_date AS join_date, 2 | SUM(CASE WHEN YEAR(order_date) = 2019 THEN 1 ELSE 0 END) AS orders_in_2019 3 | FROM Users u 4 | LEFT JOIN Orders o 5 | ON u.user_id = o.buyer_id 6 | GROUP BY u.user_id, u.join_date; 7 | -------------------------------------------------------------------------------- /CASE-WHEN/1159_Market_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, Join, CASE WHEN 2 | -- get item_id of the second item (by date) they sold for each user 3 | WITH tb1 AS ( 4 | SELECT seller_id, item_id 5 | FROM ( 6 | SELECT seller_id, item_id, 7 | ROW_NUMBER() OVER (PARTITION BY seller_id ORDER BY order_date) AS r 8 | FROM Orders 9 | ) rank 10 | WHERE r = 2 11 | ) 12 | 13 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 14 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 15 | SELECT u.user_id AS seller_id, 16 | CASE 17 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 18 | ELSE 'no' 19 | END AS '2nd_item_fav_brand' 20 | FROM Users u 21 | LEFT JOIN tb1 22 | ON u.user_id = tb1.seller_id 23 | LEFT JOIN Items i 24 | ON tb1.item_id = i.item_id; 25 | 26 | 27 | 28 | -- Solution 2: Join, Subquery, CASE WHEN 29 | -- get item_id of the second item (by date) they sold for each user (having only two sales records on or before o1.order_date) 30 | WITH tb1 AS ( 31 | SELECT o1.seller_id, o1.item_id 32 | FROM Orders o1 33 | JOIN orders o2 34 | ON o1.seller_id = o2.seller_id AND o1.order_date >= o2.order_date 35 | GROUP BY o1.seller_id, o1.order_date, o1.item_id 36 | HAVING COUNT(*) = 2 37 | ) 38 | 39 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 40 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 41 | SELECT u.user_id AS seller_id, 42 | CASE 43 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 44 | ELSE 'no' 45 | END AS '2nd_item_fav_brand' 46 | FROM Users u 47 | LEFT JOIN tb1 48 | ON u.user_id = tb1.seller_id 49 | LEFT JOIN Items i 50 | ON tb1.item_id = i.item_id; 51 | -------------------------------------------------------------------------------- /CASE-WHEN/1173_Immediate_Food_Delivery_I.sql: -------------------------------------------------------------------------------- 1 | SELECT CAST( 2 | AVG( 3 | -- using 100.0 rather than 100 is to ensure the type of number is float 4 | -- so that the number will keep digits after the decimal point when averaging 5 | CASE 6 | WHEN order_date = customer_pref_delivery_date THEN 100.0 7 | ELSE 0 8 | END 9 | ) 10 | AS DECIMAL(5,2) 11 | ) AS immediate_percentage 12 | FROM Delivery; 13 | -------------------------------------------------------------------------------- /CASE-WHEN/1174_Immediate_Food_Delivery_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, CASE WHEN 2 | WITH tb1 AS ( 3 | -- fod refers to first order date, and fdd refers to first delivery date 4 | SELECT MIN(order_date) AS fod, MIN(customer_pref_delivery_date) AS fdd 5 | FROM Delivery 6 | GROUP BY customer_id 7 | ) 8 | 9 | -- Since it is guaranteed that a customer has exactly one first order, 10 | -- when fod = fdd, the first order of that customer must be immediate order 11 | SELECT CAST( 12 | AVG( 13 | CASE 14 | WHEN fod = fdd THEN 100.0 15 | ELSE 0 16 | END 17 | ) 18 | AS DECIMAL(5,2) 19 | ) AS immediate_percentage 20 | FROM tb1; 21 | 22 | 23 | 24 | -- Solution 2: Window Function, Subquery, CASE WHEN 25 | WITH tb1 AS ( 26 | SELECT order_date, customer_pref_delivery_date, 27 | -- identify first order of each customer 28 | ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS r 29 | FROM delivery 30 | ) 31 | 32 | SELECT CAST( 33 | AVG( 34 | CASE 35 | WHEN order_date = customer_pref_delivery_date THEN 100.0 36 | ELSE 0 37 | END 38 | ) 39 | AS DECIMAL(5,2) 40 | ) AS immediate_percentage 41 | FROM tb1 42 | WHERE r = 1; 43 | -------------------------------------------------------------------------------- /CASE-WHEN/1193_Monthly_Transactions_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN 2 | SELECT LEFT(trans_date,7) AS month, country, 3 | COUNT(id) AS trans_count, 4 | SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count, 5 | SUM(amount) AS trans_total_amount, 6 | SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amount 7 | FROM Transactions 8 | GROUP BY LEFT(trans_date,7), country; 9 | 10 | 11 | 12 | -- Solution 2: CASE WHEN 13 | -- Using FORMAT to increase stability 14 | SELECT FORMAT(trans_date,'yyyy-MM') AS month, country, 15 | COUNT(id) AS trans_count, 16 | SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count, 17 | SUM(amount) AS trans_total_amount, 18 | SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amount 19 | FROM Transactions 20 | GROUP BY FORMAT(trans_date,'yyyy-MM'), country; 21 | -------------------------------------------------------------------------------- /CASE-WHEN/1211_Queries_Quality_and_Percentage.sql: -------------------------------------------------------------------------------- 1 | SELECT query_name, 2 | CAST( 3 | AVG(rating*1.0/position) 4 | AS DECIMAL(10,2) 5 | ) AS quality, 6 | CAST( 7 | AVG(CASE WHEN rating < 3 THEN 100.0 ELSE 0 END) 8 | AS DECIMAL(10,2) 9 | ) AS poor_query_percentage 10 | FROM Queries 11 | GROUP BY query_name; 12 | -------------------------------------------------------------------------------- /CASE-WHEN/1212_Team_Scores_in_Football_Tournament.sql: -------------------------------------------------------------------------------- 1 | SELECT team_id, team_name, 2 | SUM( 3 | CASE WHEN team_id = host_team AND host_goals > guest_goals THEN 3 4 | WHEN team_id = guest_team AND guest_goals > host_goals THEN 3 5 | WHEN host_goals = guest_goals THEN 1 6 | ELSE 0 7 | END 8 | ) AS num_points 9 | FROM Teams t 10 | LEFT JOIN Matches m 11 | ON t.team_id = m.host_team OR t.team_id = m.guest_team 12 | GROUP BY team_id, team_name 13 | ORDER BY num_points DESC, team_id; 14 | -------------------------------------------------------------------------------- /CASE-WHEN/1264_Page_Recommendations.sql: -------------------------------------------------------------------------------- 1 | WITH f AS ( 2 | SELECT CASE WHEN user1_id = 1 THEN user2_id ELSE user1_id END AS fid 3 | FROM Friendship 4 | WHERE user1_id = 1 OR user2_id =1 5 | ) 6 | 7 | SELECT DISTINCT page_id AS recommended_page 8 | FROM Likes 9 | WHERE user_id IN (SELECT * FROM f) 10 | EXCEPT 11 | SELECT page_id 12 | FROM Likes 13 | WHERE user_id = 1; 14 | -------------------------------------------------------------------------------- /CASE-WHEN/1294_Weather_Type_in_Each_Country.sql: -------------------------------------------------------------------------------- 1 | SELECT c.country_name, w.weather_type 2 | FROM ( 3 | SELECT country_id, 4 | CASE 5 | WHEN AVG(weather_state*1.0) <= 15 THEN 'Cold' 6 | WHEN AVG(weather_state*1.0) >= 25 THEN 'Hot' 7 | ELSE 'Warm' 8 | END AS weather_type 9 | FROM Weather 10 | WHERE LEFT(day,7) = '2019-11' 11 | GROUP BY country_id 12 | ) w 13 | JOIN Countries c 14 | ON w.country_id = c.country_id; 15 | -------------------------------------------------------------------------------- /CASE-WHEN/1322_Ads_Performance.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN 2 | SELECT ad_id, 3 | CAST( 4 | ISNULL( 5 | AVG( 6 | CASE 7 | WHEN action = 'Clicked' THEN 100.0 8 | WHEN action = 'Viewed' THEN 0 9 | ELSE NULL 10 | END 11 | ) 12 | ,0) 13 | AS DECIMAL(5,2) 14 | ) AS ctr 15 | FROM Ads 16 | GROUP BY ad_id 17 | ORDER BY ctr DESC, ad_id; 18 | 19 | 20 | 21 | -- Solution 2: Subquery, PIVOT/UNPIVOT, CASE WHEN 22 | WITH tb1 AS ( 23 | SELECT ad_id, [Clicked], [Viewed], [Ignored] 24 | FROM Ads 25 | PIVOT ( 26 | COUNT(action) FOR action IN ([Clicked], [Viewed], [Ignored]) 27 | ) pvt 28 | ) 29 | 30 | SELECT ad_id, 31 | CASE 32 | WHEN SUM(Clicked+Viewed) = 0 THEN 0.0 33 | ELSE CAST(SUM(Clicked)*100.0/SUM(Clicked+Viewed) AS DECIMAL(5,2)) 34 | END AS ctr 35 | FROM tb1 36 | GROUP BY ad_id 37 | ORDER BY ctr DESC, ad_id; 38 | -------------------------------------------------------------------------------- /CASE-WHEN/1393_Capital_Gain_Loss.sql: -------------------------------------------------------------------------------- 1 | -- For this question, the last operation of a stock is always "sell" 2 | -- and it is guaranteed that every "sell" has a "buy" before it, 3 | -- so we could simplify this to a CASE WHEN questions, otherwise, WINDOW FUNCTION could be a better choice 4 | SELECT stock_name, 5 | SUM( 6 | CASE 7 | WHEN operation = 'Buy' THEN -price 8 | ELSE price END 9 | ) AS capital_gain_loss 10 | FROM Stocks 11 | GROUP BY stock_name; 12 | -------------------------------------------------------------------------------- /CASE-WHEN/1398_Customers_Who_Bought_Products_A_and_B_but_Not_C.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT DISTINCT customer_id, product_name, 3 | CASE 4 | WHEN product_name IN ('A','B') THEN 1 5 | WHEN product_name = 'C' THEN -1 6 | ELSE 0 7 | END AS c 8 | FROM Orders 9 | ) 10 | 11 | SELECT * 12 | FROM Customers 13 | WHERE customer_id IN ( 14 | SELECT customer_id 15 | FROM tb1 16 | GROUP BY customer_id 17 | HAVING SUM(c) = 2 18 | ); 19 | -------------------------------------------------------------------------------- /CASE-WHEN/262_Trips_and_Users.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, CASE WHEN 2 | WITH t1 AS ( 3 | SELECT request_at, 4 | CASE 5 | WHEN status = 'completed' then 0 6 | ELSE 1.0 7 | END AS status 8 | FROM trips t 9 | -- filter our banned client and driver and limit time frame 10 | WHERE client_id NOT IN (SELECT users_id FROM users WHERE banned = 'Yes') 11 | AND driver_id NOT IN (SELECT users_id FROM users WHERE banned = 'Yes') 12 | AND request_at BETWEEN '2013-10-01' AND '2013-10-03' 13 | ) 14 | 15 | SELECT request_at AS 'Day', 16 | CAST(AVG(status) AS DECIMAL(4,2)) AS 'Cancellation Rate' 17 | FROM t1 18 | GROUP BY request_at; 19 | 20 | 21 | 22 | -- Solution 2: Join, CASE WHEN 23 | SELECT t.Request_at AS 'Day', 24 | CAST( 25 | AVG(CASE 26 | WHEN status = 'completed' then 0 27 | ELSE 1.0 28 | END) 29 | AS DECIMAL(3,2) 30 | ) AS 'Cancellation Rate' 31 | FROM Trips AS t 32 | INNER JOIN Users c 33 | ON t.Client_Id=c.Users_Id 34 | INNER JOIN Users d 35 | ON t.Driver_Id=d.Users_Id 36 | -- filter our banned client and driver and limit time frame 37 | WHERE c.Banned='no' AND 38 | d.Banned='no' AND 39 | t.Request_at BETWEEN '2013-10-01' AND '2013-10-03' 40 | GROUP BY t.Request_at; 41 | -------------------------------------------------------------------------------- /CASE-WHEN/597_Friend_Requests_I_Overall_Acceptance_Rate.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN 2 | SELECT 3 | CAST( 4 | CASE 5 | WHEN COUNT(DISTINCT CONCAT(sender_id,'_',send_to_id)) = 0 THEN 0 6 | ELSE 7 | COUNT(DISTINCT CONCAT(requester_id,'_',accepter_id))*1.0 8 | / 9 | COUNT(DISTINCT CONCAT(sender_id,'_',send_to_id)) 10 | END 11 | AS DECIMAL(3,2) 12 | ) AS accept_rate 13 | FROM request_accepted, friend_request; 14 | 15 | 16 | 17 | -- Solution 2: CASE WHEN, Subquery 18 | WITH send AS ( 19 | SELECT distinct sender_id, send_to_id 20 | FROM friend_request 21 | ), 22 | accept AS ( 23 | SELECT distinct requester_id, accepter_id 24 | FROM request_accepted 25 | ) 26 | 27 | SELECT 28 | CASE 29 | WHEN (SELECT COUNT(*) FROM send)=0 THEN 0.0 30 | ELSE 31 | CAST( 32 | (SELECT COUNT(*) FROM accept)*1.0/(SELECT COUNT(*) FROM send) 33 | AS DECIMAL(3,2) 34 | ) 35 | END AS accept_rate; 36 | 37 | 38 | 39 | -- Solution 3: Variable, Subquery, IIF 40 | DECLARE @accept DECIMAL(10,2); 41 | DECLARE @send DECIMAL(10,2); 42 | 43 | SELECT @accept = COUNT(*) 44 | FROM ( 45 | SELECT DISTINCT requester_id, accepter_id 46 | FROM request_accepted 47 | ) AS tb1; 48 | 49 | SELECT @send = IIF(COUNT(*) < 1, 1, COUNT(*)) 50 | FROM ( 51 | SELECT DISTINCT sender_id, send_to_id 52 | FROM friend_request 53 | ) AS tb2; 54 | 55 | Select CAST(@accept / @send AS DECIMAL(3,2)) AS accept_rate; 56 | -------------------------------------------------------------------------------- /CASE-WHEN/608_Tree_Node.sql: -------------------------------------------------------------------------------- 1 | SELECT id, 2 | CASE 3 | WHEN p_id IS NULL THEN 'Root' 4 | WHEN id IN (SELECT p_id FROM tree) THEN 'Inner' 5 | ELSE 'Leaf' 6 | END AS Type 7 | FROM tree 8 | ORDER BY id; 9 | -------------------------------------------------------------------------------- /CASE-WHEN/610_Triangle_Judgement.sql: -------------------------------------------------------------------------------- 1 | SELECT *, 2 | CASE 3 | -- the sum of any 2 sides of a triangle must be greater than the measure of the third side 4 | WHEN x+y > z AND y+z > x AND z+x > y THEN 'Yes' 5 | ELSE 'No' 6 | END AS triangle 7 | FROM triangle; 8 | -------------------------------------------------------------------------------- /CASE-WHEN/615_Average_Salary_Departments_VS_Company.sql: -------------------------------------------------------------------------------- 1 | -- If need to extract date in other format in the future, FORMAT() function could be used 2 | 3 | -- Solution 1: Join, Window Function, Subquery, CASE WHEN 4 | WITH tb1 AS ( 5 | SELECT DISTINCT department_id, LEFT(pay_date,7) AS pay_month, 6 | AVG(amount) OVER (PARTITION BY department_id, LEFT(pay_date,7))AS avg_dept, 7 | AVG(amount) OVER (PARTITION BY LEFT(pay_date,7)) AS avg_comp 8 | FROM salary s 9 | JOIN employee e 10 | ON s.employee_id = e.employee_id 11 | ) 12 | 13 | SELECT pay_month, department_id, 14 | CASE 15 | WHEN avg_dept > avg_comp THEN 'higher' 16 | WHEN avg_dept < avg_comp THEN 'lower' 17 | ELSE 'same' 18 | END AS comparison 19 | FROM tb1; 20 | 21 | 22 | 23 | -- Solution 2: Join, Subquery, CASE WHEN 24 | WITH dept AS ( 25 | SELECT e.department_id, LEFT(s.pay_date,7) AS pay_month, AVG(s.amount) AS avg_dept 26 | FROM salary s 27 | JOIN employee e 28 | ON s.employee_id = e.employee_id 29 | GROUP BY e.department_id, LEFT(s.pay_date,7) 30 | ), 31 | comp AS ( 32 | SELECT LEFT(pay_date,7) AS pay_month, AVG(amount) AS avg_comp 33 | FROM salary 34 | GROUP BY LEFT(pay_date,7) 35 | ) 36 | 37 | SELECT d.department_id, d.pay_month, 38 | CASE 39 | WHEN d.avg_dept > c.avg_comp THEN 'higher' 40 | WHEN d.avg_dept < c.avg_comp THEN 'lower' 41 | ELSE 'same' 42 | END AS comparison 43 | FROM dept d 44 | JOIN comp c 45 | ON d.pay_month = c.pay_month; 46 | -------------------------------------------------------------------------------- /CASE-WHEN/618_Students_Report_By_Geography.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | -- Numbering student from each continent separately by their name alphabetically 3 | SELECT ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r, 4 | IIF(continent = 'America', name, NULL) AS America, 5 | IIF(continent = 'Asia', name, NULL) AS Asia, 6 | IIF(continent = 'Europe', name, NULL) AS Europe 7 | FROM student 8 | ) 9 | 10 | -- Since numbering is unique in each continent, 11 | -- in each numbering group (1-3 rows), there ia only one cell contained student name in each column (e.g. America, Asia, Europe) 12 | SELECT MIN(America) AS America, MIN(Asia) AS Asia, MIN(Europe) AS Europe 13 | FROM tb1 14 | GROUP BY r; 15 | -------------------------------------------------------------------------------- /CASE-WHEN/626_Exchange_Seats.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | CASE 3 | WHEN id % 2 = 1 AND id = (SELECT MAX(id) FROM seat) THEN id 4 | WHEN id % 2 = 1 THEN id + 1 5 | ELSE id - 1 6 | END AS id, 7 | student 8 | FROM seat 9 | ORDER BY 1; 10 | -------------------------------------------------------------------------------- /CASE-WHEN/627_Swap_Salary.sql: -------------------------------------------------------------------------------- 1 | UPDATE salary 2 | SET sex = CASE WHEN sex = 'm' THEN 'f' ELSE 'm' END; 3 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1097_Game_Play_Analysis_V.sql: -------------------------------------------------------------------------------- 1 | SELECT a1.event_date AS install_dt, 2 | COUNT(DISTINCT a1.player_id) AS installs, 3 | CAST( 4 | -- The number of players logged back in the day after / the number of players first logined on that date 5 | -- using DISTINCT to avoid double counting 6 | COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id) 7 | AS DECIMAL(3,2) 8 | ) AS Day1_retention 9 | FROM ( 10 | -- get install date of each player 11 | SELECT player_id, MIN(event_date) AS event_date 12 | FROM Activity 13 | GROUP BY player_id 14 | ) a1 15 | -- if a player logged back in on the day right after install date, he/she would get a matched record from table a2 16 | LEFT JOIN Activity a2 17 | ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date 18 | GROUP BY a1.event_date; 19 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1126_Active_Businesses.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, CASE WHEN 2 | -- calculate average occurences of event types amont all business 3 | WITH tb1 AS ( 4 | SELECT *, 5 | AVG(occurences*1.0) OVER (PARTITION BY event_type) AS avg_oc 6 | FROM Events 7 | ) 8 | 9 | SELECT business_id 10 | FROM tb1 11 | GROUP BY business_id 12 | -- count number of event types of a business with occurences 13 | -- greater than the average occurences of that event type among all businesses 14 | HAVING SUM(CASE WHEN occurences > avg_oc THEN 1 ELSE 0 END) > 1; 15 | 16 | 17 | 18 | -- Solution 2: Subquery, Join 19 | -- calculate average occurences of event types amont all business 20 | WITH tb1 AS ( 21 | SELECT event_type, AVG(occurences*1.0) AS avg_oc 22 | FROM Events 23 | GROUP BY event_type 24 | ) 25 | 26 | SELECT business_id 27 | FROM Events e 28 | JOIN tb1 29 | -- use join to keep only records in which event type of a business with occurences 30 | -- greater than the average occurences of that event type among all businesses 31 | ON e.event_type = tb1.event_type AND e.occurences > tb1.avg_oc 32 | GROUP BY business_id 33 | HAVING COUNT(*) > 1; 34 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1127_User_Purchase_Platform.sql: -------------------------------------------------------------------------------- 1 | -- judge whether user used mobile only, desktop only or both mobile and desktop together for each date 2 | WITH tb1 AS ( 3 | SELECT user_id,spend_date,amount, 4 | CASE 5 | WHEN COUNT(*) OVER (PARTITION BY user_id, spend_date) = 1 THEN platform 6 | ELSE 'both' 7 | END AS platform 8 | FROM Spending 9 | ), 10 | -- calculate the total amount each user spent by date along with platform information 11 | tb2 AS ( 12 | SELECT spend_date, platform, 13 | SUM(amount) AS total_amount, 14 | COUNT(DISTINCT user_id) AS total_users 15 | FROM tb1 16 | GROUP BY spend_date, platform 17 | ), 18 | d AS ( 19 | SELECT DISTINCT spend_date 20 | FROM tb2 21 | ), 22 | p AS ( 23 | SELECT 'desktop' AS platform 24 | UNION 25 | SELECT 'mobile' 26 | UNION 27 | SELECT 'both' 28 | ) 29 | 30 | SELECT d.spend_date, p.platform, 31 | ISNULL(total_amount,0) AS total_amount, 32 | ISNULL(total_users,0) AS total_users 33 | FROM d 34 | CROSS JOIN p 35 | LEFT JOIN tb2 36 | ON d.spend_date = tb2.spend_date and p.platform = tb2.platform; 37 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1159_Market_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, Join, CASE WHEN 2 | -- get item_id of the second item (by date) they sold for each user 3 | WITH tb1 AS ( 4 | SELECT seller_id, item_id 5 | FROM ( 6 | SELECT seller_id, item_id, 7 | ROW_NUMBER() OVER (PARTITION BY seller_id ORDER BY order_date) AS r 8 | FROM Orders 9 | ) rank 10 | WHERE r = 2 11 | ) 12 | 13 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 14 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 15 | SELECT u.user_id AS seller_id, 16 | CASE 17 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 18 | ELSE 'no' 19 | END AS '2nd_item_fav_brand' 20 | FROM Users u 21 | LEFT JOIN tb1 22 | ON u.user_id = tb1.seller_id 23 | LEFT JOIN Items i 24 | ON tb1.item_id = i.item_id; 25 | 26 | 27 | 28 | -- Solution 2: Join, Subquery, CASE WHEN 29 | -- get item_id of the second item (by date) they sold for each user (having only two sales records on or before o1.order_date) 30 | WITH tb1 AS ( 31 | SELECT o1.seller_id, o1.item_id 32 | FROM Orders o1 33 | JOIN orders o2 34 | ON o1.seller_id = o2.seller_id AND o1.order_date >= o2.order_date 35 | GROUP BY o1.seller_id, o1.order_date, o1.item_id 36 | HAVING COUNT(*) = 2 37 | ) 38 | 39 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 40 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 41 | SELECT u.user_id AS seller_id, 42 | CASE 43 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 44 | ELSE 'no' 45 | END AS '2nd_item_fav_brand' 46 | FROM Users u 47 | LEFT JOIN tb1 48 | ON u.user_id = tb1.seller_id 49 | LEFT JOIN Items i 50 | ON tb1.item_id = i.item_id; 51 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1212_Team_Scores_in_Football_Tournament.sql: -------------------------------------------------------------------------------- 1 | SELECT team_id, team_name, 2 | SUM( 3 | CASE WHEN team_id = host_team AND host_goals > guest_goals THEN 3 4 | WHEN team_id = guest_team AND guest_goals > host_goals THEN 3 5 | WHEN host_goals = guest_goals THEN 1 6 | ELSE 0 7 | END 8 | ) AS num_points 9 | FROM Teams t 10 | LEFT JOIN Matches m 11 | ON t.team_id = m.host_team OR t.team_id = m.guest_team 12 | GROUP BY team_id, team_name 13 | ORDER BY num_points DESC, team_id; 14 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1225_Report_Contiguous_Dates.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | -- numbering date with different states in chronological order separately 3 | SELECT f1.fail_date AS date, 'failed' AS s, COUNT(*) AS r 4 | FROM Failed f1 5 | JOIN Failed f2 6 | ON f1.fail_date >= f2.fail_date 7 | GROUP BY f1.fail_date 8 | UNION 9 | SELECT s1.success_date AS date, 'succeeded' AS s, COUNT(*) AS r 10 | FROM Succeeded s1 11 | JOIN Succeeded s2 12 | ON s1.success_date >= s2.success_date 13 | GROUP BY s1.success_date 14 | ), 15 | tb2 AS ( 16 | SELECT *, 17 | -- numbering date in chronological order 18 | DATEPART(dayofyear, date) AS r2 19 | FROM tb1 20 | WHERE Year(date) = 2019 21 | ) 22 | 23 | -- contiguous dates with same period state share the same r2-r, 24 | -- so in a group with same r2-4, the smallest date is start date and the largest date is end date 25 | SELECT s AS period_state, MIN(date) AS start_date, MAX(date) AS end_date 26 | FROM tb2 27 | GROUP BY r2-r, s 28 | ORDER BY start_date; 29 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1251_Average_Selling_Price.sql: -------------------------------------------------------------------------------- 1 | SELECT u.product_id, 2 | CAST( 3 | SUM(price*units) * 1.0 / SUM(units) 4 | AS DECIMAL(10,2) 5 | ) AS average_price 6 | FROM UnitsSold u 7 | JOIN Prices p 8 | ON u.product_id = p.product_id 9 | AND u.purchase_date >= p.start_date 10 | AND u.purchase_date <= p.end_date 11 | GROUP BY u.product_id; 12 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql: -------------------------------------------------------------------------------- 1 | -- when the number is continous with the last one, both log_id and r add 1 2 | -- Therefore, continuous numbers share the same log_id - r 3 | -- when grouped by log_id - r, the start number is the samllest number in group and the end is the largest 4 | WITH tb1 AS ( 5 | SELECT l1.log_id, COUNT(*) AS r 6 | FROM Logs l1 7 | JOIN Logs l2 8 | ON l1.log_id >= l2.log_id 9 | GROUP BY l1.log_id 10 | ) 11 | 12 | SELECT MIN(log_id) AS START_ID, MAX(log_id) AS END_ID 13 | FROM tb1 14 | GROUP BY log_id-r; 15 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1308_Running_Total_for_Different_Genders.sql: -------------------------------------------------------------------------------- 1 | SELECT s1.gender, s1.day, SUM(s2.score_points) AS total 2 | FROM Scores s1 3 | JOIN Scores s2 4 | ON s1.gender = s2.gender AND s1.day >= s2.day 5 | GROUP BY s1.gender, s1.day 6 | ORDER BY s1.gender, s1.day; 7 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1321_Restaurant_Growth.sql: -------------------------------------------------------------------------------- 1 | WITH total AS ( 2 | SELECT visited_on, SUM(amount) AS amount 3 | FROM Customer 4 | GROUP BY visited_on 5 | ) 6 | 7 | SELECT t1.visited_on, 8 | SUM(t2.amount) AS amount, 9 | CAST(AVG(t2.amount*1.0) AS DECIMAL(10,2)) AS average_amount 10 | FROM total t1 11 | JOIN total t2 12 | ON t1.visited_on >= t2.visited_on AND t1.visited_on <= DATEADD(day,6,t2.visited_on) 13 | GROUP BY t1.visited_on 14 | HAVING COUNT(t2.visited_on) = 7 15 | ORDER BY t1.visited_on; 16 | -------------------------------------------------------------------------------- /Join/Advanced-Join/1369_Get_the_Second_Most_Recent_Activity.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT u1.username, u1.activity, u1.startDate, u1.endDate, COUNT(*) AS r 3 | FROM UserActivity u1 4 | JOIN UserActivity u2 5 | ON u1.username = u2.username AND u1.endDate <= u2.endDate 6 | GROUP BY u1.username, u1.activity, u1.startDate, u1.endDate 7 | ), 8 | tb2 AS ( 9 | SELECT username, COUNT(*) AS c 10 | FROM UserActivity 11 | GROUP BY username 12 | ) 13 | 14 | SELECT tb1.username, tb1.activity, tb1.startDate, tb1.endDate 15 | FROM tb1 16 | JOIN tb2 17 | ON tb1.username = tb2.username 18 | WHERE tb1.r = 2 OR tb2.c = 1; 19 | -------------------------------------------------------------------------------- /Join/Advanced-Join/180_Consecutive_Numbers.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT l1.num AS ConsecutiveNums 2 | FROM logs l1 3 | JOIN logs l2 4 | ON l1.id = l2.id-1 AND l1.num = l2.num 5 | JOIN logs l3 6 | ON l1.id = l3.id-2 AND l2.num = l3.num; 7 | -------------------------------------------------------------------------------- /Join/Advanced-Join/196_Delete_Duplicate_Emails.sql: -------------------------------------------------------------------------------- 1 | DELETE p1 2 | FROM person p1 3 | JOIN person p2 4 | ON p1.email = p2.email AND p1.id > p2.id; 5 | -------------------------------------------------------------------------------- /Join/Advanced-Join/534_Game_Play_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | SELECT a1.player_id, a1.event_date, SUM(a2.games_played) AS games_played_so_far 2 | FROM activity a1 3 | JOIN activity a2 4 | -- the matched data from a2 include all records happened before or exactly on a1.event_date of the according record in a1 5 | ON a1.player_id = a2.player_id AND a1.event_date >= a2. event_date 6 | GROUP BY a1.player_id, a1.event_date; 7 | -------------------------------------------------------------------------------- /Join/Advanced-Join/569_Median_Employee_Salary.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT e1.id, e1.company, e1.salary, COUNT(*) AS r, 3 | (SELECT COUNT(*) FROM employee WHERE company = e1.company) AS num 4 | FROM employee e1 5 | JOIN employee e2 6 | ON e1.company = e2.company 7 | AND (e1.salary > e2.salary OR (e1.salary = e2.salary AND e1.id >= e2.id)) 8 | GROUP BY e1.id, e1.company, e1.salary 9 | ) 10 | 11 | SELECT id, company, salary 12 | FROM tb1 13 | -- when num % 2 = 0, the r of the median is num/2 and num/2 + 1 14 | -- when num % 2 = 1, the r of the median is (num+1)/2, between num/2 and num/2 + 1 15 | WHERE r BETWEEN num*1.0/2 AND num*1.0/2 + 1; 16 | -------------------------------------------------------------------------------- /Join/Advanced-Join/579_Find_Cumulative_Salary_of_an_Employee.sql: -------------------------------------------------------------------------------- 1 | SELECT e1.id, e1.month, SUM(e2.salary) AS Salary 2 | FROM Employee e1 3 | JOIN Employee e2 4 | -- data from table e2 only contained salary over a period of 3 months until e1.month 5 | ON e1.id = e2.id AND e1.month >= e2.month AND e1.month <= e2.month + 2 6 | -- exclude the most recent month for each employee 7 | WHERE e1.month != (SELECT MAX(month) FROM Employee WHERE id = e1.id) 8 | GROUP BY e1.id, e1.month 9 | ORDER BY e1.id, e1.month DESC; 10 | -------------------------------------------------------------------------------- /Join/Advanced-Join/601_Human_Traffic_of_Stadium.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT s1.id AS id1, s2.id AS id2, s3.id AS id3 3 | FROM stadium s1, stadium s2, stadium s3 4 | WHERE s1.id + 1 = s2.id AND s2.id + 1 = s3.id 5 | AND s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100 6 | ) 7 | 8 | 9 | SELECT * 10 | FROM stadium 11 | WHERE id IN (SELECT id1 id FROM tb1 12 | UNION 13 | SELECT id2 FROM tb1 14 | UNION 15 | SELECT id3 FROM tb1); 16 | -------------------------------------------------------------------------------- /Join/Advanced-Join/603_Consecutive_Available_Seats.sql: -------------------------------------------------------------------------------- 1 | SELECT c2.seat_id 2 | FROM cinema c1 3 | RIGHT JOIN cinema c2 4 | ON c1.seat_id + 1 = c2.seat_id 5 | LEFT JOIN cinema c3 6 | ON c2.seat_id + 1 = c3.seat_id 7 | WHERE c2.free = 1 AND (c1.free = 1 OR c3.free = 1); 8 | -------------------------------------------------------------------------------- /Join/Advanced-Join/612_Shortest_Distance_in_a_Plane.sql: -------------------------------------------------------------------------------- 1 | SELECT CAST( 2 | MIN( 3 | SQRT( 4 | POWER(p1.x-p2.x,2)+POWER(p1.y-p2.y,2) 5 | ) 6 | ) 7 | AS DECIMAL(10,2) 8 | ) AS shortest 9 | FROM point_2d p1 10 | JOIN point_2d p2 11 | ON p1.x != p2.x OR p1.y != p2.y; 12 | -------------------------------------------------------------------------------- /Join/Advanced-Join/613_Shortest_Distance_in_a_Line.sql: -------------------------------------------------------------------------------- 1 | SELECT MIN(ABS(p1.x-p2.x)) AS shortest 2 | FROM point p1 3 | JOIN point p2 4 | ON p1.x != p2.x; 5 | -------------------------------------------------------------------------------- /Join/Join.md: -------------------------------------------------------------------------------- 1 | # Join 2 | 3 | 4 | ## Simple Structre 5 | 6 | ```SQL 7 | SELECT * 8 | FROM table1 t1 9 | JOIN table2 t2 10 | ON t1.key1 = t2.key2 11 | -------------------------------------------------------------------------------- /Join/Simple-Join/1068_Product_Sales_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | SELECT p.product_name, s.year, s.price 2 | FROM Sales s 3 | JOIN Product p 4 | on s.product_id = p.product_id; 5 | -------------------------------------------------------------------------------- /Join/Simple-Join/1070_Product_Sales_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT product_id, MIN(year) AS first_year 3 | FROM Sales 4 | GROUP BY product_id 5 | ) 6 | 7 | SELECT s.product_id, first_year, quantity, price 8 | FROM Sales s 9 | JOIN tb1 10 | ON s.product_id = tb1.product_id AND s.year = tb1.first_year; 11 | -------------------------------------------------------------------------------- /Join/Simple-Join/1075_Project_Employees_I.sql: -------------------------------------------------------------------------------- 1 | SELECT p.project_id, CAST(AVG(e.experience_years*1.0) AS DECIMAL(10,2)) AS average_years 2 | FROM Project p 3 | LEFT JOIN Employee e 4 | ON p.employee_id = e.employee_id 5 | GROUP BY p.project_id; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/1077_Project_Employees_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, Window Function, Subquery 2 | SELECT project_id, employee_id 3 | FROM ( 4 | SELECT p.project_id, p.employee_id, 5 | RANK() OVER (PARTITION BY project_id ORDER BY experience_years DESC) AS r 6 | FROM Project p 7 | JOIN Employee e 8 | ON p.employee_id = e.employee_id 9 | ) tb1 10 | WHERE r = 1; 11 | 12 | 13 | 14 | -- Solution 2: Join, Subquery 15 | WITH tb1 AS ( 16 | SELECT p.project_id, p.employee_id, e.experience_years 17 | FROM Project p 18 | JOIN Employee e 19 | ON p.employee_id = e.employee_id 20 | ), 21 | tb2 AS ( 22 | SELECT project_id, MAX(experience_years) AS max_years 23 | FROM tb1 24 | GROUP BY project_id 25 | ) 26 | 27 | SELECT project_id, employee_id 28 | FROM tb1 29 | WHERE experience_years = (SELECT max_years FROM tb2 WHERE project_id = tb1.project_id); 30 | -------------------------------------------------------------------------------- /Join/Simple-Join/1083_Sales_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, Subquery 2 | WITH tb1 AS ( 3 | SELECT s.buyer_id, p.product_name 4 | FROM Sales s 5 | JOIN Product p 6 | ON s.product_id = p.product_id 7 | ) 8 | 9 | SELECT buyer_id 10 | FROM tb1 11 | WHERE product_name = 'S8' 12 | EXCEPT 13 | SELECT buyer_id 14 | FROM tb1 15 | WHERE product_name = 'iPhone'; 16 | 17 | 18 | 19 | -- Solution 2: Join, Subquery 20 | WITH tb1 AS ( 21 | SELECT s.buyer_id, p.product_name 22 | FROM Sales s 23 | JOIN Product p 24 | ON s.product_id = p.product_id 25 | ) 26 | 27 | SELECT DISTINCT buyer_id 28 | FROM tb1 29 | WHERE product_name = 'S8' AND buyer_id NOT IN ( 30 | SELECT buyer_id 31 | FROM tb1 32 | WHERE product_name = 'iPhone' 33 | ); 34 | -------------------------------------------------------------------------------- /Join/Simple-Join/1112_Highest_Grade_For_Each_Student.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT student_id, MAX(grade) AS grade 3 | FROM Enrollments 4 | GROUP BY student_id 5 | ) 6 | 7 | SELECT e.student_id, MIN(course_id) AS course_id, e.grade 8 | FROM Enrollments e 9 | JOIN tb1 10 | ON e.student_id = tb1.student_id AND e.grade = tb1.grade 11 | GROUP BY e.student_id, e.grade 12 | ORDER BY e.student_id; 13 | -------------------------------------------------------------------------------- /Join/Simple-Join/1132_Reported_Posts_II.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT COUNT(DISTINCT r.post_id)*100.0/COUNT(DISTINCT a.post_id) AS daily_p 3 | FROM Actions a 4 | LEFT JOIN Removals r 5 | ON a.post_id = r.post_id 6 | WHERE a.action = 'report' AND a.extra = 'spam' 7 | GROUP BY a.action_date 8 | ) 9 | 10 | SELECT CAST(AVG(daily_p) AS DECIMAL(5,2)) AS average_daily_percent 11 | FROM tb1; 12 | -------------------------------------------------------------------------------- /Join/Simple-Join/1158_Market_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, CASE WHEN 2 | SELECT u.user_id AS buyer_id, u.join_date AS join_date, 3 | SUM(CASE WHEN YEAR(order_date) = 2019 THEN 1 ELSE 0 END) AS orders_in_2019 4 | FROM Users u 5 | LEFT JOIN Orders o 6 | ON u.user_id = o.buyer_id 7 | GROUP BY u.user_id, u.join_date; 8 | 9 | 10 | 11 | -- Solution 2: Subquery, Join 12 | WITH tb1 AS ( 13 | SELECT buyer_id, COUNT(*) AS num 14 | FROM orders 15 | WHERE YEAR(order_date) = 2019 16 | GROUP BY buyer_id 17 | ) 18 | 19 | SELECT u.user_id AS buyer_id, u.join_date, ISNULL(num, 0) AS orders_in_2019 20 | FROM users u 21 | LEFT JOIN tb1 o 22 | ON u.user_id = o.buyer_id; 23 | -------------------------------------------------------------------------------- /Join/Simple-Join/1164_Product_Price_at_a_Given_Date.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, Join 2 | WITH tb1 AS ( 3 | SELECT product_id, new_price 4 | FROM ( 5 | SELECT product_id, new_price, 6 | -- use ROW_NUMBER() to find the last time when the price of each product was changed before '2019-08-16' 7 | -- so if the price of a product had not been changed before '2019-08-16', the product will not be included in tb1 8 | ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY change_date DESC) AS r 9 | FROM Products 10 | WHERE change_date <= '2019-08-16' 11 | ) rank 12 | WHERE r = 1 13 | ) 14 | 15 | -- if a product does not in tb1, which means it has no price change before '2019-08-16' 16 | -- assign the original price 10 to that product 17 | SELECT p.product_id, ISNULL(new_price,10) AS price 18 | FROM ( 19 | SELECT DISTINCT product_id 20 | FROM Products 21 | ) p 22 | LEFT JOIN tb1 23 | ON p.product_id = tb1.product_id; 24 | 25 | 26 | 27 | -- Solution 2: Subquery, Join 28 | -- find the date of last time when the price of each product was changed before '2019-08-16'' 29 | WITH tb1 AS ( 30 | SELECT product_id, MAX(change_date) AS date 31 | FROM Products 32 | WHERE change_date <= '2019-08-16' 33 | GROUP BY product_id 34 | ), 35 | -- find the latest price of product which had been changed price for at least one time before '2019-08-16' 36 | tb2 AS ( 37 | SELECT p.product_id, p.new_price 38 | FROM Products p 39 | JOIN tb1 40 | ON p.product_id = tb1.product_id AND p.change_date = tb1.date 41 | ) 42 | 43 | -- if a product does not in tb2, which means it has no price change before '2019-08-16' 44 | -- assign the original price 10 to that product 45 | SELECT p.product_id, ISNULL(new_price,10) AS price 46 | FROM ( 47 | SELECT DISTINCT product_id 48 | FROM Products 49 | ) p 50 | LEFT JOIN tb2 51 | ON p.product_id = tb2.product_id; 52 | -------------------------------------------------------------------------------- /Join/Simple-Join/1204_Last_Person_to_Fit_in_the_Elevator.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 q1.person_name 2 | FROM Queue q1 3 | JOIN Queue q2 4 | ON q1.turn >= q2.turn 5 | GROUP BY q1.person_id, q1.person_name 6 | HAVING SUM(q2.weight) <= 1000 7 | ORDER BY SUM(q2.weight) DESC; 8 | -------------------------------------------------------------------------------- /Join/Simple-Join/1205_Monthly_Transactions_II.sql: -------------------------------------------------------------------------------- 1 | -- find the number of approved transactions and their total amount for each month and country 2 | WITH tb1 AS ( 3 | SELECT LEFT(trans_date,7) AS month, country, 4 | COUNT(state) AS approved_count, 5 | SUM(amount) AS approved_amount 6 | FROM Transactions 7 | WHERE state = 'approved' 8 | GROUP BY LEFT(trans_date,7), country 9 | ), 10 | -- find the number of chargebacks and their total amount for each month and country 11 | tb2 AS ( 12 | SELECT LEFT(c.trans_date,7) AS month, country, 13 | COUNT(c.trans_id) AS chargeback_count, 14 | SUM(t.amount) AS chargeback_amount 15 | FROM Chargebacks c 16 | JOIN Transactions t 17 | ON c.trans_id = t.id 18 | GROUP BY LEFT(c.trans_date,7), country 19 | ) 20 | 21 | -- when there is no approved transactions or chargebacks for a country in a certain month, 22 | -- replace the NULL with 0 23 | SELECT COALESCE(tb1.month,tb2.month) AS month, 24 | COALESCE(tb1.country,tb2.country) AS country, 25 | ISNULL(tb1.approved_count,0) AS approved_count, 26 | ISNULL(tb1.approved_amount,0) AS approved_amount, 27 | ISNULL(tb2.chargeback_count,0) AS chargeback_count, 28 | ISNULL(tb2.chargeback_amount,0) AS chargeback_amount 29 | FROM tb1 30 | FULL OUTER JOIN tb2 31 | ON tb1.month = tb2.month AND tb1.country = tb2.country; 32 | -------------------------------------------------------------------------------- /Join/Simple-Join/1241_Number_of_Comments_per_Post.sql: -------------------------------------------------------------------------------- 1 | SELECT s1.sub_id AS post_id, COUNT(DISTINCT s2.sub_id) AS number_of_comments 2 | FROM Submissions s1 3 | LEFT JOIN Submissions s2 4 | -- Orginal posts are in left table, and comments are in right table 5 | ON s1.sub_id = s2.parent_id 6 | WHERE s1.parent_id IS NULL 7 | GROUP BY s1.sub_id; 8 | -------------------------------------------------------------------------------- /Join/Simple-Join/1270_All_People_Report_to_the_Given_Manager.sql: -------------------------------------------------------------------------------- 1 | -- find employees directly report to managers directly, 2 | -- and then find people who report to managers indirectly using cte 3 | WITH cte AS ( 4 | SELECT employee_id 5 | FROM Employees 6 | WHERE manager_id = 1 AND employee_id != manager_id 7 | UNION ALL 8 | SELECT e.employee_id 9 | FROM Employees e 10 | JOIN cte 11 | ON e.manager_id = cte.employee_id 12 | ) 13 | 14 | SELECT employee_id 15 | FROM cte 16 | OPTION (MAXRECURSION 3); 17 | -------------------------------------------------------------------------------- /Join/Simple-Join/1280_Students_and_Examinations.sql: -------------------------------------------------------------------------------- 1 | SELECT s.student_id, s.student_name, b.subject_name, 2 | COUNT(e.student_id) AS attended_exams 3 | FROM students s 4 | CROSS JOIN subjects b 5 | LEFT JOIN examinations e 6 | ON s.student_id = e.student_id AND b.subject_name = e.subject_name 7 | GROUP BY s.student_id, s.student_name, b.subject_name 8 | ORDER BY s.student_id, b.subject_name; 9 | -------------------------------------------------------------------------------- /Join/Simple-Join/1294_Weather_Type_in_Each_Country.sql: -------------------------------------------------------------------------------- 1 | SELECT c.country_name, w.weather_type 2 | FROM ( 3 | SELECT country_id, 4 | CASE 5 | WHEN AVG(weather_state*1.0) <= 15 THEN 'Cold' 6 | WHEN AVG(weather_state*1.0) >= 25 THEN 'Hot' 7 | ELSE 'Warm' 8 | END AS weather_type 9 | FROM Weather 10 | WHERE LEFT(day,7) = '2019-11' 11 | GROUP BY country_id 12 | ) w 13 | JOIN Countries c 14 | ON w.country_id = c.country_id; 15 | -------------------------------------------------------------------------------- /Join/Simple-Join/1303_Find_the_Team_Size.sql: -------------------------------------------------------------------------------- 1 | SELECT e1.employee_id, COUNT(*) AS team_size 2 | FROM Employee e1 3 | JOIN Employee e2 4 | ON e1.team_id = e2.team_id 5 | GROUP BY e1.employee_id; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/1327_List_the_Products_Ordered_in_a_Period.sql: -------------------------------------------------------------------------------- 1 | SELECT MIN(p.product_name) AS product_name, SUM(unit) AS unit 2 | FROM Orders o 3 | JOIN Products p 4 | ON o.product_id = p.product_id 5 | WHERE YEAR(o.order_date) = 2020 AND MONTH(o.order_date) = 2 6 | GROUP BY p.product_id 7 | HAVING SUM(unit) >= 100; 8 | -------------------------------------------------------------------------------- /Join/Simple-Join/1336_Number_of_Transactions_per_Visit.sql: -------------------------------------------------------------------------------- 1 | -- find number of transactions done for each visit 2 | WITH tb1 AS ( 3 | SELECT v.user_id, v.visit_date, COUNT(t.transaction_date) AS c 4 | FROM Visits v 5 | LEFT JOIN Transactions t 6 | ON v.visit_date = t.transaction_date AND v.user_id = t.user_id 7 | GROUP BY v.user_id, v.visit_date 8 | ), 9 | -- get all values from 0 to max(transactions_count) done by one or more users 10 | cte AS ( 11 | SELECT MAX(c) AS c 12 | FROM tb1 13 | UNION ALL 14 | SELECT c-1 15 | FROM cte 16 | WHERE c > 0 17 | ) 18 | 19 | -- count the corresponding number of users who did a certain transactions_count in one visit to the bank. 20 | SELECT cte.c AS transactions_count, 21 | COUNT(tb1.user_id) AS visits_count 22 | FROM cte 23 | LEFT JOIN tb1 24 | ON cte.c = tb1.c 25 | GROUP BY cte.c 26 | ORDER BY transactions_count; 27 | -------------------------------------------------------------------------------- /Join/Simple-Join/1350_Students_With_Invalid_Departments.sql: -------------------------------------------------------------------------------- 1 | SELECT s.id, s.name 2 | FROM Students s 3 | LEFT JOIN Departments d 4 | ON s.department_id = d.id 5 | WHERE d.id IS NULL; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/1364_Number_of_Trusted_Contacts_of_a_Customer.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT c.customer_id, c.customer_name, 3 | COUNT(con.contact_name) AS contacts_cnt, 4 | COUNT(c2.customer_id) AS trusted_contacts_cnt 5 | FROM Customers c 6 | LEFT JOIN Contacts con 7 | ON c.customer_id = con.user_id 8 | LEFT JOIN Customers c2 9 | ON con.contact_email = c2.email 10 | GROUP BY c.customer_id, c.customer_name 11 | ) 12 | 13 | SELECT i.invoice_id, 14 | tb1.customer_name, 15 | i.price, 16 | tb1.contacts_cnt, 17 | tb1.trusted_contacts_cnt 18 | FROM Invoices i 19 | JOIN tb1 20 | ON i.user_id = tb1.customer_id 21 | ORDER BY i.invoice_id; 22 | -------------------------------------------------------------------------------- /Join/Simple-Join/1378_Replace_Employee_ID_With_The_Unique_Identifier.sql: -------------------------------------------------------------------------------- 1 | SELECT u.unique_id, e.name 2 | FROM Employees e 3 | LEFT JOIN EmployeeUNI u 4 | ON e.id = u.id; 5 | -------------------------------------------------------------------------------- /Join/Simple-Join/1384_Total_Sales_Amount_by_Year.sql: -------------------------------------------------------------------------------- 1 | -- get all dates from MIN(period_start) to MAX(period_end) 2 | WITH cte AS ( 3 | SELECT MIN(period_start) AS date, MAX(period_end) AS end_date 4 | FROM Sales 5 | UNION ALL 6 | SELECT DATEADD(day,1,date), end_date 7 | FROM cte 8 | WHERE date < end_date 9 | ) 10 | 11 | -- after join, products will have same number of records as the number of days in sale period 12 | SELECT s.product_id AS PRODUCT_ID, 13 | p.product_name AS PRODUCT_NAME, 14 | CAST(Year(cte.date) AS CHAR(4)) AS REPORT_YEAR, 15 | SUM(average_daily_sales) AS TOTAL_AMOUNT 16 | FROM cte 17 | JOIN Sales s 18 | ON cte.date BETWEEN s.period_start AND s.period_end 19 | JOIN Product p 20 | ON s.product_id = p.product_id 21 | GROUP BY s.product_id, p.product_name, Year(cte.date) 22 | ORDER BY PRODUCT_ID, REPORT_YEAR 23 | OPTION (MAXRECURSION 0); 24 | -------------------------------------------------------------------------------- /Join/Simple-Join/1407_Top_Travellers.sql: -------------------------------------------------------------------------------- 1 | SELECT name, 2 | -- 0 will be shown as distance if no record in table Rides 3 | COALESCE(SUM(distance),0) AS travelled_distance 4 | FROM Users 5 | LEFT JOIN Rides 6 | ON Users.id = Rides.user_id 7 | GROUP BY name 8 | ORDER BY travelled_distance DESC, name 9 | -------------------------------------------------------------------------------- /Join/Simple-Join/175_Combine_Two_Tables.sql: -------------------------------------------------------------------------------- 1 | SELECT p.firstname, p.lastname, a.city, a.state 2 | FROM person p 3 | -- LEFT JOIN return all records from the left table, and the matched records from the right table 4 | LEFT JOIN address a 5 | ON p.personid = a.personid; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/181_Employees_Earning_More_Than_Their_Managers.sql: -------------------------------------------------------------------------------- 1 | SELECT e1.name AS Employee 2 | FROM employee e1 3 | JOIN employee e2 4 | ON e1.Managerid = e2.id 5 | WHERE e1.salary > e2.salary; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/183_Customers_Who_Never_Order.sql: -------------------------------------------------------------------------------- 1 | SELECT c.name AS customers 2 | FROM customers c 3 | LEFT JOIN orders o 4 | ON c.id = o.customerid 5 | WHERE o.id IS NULL; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/184_Department_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | WITH max_salary AS ( 2 | SELECT departmentid, max(salary) AS max_salary 3 | FROM employee 4 | GROUP BY departmentid 5 | ) 6 | 7 | SELECT d.name department, e.name employee, e.salary 8 | FROM max_salary ms 9 | JOIN employee e 10 | ON ms.departmentid = e.departmentid AND ms.max_salary = e.salary 11 | JOIN department d 12 | ON e.departmentid = d.id; 13 | -------------------------------------------------------------------------------- /Join/Simple-Join/197_Rising_Temperature.sql: -------------------------------------------------------------------------------- 1 | SELECT w2.id 2 | FROM weather w1 3 | JOIN weather w2 4 | ON DATEADD(day,1,w1.recorddate) = w2.recorddate 5 | WHERE w1.temperature < w2.temperature; 6 | -------------------------------------------------------------------------------- /Join/Simple-Join/262_Trips_and_Users.sql: -------------------------------------------------------------------------------- 1 | SELECT t.Request_at AS 'Day', 2 | CAST( 3 | AVG(CASE 4 | WHEN status = 'completed' then 0 5 | ELSE 1.0 6 | END) 7 | AS DECIMAL(3,2) 8 | ) AS 'Cancellation Rate' 9 | FROM Trips AS t 10 | INNER JOIN Users c 11 | ON t.Client_Id=c.Users_Id 12 | INNER JOIN Users d 13 | ON t.Driver_Id=d.Users_Id 14 | -- filter our banned client and driver and limit time frame 15 | WHERE c.Banned='no' AND 16 | d.Banned='no' AND 17 | t.Request_at BETWEEN '2013-10-01' AND '2013-10-03' 18 | GROUP BY t.Request_at; 19 | -------------------------------------------------------------------------------- /Join/Simple-Join/512_Game_Play_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | SELECT a.player_id, device_id 2 | FROM Activity a 3 | JOIN ( 4 | SELECT player_id, MIN(event_date) min_date 5 | FROM Activity 6 | GROUP BY player_id 7 | ) tb1 8 | ON a.player_id = tb1.player_id AND a.event_date = tb1.min_date; 9 | -------------------------------------------------------------------------------- /Join/Simple-Join/550_Game_Play_Analysis_IV.sql: -------------------------------------------------------------------------------- 1 | SELECT CAST( 2 | -- using DISTINCT to avoid double counting 3 | COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id) 4 | AS DECIMAL(3,2) 5 | ) AS fraction 6 | FROM ( 7 | -- get the first-logged-in date of each player 8 | SELECT player_id, MIN(event_date) AS event_date 9 | FROM Activity 10 | GROUP BY player_id 11 | ) a1 12 | -- if a player logged back in on the day right after the first-logged-in date, 13 | -- he/she would get a matched record from table a2 14 | LEFT JOIN Activity a2 15 | ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date; 16 | -------------------------------------------------------------------------------- /Join/Simple-Join/570_Managers_with_at_Least_5_Direct_Reports.sql: -------------------------------------------------------------------------------- 1 | SELECT e2.name 2 | FROM employee e1 3 | JOIN employee e2 4 | ON e1.managerid = e2.id 5 | GROUP BY e2.id, e2.name 6 | HAVING COUNT(e1.id) >= 5; 7 | -------------------------------------------------------------------------------- /Join/Simple-Join/574_Winning_Candidate.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 c.Name 2 | FROM Candidate c 3 | JOIN Vote v 4 | ON c.id = v.CandidateId 5 | GROUP BY c.id, c.Name 6 | ORDER BY COUNT(*) DESC; 7 | -------------------------------------------------------------------------------- /Join/Simple-Join/577_Employee_Bonus.sql: -------------------------------------------------------------------------------- 1 | SELECT e.name, b.bonus 2 | FROM Employee e 3 | LEFT JOIN Bonus b 4 | ON e.empId = b.empId 5 | -- when employee has no bonus, his/her bonus will be null after left join 6 | WHERE b.bonus IS NULL 7 | OR b.bonus < 1000; 8 | -------------------------------------------------------------------------------- /Join/Simple-Join/580_Count_Student_Number_in_Departments.sql: -------------------------------------------------------------------------------- 1 | SELECT d.dept_name, COUNT(student_id) AS student_number 2 | FROM department d 3 | LEFT JOIN student s 4 | ON d.dept_id = s.dept_id 5 | GROUP BY d.dept_id, d.dept_name 6 | ORDER BY student_number DESC, d.dept_name; 7 | -------------------------------------------------------------------------------- /Join/Simple-Join/607_Sales_Person.sql: -------------------------------------------------------------------------------- 1 | SELECT name 2 | FROM salesperson 3 | WHERE sales_id NOT IN ( 4 | SELECT o.sales_id 5 | FROM orders o 6 | JOIN company c 7 | ON o.com_id = c.com_id 8 | WHERE c.name = 'RED' 9 | ); 10 | -------------------------------------------------------------------------------- /Join/Simple-Join/614_Second_Degree_Follower.sql: -------------------------------------------------------------------------------- 1 | SELECT f1.follower, COUNT(DISTINCT f2.follower) AS num 2 | FROM follow f1 3 | JOIN follow f2 4 | ON f1.follower = f2.followee 5 | GROUP BY f1.follower 6 | ORDER BY f1.follower; 7 | -------------------------------------------------------------------------------- /Join/Simple-Join/615_Average_Salary_Departments_VS_Company.sql: -------------------------------------------------------------------------------- 1 | -- If need to extract date in other format in the future, FORMAT() function could be used 2 | 3 | -- Solution 1: Join, Window Function, Subquery, CASE WHEN 4 | WITH tb1 AS ( 5 | SELECT DISTINCT department_id, LEFT(pay_date,7) AS pay_month, 6 | AVG(amount) OVER (PARTITION BY department_id, LEFT(pay_date,7))AS avg_dept, 7 | AVG(amount) OVER (PARTITION BY LEFT(pay_date,7)) AS avg_comp 8 | FROM salary s 9 | JOIN employee e 10 | ON s.employee_id = e.employee_id 11 | ) 12 | 13 | SELECT pay_month, department_id, 14 | CASE 15 | WHEN avg_dept > avg_comp THEN 'higher' 16 | WHEN avg_dept < avg_comp THEN 'lower' 17 | ELSE 'same' 18 | END AS comparison 19 | FROM tb1; 20 | 21 | 22 | 23 | -- Solution 2: Join, Subquery, CASE WHEN 24 | WITH dept AS ( 25 | SELECT e.department_id, LEFT(s.pay_date,7) AS pay_month, AVG(s.amount) AS avg_dept 26 | FROM salary s 27 | JOIN employee e 28 | ON s.employee_id = e.employee_id 29 | GROUP BY e.department_id, LEFT(s.pay_date,7) 30 | ), 31 | comp AS ( 32 | SELECT LEFT(pay_date,7) AS pay_month, AVG(amount) AS avg_comp 33 | FROM salary 34 | GROUP BY LEFT(pay_date,7) 35 | ) 36 | 37 | SELECT d.department_id, d.pay_month, 38 | CASE 39 | WHEN d.avg_dept > c.avg_comp THEN 'higher' 40 | WHEN d.avg_dept < c.avg_comp THEN 'lower' 41 | ELSE 'same' 42 | END AS comparison 43 | FROM dept d 44 | JOIN comp c 45 | ON d.pay_month = c.pay_month; 46 | -------------------------------------------------------------------------------- /OFFSET-FETCH/1321_Restaurant_Growth.sql: -------------------------------------------------------------------------------- 1 | SELECT visited_on, 2 | SUM(SUM(amount)) OVER ( 3 | ORDER BY visited_on 4 | ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 5 | ) AS amount, 6 | CAST( 7 | SUM(SUM(amount)) OVER ( 8 | ORDER BY visited_on 9 | ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 10 | )/7.0 11 | AS DECIMAL(10,2) 12 | ) AS average_amount 13 | FROM Customer 14 | GROUP BY visited_on 15 | ORDER BY visited_on 16 | OFFSET 6 ROWS; 17 | -------------------------------------------------------------------------------- /OFFSET-FETCH/176_Second_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | SELECT ( 2 | SELECT DISTINCT salary 3 | FROM employee 4 | ORDER BY salary DESC 5 | OFFSET 1 ROW 6 | FETCH NEXT 1 ROW ONLY 7 | ) AS SecondHighestSalary; 8 | -------------------------------------------------------------------------------- /OFFSET-FETCH/177_Nth_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION getNthHighestSalary(@N INT) RETURNS INT AS 2 | BEGIN 3 | RETURN ( 4 | SELECT DISTINCT salary 5 | FROM employee 6 | ORDER BY salary DESC 7 | OFFSET @N-1 ROW 8 | FETCH FIRST 1 ROW ONLY 9 | ); 10 | END 11 | -------------------------------------------------------------------------------- /OFFSET-FETCH/OFFSET-FETCH.md: -------------------------------------------------------------------------------- 1 | # OFFSET and FETCH 2 | 3 | ## Basic Structre 4 | 5 | ```SQL 6 | SELECT * 7 | FROM table 8 | ORDER BY column_list [ASC |DESC] 9 | OFFSET offset_row_count {ROW | ROWS} 10 | FETCH {FIRST | NEXT} fetch_row_count {ROW | ROWS} ONLY 11 | ``` 12 | -------------------------------------------------------------------------------- /PIVOT-UNPIVOT/1179_Reformat_Department_Table.sql: -------------------------------------------------------------------------------- 1 | SELECT id, 2 | "Jan" as Jan_Revenue, 3 | "Feb" as Feb_Revenue, 4 | "Mar" as Mar_Revenue, 5 | "Apr" as Apr_Revenue, 6 | "May" as May_Revenue, 7 | "Jun" as Jun_Revenue, 8 | "Jul" as Jul_Revenue, 9 | "Aug" as Aug_Revenue, 10 | "Sep" as Sep_Revenue, 11 | "Oct" as Oct_Revenue, 12 | "Nov" as Nov_Revenue, 13 | "Dec" as Dec_Revenue 14 | FROM department 15 | PIVOT ( 16 | MAX(revenue) 17 | FOR month IN ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec") 18 | ) AS pvt; 19 | -------------------------------------------------------------------------------- /PIVOT-UNPIVOT/1322_Ads_Performance.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT ad_id, [Clicked], [Viewed], [Ignored] 3 | FROM Ads 4 | PIVOT ( 5 | COUNT(action) FOR action IN ([Clicked], [Viewed], [Ignored]) 6 | ) pvt 7 | ) 8 | 9 | SELECT ad_id, 10 | CASE 11 | WHEN SUM(Clicked+Viewed) = 0 THEN 0.0 12 | ELSE CAST(SUM(Clicked)*100.0/SUM(Clicked+Viewed) AS DECIMAL(5,2)) 13 | END AS ctr 14 | FROM tb1 15 | GROUP BY ad_id 16 | ORDER BY ctr DESC, ad_id; 17 | -------------------------------------------------------------------------------- /PIVOT-UNPIVOT/602_Friend_Requests_II_Who_Has_the_Most_Friends.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 upvt.id, COUNT(*) AS num 2 | FROM request_accepted 3 | UNPIVOT ( 4 | id FOR ids IN (requester_id, accepter_id) 5 | ) upvt 6 | GROUP BY upvt.id 7 | ORDER BY COUNT(*) DESC; 8 | -------------------------------------------------------------------------------- /PIVOT-UNPIVOT/618_Students_Report_By_Geography.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | -- Numbering student from each continent separately by their name alphabetically 3 | SELECT *, ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r 4 | FROM student 5 | ) 6 | 7 | -- each row will be a group of student name of whom from different continent and have same numbering 8 | SELECT [America],[Asia],[Europe] 9 | FROM tb1 10 | PIVOT ( 11 | MIN(name) FOR continent IN ([America],[Asia],[Europe]) 12 | ) pvt; 13 | -------------------------------------------------------------------------------- /Questions_by_ID/1045_Customers_Who_Bought_All_Products.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery 2 | SELECT customer_id 3 | FROM customer 4 | GROUP BY customer_id 5 | -- the number of different products bought by customer equals to number of existing products 6 | HAVING COUNT(DISTINCT product_key) = (SELECT COUNT(*) FROM product); 7 | -------------------------------------------------------------------------------- /Questions_by_ID/1050_Actors_and_Directors_Who_Cooperated_At_Least_Three_Times.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT actor_id, director_id 3 | FROM ActorDirector 4 | GROUP BY actor_id, director_id 5 | HAVING COUNT(*) >= 3; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1068_Product_Sales_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT p.product_name, s.year, s.price 3 | FROM Sales s 4 | JOIN Product p 5 | on s.product_id = p.product_id; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1069_Product_Sales_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT product_id, SUM(quantity) AS total_quantity 3 | FROM Sales 4 | GROUP BY product_id; 5 | -------------------------------------------------------------------------------- /Questions_by_ID/1070_Product_Sales_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT product_id, year AS first_year, quantity, price 3 | FROM ( 4 | SELECT *, DENSE_RANK() OVER (PARTITION BY product_id ORDER BY year) AS r 5 | FROM Sales 6 | ) tb1 7 | WHERE r = 1; 8 | 9 | 10 | 11 | -- Solution 2: Subquery 12 | SELECT product_id, year AS first_year, quantity, price 13 | FROM Sales s 14 | WHERE year = ( 15 | SELECT TOP 1 year 16 | FROM Sales 17 | WHERE product_id = s.product_id 18 | ORDER BY year 19 | ); 20 | 21 | 22 | 23 | -- Solution 3: Subquery, Join 24 | WITH tb1 AS ( 25 | SELECT product_id, MIN(year) AS first_year 26 | FROM Sales 27 | GROUP BY product_id 28 | ) 29 | 30 | SELECT s.product_id, first_year, quantity, price 31 | FROM Sales s 32 | JOIN tb1 33 | ON s.product_id = tb1.product_id AND s.year = tb1.first_year; 34 | -------------------------------------------------------------------------------- /Questions_by_ID/1075_Project_Employees_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT p.project_id, CAST(AVG(e.experience_years*1.0) AS DECIMAL(10,2)) AS average_years 3 | FROM Project p 4 | LEFT JOIN Employee e 5 | ON p.employee_id = e.employee_id 6 | GROUP BY p.project_id; 7 | -------------------------------------------------------------------------------- /Questions_by_ID/1076_Project_Employees_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT TOP 1 WITH TIES project_id 3 | FROM Project 4 | GROUP BY project_id 5 | ORDER BY COUNT(employee_id) DESC; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1077_Project_Employees_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, Window Function, Subquery 2 | SELECT project_id, employee_id 3 | FROM ( 4 | SELECT p.project_id, p.employee_id, 5 | RANK() OVER (PARTITION BY project_id ORDER BY experience_years DESC) AS r 6 | FROM Project p 7 | JOIN Employee e 8 | ON p.employee_id = e.employee_id 9 | ) tb1 10 | WHERE r = 1; 11 | 12 | 13 | 14 | -- Solution 2: Join, Subquery 15 | WITH tb1 AS ( 16 | SELECT p.project_id, p.employee_id, e.experience_years 17 | FROM Project p 18 | JOIN Employee e 19 | ON p.employee_id = e.employee_id 20 | ), 21 | tb2 AS ( 22 | SELECT project_id, MAX(experience_years) AS max_years 23 | FROM tb1 24 | GROUP BY project_id 25 | ) 26 | 27 | SELECT project_id, employee_id 28 | FROM tb1 29 | WHERE experience_years = (SELECT max_years FROM tb2 WHERE project_id = tb1.project_id); 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Questions_by_ID/1082_Sales_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT TOP 1 WITH TIES seller_id 3 | FROM Sales 4 | GROUP BY seller_id 5 | ORDER BY SUM(price) DESC; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1083_Sales_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, Subquery 2 | WITH tb1 AS ( 3 | SELECT s.buyer_id, p.product_name 4 | FROM Sales s 5 | JOIN Product p 6 | ON s.product_id = p.product_id 7 | ) 8 | 9 | SELECT buyer_id 10 | FROM tb1 11 | WHERE product_name = 'S8' 12 | EXCEPT 13 | SELECT buyer_id 14 | FROM tb1 15 | WHERE product_name = 'iPhone'; 16 | 17 | 18 | 19 | -- Solution 2: Join, Subquery 20 | WITH tb1 AS ( 21 | SELECT s.buyer_id, p.product_name 22 | FROM Sales s 23 | JOIN Product p 24 | ON s.product_id = p.product_id 25 | ) 26 | 27 | SELECT DISTINCT buyer_id 28 | FROM tb1 29 | WHERE product_name = 'S8' AND buyer_id NOT IN ( 30 | SELECT buyer_id 31 | FROM tb1 32 | WHERE product_name = 'iPhone' 33 | ); 34 | -------------------------------------------------------------------------------- /Questions_by_ID/1084_Sales_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery 2 | SELECT product_id, product_name 3 | FROM Product 4 | WHERE product_id IN ( 5 | SELECT product_id 6 | FROM Sales 7 | WHERE sale_date BETWEEN '2019-01-01' AND '2019-03-31' 8 | EXCEPT 9 | SELECT product_id 10 | FROM Sales 11 | WHERE NOT sale_date BETWEEN '2019-01-01' AND '2019-03-31' 12 | ); 13 | -------------------------------------------------------------------------------- /Questions_by_ID/1097_Game_Play_Analysis_V.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery, Join 2 | SELECT a1.event_date AS install_dt, 3 | COUNT(DISTINCT a1.player_id) AS installs, 4 | CAST( 5 | -- The number of players logged back in the day after / the number of players first logined on that date 6 | -- using DISTINCT to avoid double counting 7 | COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id) 8 | AS DECIMAL(3,2) 9 | ) AS Day1_retention 10 | FROM ( 11 | -- get install date of each player 12 | SELECT player_id, MIN(event_date) AS event_date 13 | FROM Activity 14 | GROUP BY player_id 15 | ) a1 16 | -- if a player logged back in on the day right after install date, he/she would get a matched record from table a2 17 | LEFT JOIN Activity a2 18 | ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date 19 | GROUP BY a1.event_date; 20 | -------------------------------------------------------------------------------- /Questions_by_ID/1098_Unpopular_Books.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT book_id, name 3 | FROM Books 4 | WHERE available_from <= '2019-05-23' 5 | -- find books that have sold more than 10 copies in the last year 6 | AND book_id NOT IN ( 7 | SELECT book_id 8 | FROM Orders 9 | WHERE dispatch_date >= '2018-06-24' 10 | GROUP BY book_id 11 | HAVING SUM(quantity) >= 10 12 | ); 13 | 14 | 15 | 16 | -- Solution 2: Subquery, Variable 17 | 18 | -- Solution 2 is better in terms of automation. 19 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 20 | 21 | DECLARE @d date; 22 | SET @d = '2019-06-23'; 23 | 24 | SELECT book_id, name 25 | FROM Books 26 | WHERE available_from <= DATEADD(month, -1, @d) 27 | -- find books that have sold more than 10 copies in the last year 28 | AND book_id NOT IN ( 29 | SELECT book_id 30 | FROM Orders 31 | WHERE dispatch_date > DATEADD(year, -1, @d) 32 | GROUP BY book_id 33 | HAVING SUM(quantity) >= 10 34 | ); 35 | -------------------------------------------------------------------------------- /Questions_by_ID/1107_New_Users_Daily_Count.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | -- Solution 1: Subquery, Variable 4 | DECLARE @d date; 5 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 6 | 7 | WITH tb1 AS ( 8 | SELECT user_id, MIN(activity_date) AS login_date 9 | FROM traffic 10 | WHERE activity = 'login' 11 | GROUP BY user_id) 12 | 13 | SELECT login_date, COUNT(*) AS user_count 14 | FROM tb1 15 | GROUP BY login_date 16 | HAVING login_date >= @d; 17 | 18 | 19 | 20 | -- Solution 2: Window Function, Subquery, Variable 21 | 22 | -- Using ROW_NUMBER() instead of RANK() or DENSE_RANK() 23 | -- to avoid return several rows when user login more than once at the first date 24 | 25 | DECLARE @d date; 26 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 27 | 28 | WITH tb1 AS ( 29 | SELECT *, 30 | ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY activity_date) AS r 31 | FROM Traffic 32 | WHERE activity = 'login' 33 | ) 34 | 35 | SELECT activity_date AS login_date, COUNT(*) AS user_count 36 | FROM tb1 37 | WHERE r = 1 38 | GROUP BY activity_date 39 | HAVING activity_date >= @d; 40 | -------------------------------------------------------------------------------- /Questions_by_ID/1112_Highest_Grade_For_Each_Student.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT *, 4 | ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY grade DESC, course_id) AS r 5 | FROM Enrollments 6 | ) 7 | 8 | SELECT student_id, course_id, grade 9 | FROM tb1 10 | WHERE r = 1 11 | ORDER BY student_id; 12 | 13 | 14 | 15 | -- Solution 2: Subquery, Join 16 | WITH tb1 AS ( 17 | SELECT student_id, MAX(grade) AS grade 18 | FROM Enrollments 19 | GROUP BY student_id 20 | ) 21 | 22 | SELECT e.student_id, MIN(course_id) AS course_id, e.grade 23 | FROM Enrollments e 24 | JOIN tb1 25 | ON e.student_id = tb1.student_id AND e.grade = tb1.grade 26 | GROUP BY e.student_id, e.grade 27 | ORDER BY e.student_id; 28 | -------------------------------------------------------------------------------- /Questions_by_ID/1113_Reported_Posts.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | -- Solution: Variable 4 | DECLARE @d date; 5 | SET @d = DATEADD(day,-1,'2019-07-05'); 6 | 7 | SELECT extra AS report_reason, 8 | COUNT(DISTINCT post_id) AS report_count 9 | FROM Actions 10 | WHERE Action_date = @d AND action = 'report' 11 | GROUP BY extra; 12 | -------------------------------------------------------------------------------- /Questions_by_ID/1126_Active_Businesses.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, CASE WHEN 2 | -- calculate average occurences of event types amont all business 3 | WITH tb1 AS ( 4 | SELECT *, 5 | AVG(occurences*1.0) OVER (PARTITION BY event_type) AS avg_oc 6 | FROM Events 7 | ) 8 | 9 | SELECT business_id 10 | FROM tb1 11 | GROUP BY business_id 12 | -- count number of event types of a business with occurences 13 | -- greater than the average occurences of that event type among all businesses 14 | HAVING SUM(CASE WHEN occurences > avg_oc THEN 1 ELSE 0 END) > 1; 15 | 16 | 17 | 18 | -- Solution 2: Subquery, Join 19 | -- calculate average occurences of event types amont all business 20 | WITH tb1 AS ( 21 | SELECT event_type, AVG(occurences*1.0) AS avg_oc 22 | FROM Events 23 | GROUP BY event_type 24 | ) 25 | 26 | SELECT business_id 27 | FROM Events e 28 | JOIN tb1 29 | -- use join to keep only records in which event type of a business with occurences 30 | -- greater than the average occurences of that event type among all businesses 31 | ON e.event_type = tb1.event_type AND e.occurences > tb1.avg_oc 32 | GROUP BY business_id 33 | HAVING COUNT(*) > 1; 34 | -------------------------------------------------------------------------------- /Questions_by_ID/1127_User_Purchase_Platform.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Window Function, Subquery, Join 2 | -- judge whether user used mobile only, desktop only or both mobile and desktop together for each date 3 | WITH tb1 AS ( 4 | SELECT user_id,spend_date,amount, 5 | CASE 6 | WHEN COUNT(*) OVER (PARTITION BY user_id, spend_date) = 1 THEN platform 7 | ELSE 'both' 8 | END AS platform 9 | FROM Spending 10 | ), 11 | -- calculate the total amount each user spent by date along with platform information 12 | tb2 AS ( 13 | SELECT spend_date, platform, 14 | SUM(amount) AS total_amount, 15 | COUNT(DISTINCT user_id) AS total_users 16 | FROM tb1 17 | GROUP BY spend_date, platform 18 | ), 19 | d AS ( 20 | SELECT DISTINCT spend_date 21 | FROM tb2 22 | ), 23 | p AS ( 24 | SELECT 'desktop' AS platform 25 | UNION 26 | SELECT 'mobile' 27 | UNION 28 | SELECT 'both' 29 | ) 30 | 31 | SELECT d.spend_date, p.platform, 32 | ISNULL(total_amount,0) AS total_amount, 33 | ISNULL(total_users,0) AS total_users 34 | FROM d 35 | CROSS JOIN p 36 | LEFT JOIN tb2 37 | ON d.spend_date = tb2.spend_date and p.platform = tb2.platform; 38 | -------------------------------------------------------------------------------- /Questions_by_ID/1132_Reported_Posts_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join, Subquery 2 | WITH tb1 AS ( 3 | SELECT COUNT(DISTINCT r.post_id)*100.0/COUNT(DISTINCT a.post_id) AS daily_p 4 | FROM Actions a 5 | LEFT JOIN Removals r 6 | ON a.post_id = r.post_id 7 | WHERE a.action = 'report' AND a.extra = 'spam' 8 | GROUP BY a.action_date 9 | ) 10 | 11 | SELECT CAST(AVG(daily_p) AS DECIMAL(5,2)) AS average_daily_percent 12 | FROM tb1; 13 | -------------------------------------------------------------------------------- /Questions_by_ID/1141_User_Activity_for_the_Past_30_Days_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT activity_date AS day, COUNT(DISTINCT user_id) AS active_users 3 | FROM Activity 4 | GROUP BY activity_date 5 | HAVING activity_date BETWEEN DATEADD(day,-29,'2019-07-27') and '2019-07-27'; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1142_User_Activity_for_the_Past_30_Days_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: IIF 2 | SELECT CAST( 3 | COUNT(DISTINCT session_id)*1.0 4 | / 5 | IIF(COUNT(DISTINCT user_id) > 0,COUNT(DISTINCT user_id) ,1) 6 | AS DECIMAL(10,2) 7 | ) AS average_sessions_per_user 8 | FROM Activity 9 | WHERE activity_date BETWEEN DATEADD(day,-29,'2019-07-27') and '2019-07-27'; 10 | 11 | 12 | 13 | -- Solution 2: Subquery 14 | WITH tb1 AS( 15 | SELECT COUNT(DISTINCT session_id) AS num 16 | FROM activity 17 | WHERE activity_date BETWEEN DATEADD(day,-29,'2019-07-27') and '2019-07-27' 18 | GROUP BY user_id 19 | ) 20 | 21 | SELECT CAST( 22 | ISNULL(AVG(num*1.0),0) 23 | AS DECIMAL(10,2) 24 | ) AS average_sessions_per_user 25 | FROM tb1; 26 | -------------------------------------------------------------------------------- /Questions_by_ID/1148_Article_Views_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT DISTINCT author_id AS id 3 | FROM Views 4 | WHERE author_id = viewer_id 5 | ORDER BY id; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1149_Article_Views_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT DISTINCT viewer_id AS id 3 | FROM Views 4 | GROUP BY viewer_id, view_date 5 | -- When viewer viewed the same article more than once in the same day, using DISTINCT could avoid count that article twice 6 | HAVING COUNT(DISTINCT article_id) > 1 7 | ORDER BY id; 8 | -------------------------------------------------------------------------------- /Questions_by_ID/1158_Market_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, CASE WHEN 2 | SELECT u.user_id AS buyer_id, u.join_date AS join_date, 3 | SUM(CASE WHEN YEAR(order_date) = 2019 THEN 1 ELSE 0 END) AS orders_in_2019 4 | FROM Users u 5 | LEFT JOIN Orders o 6 | ON u.user_id = o.buyer_id 7 | GROUP BY u.user_id, u.join_date; 8 | 9 | 10 | 11 | -- Solution 2: Subquery, Join 12 | WITH tb1 AS ( 13 | SELECT buyer_id, COUNT(*) AS num 14 | FROM orders 15 | WHERE YEAR(order_date) = 2019 16 | GROUP BY buyer_id 17 | ) 18 | 19 | SELECT u.user_id AS buyer_id, u.join_date, ISNULL(num, 0) AS orders_in_2019 20 | FROM users u 21 | LEFT JOIN tb1 o 22 | ON u.user_id = o.buyer_id; 23 | -------------------------------------------------------------------------------- /Questions_by_ID/1159_Market_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, Join, CASE WHEN 2 | -- get item_id of the second item (by date) they sold for each user 3 | WITH tb1 AS ( 4 | SELECT seller_id, item_id 5 | FROM ( 6 | SELECT seller_id, item_id, 7 | ROW_NUMBER() OVER (PARTITION BY seller_id ORDER BY order_date) AS r 8 | FROM Orders 9 | ) rank 10 | WHERE r = 2 11 | ) 12 | 13 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 14 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 15 | SELECT u.user_id AS seller_id, 16 | CASE 17 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 18 | ELSE 'no' 19 | END AS '2nd_item_fav_brand' 20 | FROM Users u 21 | LEFT JOIN tb1 22 | ON u.user_id = tb1.seller_id 23 | LEFT JOIN Items i 24 | ON tb1.item_id = i.item_id; 25 | 26 | 27 | 28 | -- Solution 2: Join, Subquery, CASE WHEN 29 | -- get item_id of the second item (by date) they sold for each user (having only two sales records on or before o1.order_date) 30 | WITH tb1 AS ( 31 | SELECT o1.seller_id, o1.item_id 32 | FROM Orders o1 33 | JOIN orders o2 34 | ON o1.seller_id = o2.seller_id AND o1.order_date >= o2.order_date 35 | GROUP BY o1.seller_id, o1.order_date, o1.item_id 36 | HAVING COUNT(*) = 2 37 | ) 38 | 39 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 40 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 41 | SELECT u.user_id AS seller_id, 42 | CASE 43 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 44 | ELSE 'no' 45 | END AS '2nd_item_fav_brand' 46 | FROM Users u 47 | LEFT JOIN tb1 48 | ON u.user_id = tb1.seller_id 49 | LEFT JOIN Items i 50 | ON tb1.item_id = i.item_id; 51 | -------------------------------------------------------------------------------- /Questions_by_ID/1173_Immediate_Food_Delivery_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN 2 | SELECT CAST( 3 | AVG( 4 | -- using 100.0 rather than 100 is to ensure the type of number is float 5 | -- so that the number will keep digits after the decimal point when averaging 6 | CASE 7 | WHEN order_date = customer_pref_delivery_date THEN 100.0 8 | ELSE 0 9 | END 10 | ) 11 | AS DECIMAL(5,2) 12 | ) AS immediate_percentage 13 | FROM Delivery; 14 | -------------------------------------------------------------------------------- /Questions_by_ID/1174_Immediate_Food_Delivery_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, CASE WHEN 2 | WITH tb1 AS ( 3 | -- fod refers to first order date, and fdd refers to first delivery date 4 | SELECT MIN(order_date) AS fod, MIN(customer_pref_delivery_date) AS fdd 5 | FROM Delivery 6 | GROUP BY customer_id 7 | ) 8 | 9 | -- Since it is guaranteed that a customer has exactly one first order, 10 | -- when fod = fdd, the first order of that customer must be immediate order 11 | SELECT CAST( 12 | AVG( 13 | CASE 14 | WHEN fod = fdd THEN 100.0 15 | ELSE 0 16 | END 17 | ) 18 | AS DECIMAL(5,2) 19 | ) AS immediate_percentage 20 | FROM tb1; 21 | 22 | 23 | 24 | -- Solution 2: Window Function, Subquery, CASE WHEN 25 | WITH tb1 AS ( 26 | SELECT order_date, customer_pref_delivery_date, 27 | -- identify first order of each customer 28 | ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS r 29 | FROM delivery 30 | ) 31 | 32 | SELECT CAST( 33 | AVG( 34 | CASE 35 | WHEN order_date = customer_pref_delivery_date THEN 100.0 36 | ELSE 0 37 | END 38 | ) 39 | AS DECIMAL(5,2) 40 | ) AS immediate_percentage 41 | FROM tb1 42 | WHERE r = 1; 43 | -------------------------------------------------------------------------------- /Questions_by_ID/1179_Reformat_Department_Table.sql: -------------------------------------------------------------------------------- 1 | -- Solution: PIVOT/UNPIVOT 2 | SELECT id, 3 | "Jan" as Jan_Revenue, 4 | "Feb" as Feb_Revenue, 5 | "Mar" as Mar_Revenue, 6 | "Apr" as Apr_Revenue, 7 | "May" as May_Revenue, 8 | "Jun" as Jun_Revenue, 9 | "Jul" as Jul_Revenue, 10 | "Aug" as Aug_Revenue, 11 | "Sep" as Sep_Revenue, 12 | "Oct" as Oct_Revenue, 13 | "Nov" as Nov_Revenue, 14 | "Dec" as Dec_Revenue 15 | FROM department 16 | PIVOT ( 17 | MAX(revenue) 18 | FOR month IN ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec") 19 | ) AS pvt; 20 | -------------------------------------------------------------------------------- /Questions_by_ID/1193_Monthly_Transactions_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN 2 | SELECT LEFT(trans_date,7) AS month, country, 3 | COUNT(id) AS trans_count, 4 | SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count, 5 | SUM(amount) AS trans_total_amount, 6 | SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amount 7 | FROM Transactions 8 | GROUP BY LEFT(trans_date,7), country; 9 | 10 | 11 | 12 | -- Solution 2: CASE WHEN 13 | -- Using FORMAT to increase stability 14 | SELECT FORMAT(trans_date,'yyyy-MM') AS month, country, 15 | COUNT(id) AS trans_count, 16 | SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count, 17 | SUM(amount) AS trans_total_amount, 18 | SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amount 19 | FROM Transactions 20 | GROUP BY FORMAT(trans_date,'yyyy-MM'), country; 21 | -------------------------------------------------------------------------------- /Questions_by_ID/1204_Last_Person_to_Fit_in_the_Elevator.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT TOP 1 person_name 3 | FROM ( 4 | SELECT person_name, turn, 5 | SUM(weight) OVER (ORDER BY turn) AS tw 6 | FROM Queue 7 | ) tb1 8 | WHERE tw <= 1000 9 | ORDER BY turn DESC; 10 | 11 | 12 | 13 | -- Solution 2: Join 14 | SELECT TOP 1 q1.person_name 15 | FROM Queue q1 16 | JOIN Queue q2 17 | ON q1.turn >= q2.turn 18 | GROUP BY q1.person_id, q1.person_name 19 | HAVING SUM(q2.weight) <= 1000 20 | ORDER BY SUM(q2.weight) DESC; 21 | -------------------------------------------------------------------------------- /Questions_by_ID/1205_Monthly_Transactions_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery, Join 2 | -- find the number of approved transactions and their total amount for each month and country 3 | WITH tb1 AS ( 4 | SELECT LEFT(trans_date,7) AS month, country, 5 | COUNT(state) AS approved_count, 6 | SUM(amount) AS approved_amount 7 | FROM Transactions 8 | WHERE state = 'approved' 9 | GROUP BY LEFT(trans_date,7), country 10 | ), 11 | -- find the number of chargebacks and their total amount for each month and country 12 | tb2 AS ( 13 | SELECT LEFT(c.trans_date,7) AS month, country, 14 | COUNT(c.trans_id) AS chargeback_count, 15 | SUM(t.amount) AS chargeback_amount 16 | FROM Chargebacks c 17 | JOIN Transactions t 18 | ON c.trans_id = t.id 19 | GROUP BY LEFT(c.trans_date,7), country 20 | ) 21 | 22 | -- when there is no approved transactions or chargebacks for a country in a certain month, 23 | -- replace the NULL with 0 24 | SELECT COALESCE(tb1.month,tb2.month) AS month, 25 | COALESCE(tb1.country,tb2.country) AS country, 26 | ISNULL(tb1.approved_count,0) AS approved_count, 27 | ISNULL(tb1.approved_amount,0) AS approved_amount, 28 | ISNULL(tb2.chargeback_count,0) AS chargeback_count, 29 | ISNULL(tb2.chargeback_amount,0) AS chargeback_amount 30 | FROM tb1 31 | FULL OUTER JOIN tb2 32 | ON tb1.month = tb2.month AND tb1.country = tb2.country; 33 | -------------------------------------------------------------------------------- /Questions_by_ID/1211_Queries_Quality_and_Percentage.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN 2 | SELECT query_name, 3 | CAST( 4 | AVG(rating*1.0/position) 5 | AS DECIMAL(10,2) 6 | ) AS quality, 7 | CAST( 8 | AVG(CASE WHEN rating < 3 THEN 100.0 ELSE 0 END) 9 | AS DECIMAL(10,2) 10 | ) AS poor_query_percentage 11 | FROM Queries 12 | GROUP BY query_name; 13 | -------------------------------------------------------------------------------- /Questions_by_ID/1212_Team_Scores_in_Football_Tournament.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN, Join 2 | SELECT team_id, team_name, 3 | SUM( 4 | CASE WHEN team_id = host_team AND host_goals > guest_goals THEN 3 5 | WHEN team_id = guest_team AND guest_goals > host_goals THEN 3 6 | WHEN host_goals = guest_goals THEN 1 7 | ELSE 0 8 | END 9 | ) AS num_points 10 | FROM Teams t 11 | LEFT JOIN Matches m 12 | ON t.team_id = m.host_team OR t.team_id = m.guest_team 13 | GROUP BY team_id, team_name 14 | ORDER BY num_points DESC, team_id; 15 | -------------------------------------------------------------------------------- /Questions_by_ID/1225_Report_Contiguous_Dates.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, Window Function 2 | WITH tb1 AS ( 3 | SELECT fail_date AS date, 'failed' AS s 4 | FROM Failed 5 | UNION 6 | SELECT success_date AS date, 'succeeded' AS s 7 | FROM Succeeded 8 | ), 9 | tb2 AS ( 10 | SELECT *, 11 | ROW_NUMBER() OVER (PARTITION BY s ORDER BY date) AS r, 12 | ROW_NUMBER() OVER (ORDER BY date) AS r2 13 | FROM tb1 14 | WHERE Year(date) = 2019 15 | ) 16 | 17 | -- contiguous dates with same period state share the same r2-r, 18 | -- so in a group with same r2-4, the smallest date is start date and the largest date is end date 19 | SELECT s AS period_state, MIN(date) AS start_date, MAX(date) AS end_date 20 | FROM tb2 21 | GROUP BY r2-r, s 22 | ORDER BY start_date; 23 | 24 | 25 | 26 | -- Solution 2: Join, Subquery 27 | WITH tb1 AS ( 28 | -- numbering date with different states in chronological order separately 29 | SELECT f1.fail_date AS date, 'failed' AS s, COUNT(*) AS r 30 | FROM Failed f1 31 | JOIN Failed f2 32 | ON f1.fail_date >= f2.fail_date 33 | GROUP BY f1.fail_date 34 | UNION 35 | SELECT s1.success_date AS date, 'succeeded' AS s, COUNT(*) AS r 36 | FROM Succeeded s1 37 | JOIN Succeeded s2 38 | ON s1.success_date >= s2.success_date 39 | GROUP BY s1.success_date 40 | ), 41 | tb2 AS ( 42 | SELECT *, 43 | -- numbering date in chronological order 44 | DATEPART(dayofyear, date) AS r2 45 | FROM tb1 46 | WHERE Year(date) = 2019 47 | ) 48 | 49 | -- contiguous dates with same period state share the same r2-r, 50 | -- so in a group with same r2-4, the smallest date is start date and the largest date is end date 51 | SELECT s AS period_state, MIN(date) AS start_date, MAX(date) AS end_date 52 | FROM tb2 53 | GROUP BY r2-r, s 54 | ORDER BY start_date; 55 | -------------------------------------------------------------------------------- /Questions_by_ID/1241_Number_of_Comments_per_Post.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT s1.sub_id AS post_id, COUNT(DISTINCT s2.sub_id) AS number_of_comments 3 | FROM Submissions s1 4 | LEFT JOIN Submissions s2 5 | -- Orginal posts are in left table, and comments are in right table 6 | ON s1.sub_id = s2.parent_id 7 | WHERE s1.parent_id IS NULL 8 | GROUP BY s1.sub_id; 9 | -------------------------------------------------------------------------------- /Questions_by_ID/1251_Average_Selling_Price.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT u.product_id, 3 | CAST( 4 | SUM(price*units) * 1.0 / SUM(units) 5 | AS DECIMAL(10,2) 6 | ) AS average_price 7 | FROM UnitsSold u 8 | JOIN Prices p 9 | ON u.product_id = p.product_id 10 | AND u.purchase_date >= p.start_date 11 | AND u.purchase_date <= p.end_date 12 | GROUP BY u.product_id; 13 | -------------------------------------------------------------------------------- /Questions_by_ID/1264_Page_Recommendations.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN, Subquery 2 | WITH f AS ( 3 | SELECT CASE WHEN user1_id = 1 THEN user2_id ELSE user1_id END AS fid 4 | FROM Friendship 5 | WHERE user1_id = 1 OR user2_id =1 6 | ) 7 | 8 | SELECT DISTINCT page_id AS recommended_page 9 | FROM Likes 10 | WHERE user_id IN (SELECT * FROM f) 11 | EXCEPT 12 | SELECT page_id 13 | FROM Likes 14 | WHERE user_id = 1; 15 | -------------------------------------------------------------------------------- /Questions_by_ID/1270_All_People_Report_to_the_Given_Manager.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Recursive CTE, Join 2 | -- find employees directly report to managers directly, 3 | -- and then find people who report to managers indirectly using cte 4 | WITH cte AS ( 5 | SELECT employee_id 6 | FROM Employees 7 | WHERE manager_id = 1 AND employee_id != manager_id 8 | UNION ALL 9 | SELECT e.employee_id 10 | FROM Employees e 11 | JOIN cte 12 | ON e.manager_id = cte.employee_id 13 | ) 14 | 15 | SELECT employee_id 16 | FROM cte 17 | OPTION (MAXRECURSION 3); 18 | 19 | 20 | -- Solution 2: Subquery 21 | With tb1 AS ( 22 | SELECT employee_id 23 | FROM Employees 24 | WHERE manager_id = 1 AND employee_id != manager_id 25 | ), 26 | tb2 AS ( 27 | SELECT employee_id 28 | FROM Employees 29 | WHERE manager_id IN (SELECT * FROM tb1) 30 | ), 31 | tb3 AS ( 32 | SELECT employee_id 33 | FROM Employees 34 | WHERE manager_id IN (SELECT * FROM tb2) 35 | ) 36 | 37 | SELECT * 38 | FROM tb1 39 | UNION 40 | SELECT * 41 | FROM tb2 42 | UNION 43 | SELECT * 44 | FROM tb3; 45 | -------------------------------------------------------------------------------- /Questions_by_ID/1280_Students_and_Examinations.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT s.student_id, s.student_name, b.subject_name, 3 | ( 4 | SELECT COUNT(*) 5 | From Examinations 6 | WHERE student_id = s.student_id AND subject_name = b.subject_name 7 | ) AS attended_exams 8 | FROM Students s, Subjects b 9 | ORDER BY s.student_id, b.subject_name; 10 | 11 | 12 | 13 | -- Solution 2: Join 14 | SELECT s.student_id, s.student_name, b.subject_name, 15 | COUNT(e.student_id) AS attended_exams 16 | FROM students s 17 | CROSS JOIN subjects b 18 | LEFT JOIN examinations e 19 | ON s.student_id = e.student_id AND b.subject_name = e.subject_name 20 | GROUP BY s.student_id, s.student_name, b.subject_name 21 | ORDER BY s.student_id, b.subject_name; 22 | -------------------------------------------------------------------------------- /Questions_by_ID/1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | -- when the number is continous with the last one, both log_id and r add 1 3 | -- Therefore, continuous numbers share the same log_id - r 4 | -- when grouped by log_id - r, the start number is the samllest number in group and the end is the largest 5 | WITH tb1 AS ( 6 | SELECT log_id, ROW_NUMBER() OVER (ORDER BY log_id) AS r 7 | FROM Logs 8 | ) 9 | 10 | SELECT MIN(log_id) AS START_ID, MAX(log_id) AS END_ID 11 | FROM tb1 12 | GROUP BY log_id-r; 13 | 14 | 15 | 16 | -- Solution 2: Join, Subquery 17 | WITH tb1 AS ( 18 | SELECT l1.log_id, COUNT(*) AS r 19 | FROM Logs l1 20 | JOIN Logs l2 21 | ON l1.log_id >= l2.log_id 22 | GROUP BY l1.log_id 23 | ) 24 | 25 | SELECT MIN(log_id) AS START_ID, MAX(log_id) AS END_ID 26 | FROM tb1 27 | GROUP BY log_id-r; 28 | -------------------------------------------------------------------------------- /Questions_by_ID/1294_Weather_Type_in_Each_Country.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN, Subquery, Join 2 | SELECT c.country_name, w.weather_type 3 | FROM ( 4 | SELECT country_id, 5 | CASE 6 | WHEN AVG(weather_state*1.0) <= 15 THEN 'Cold' 7 | WHEN AVG(weather_state*1.0) >= 25 THEN 'Hot' 8 | ELSE 'Warm' 9 | END AS weather_type 10 | FROM Weather 11 | WHERE LEFT(day,7) = '2019-11' 12 | GROUP BY country_id 13 | ) w 14 | JOIN Countries c 15 | ON w.country_id = c.country_id; 16 | -------------------------------------------------------------------------------- /Questions_by_ID/1303_Find_the_Team_Size.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function 2 | SELECT employee_id, 3 | COUNT(*) OVER (PARTITION BY team_id) AS team_size 4 | FROM Employee; 5 | 6 | 7 | 8 | -- Solution 2: Join 9 | SELECT e1.employee_id, COUNT(*) AS team_size 10 | FROM Employee e1 11 | JOIN Employee e2 12 | ON e1.team_id = e2.team_id 13 | GROUP BY e1.employee_id; 14 | -------------------------------------------------------------------------------- /Questions_by_ID/1308_Running_Total_for_Different_Genders.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function 2 | SELECT DISTINCT gender, day, 3 | SUM(score_points) OVER (PARTITION BY gender ORDER BY day) AS total 4 | FROM Scores 5 | ORDER BY gender, day; 6 | 7 | 8 | 9 | -- Solution 2: Join 10 | SELECT s1.gender, s1.day, SUM(s2.score_points) AS total 11 | FROM Scores s1 12 | JOIN Scores s2 13 | ON s1.gender = s2.gender AND s1.day >= s2.day 14 | GROUP BY s1.gender, s1.day 15 | ORDER BY s1.gender, s1.day; 16 | -------------------------------------------------------------------------------- /Questions_by_ID/1321_Restaurant_Growth.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, OFFSET FETCH 2 | SELECT visited_on, 3 | SUM(SUM(amount)) OVER ( 4 | ORDER BY visited_on 5 | ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 6 | ) AS amount, 7 | CAST( 8 | SUM(SUM(amount)) OVER ( 9 | ORDER BY visited_on 10 | ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 11 | )/7.0 12 | AS DECIMAL(10,2) 13 | ) AS average_amount 14 | FROM Customer 15 | GROUP BY visited_on 16 | ORDER BY visited_on 17 | OFFSET 6 ROWS; 18 | 19 | 20 | 21 | -- Solution 2: Subquery, Join 22 | WITH total AS ( 23 | SELECT visited_on, SUM(amount) AS amount 24 | FROM Customer 25 | GROUP BY visited_on 26 | ) 27 | 28 | SELECT t1.visited_on, 29 | SUM(t2.amount) AS amount, 30 | CAST(AVG(t2.amount*1.0) AS DECIMAL(10,2)) AS average_amount 31 | FROM total t1 32 | JOIN total t2 33 | ON t1.visited_on >= t2.visited_on AND t1.visited_on <= DATEADD(day,6,t2.visited_on) 34 | GROUP BY t1.visited_on 35 | HAVING COUNT(t2.visited_on) = 7 36 | ORDER BY t1.visited_on; 37 | -------------------------------------------------------------------------------- /Questions_by_ID/1322_Ads_Performance.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN 2 | SELECT ad_id, 3 | CAST( 4 | ISNULL( 5 | AVG( 6 | CASE 7 | WHEN action = 'Clicked' THEN 100.0 8 | WHEN action = 'Viewed' THEN 0 9 | ELSE NULL 10 | END 11 | ) 12 | ,0) 13 | AS DECIMAL(5,2) 14 | ) AS ctr 15 | FROM Ads 16 | GROUP BY ad_id 17 | ORDER BY ctr DESC, ad_id; 18 | 19 | 20 | 21 | -- Solution 2: Subquery, PIVOT/UNPIVOT, CASE WHEN 22 | WITH tb1 AS ( 23 | SELECT ad_id, [Clicked], [Viewed], [Ignored] 24 | FROM Ads 25 | PIVOT ( 26 | COUNT(action) FOR action IN ([Clicked], [Viewed], [Ignored]) 27 | ) pvt 28 | ) 29 | 30 | SELECT ad_id, 31 | CASE 32 | WHEN SUM(Clicked+Viewed) = 0 THEN 0.0 33 | ELSE CAST(SUM(Clicked)*100.0/SUM(Clicked+Viewed) AS DECIMAL(5,2)) 34 | END AS ctr 35 | FROM tb1 36 | GROUP BY ad_id 37 | ORDER BY ctr DESC, ad_id; 38 | -------------------------------------------------------------------------------- /Questions_by_ID/1327_List_the_Products_Ordered_in_a_Period.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT MIN(p.product_name) AS product_name, SUM(unit) AS unit 3 | FROM Orders o 4 | JOIN Products p 5 | ON o.product_id = p.product_id 6 | WHERE YEAR(o.order_date) = 2020 AND MONTH(o.order_date) = 2 7 | GROUP BY p.product_id 8 | HAVING SUM(unit) >= 100; 9 | -------------------------------------------------------------------------------- /Questions_by_ID/1336_Number_of_Transactions_per_Visit.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join, Recursive CTE, Subquery 2 | -- find number of transactions done for each visit 3 | WITH tb1 AS ( 4 | SELECT v.user_id, v.visit_date, COUNT(t.transaction_date) AS c 5 | FROM Visits v 6 | LEFT JOIN Transactions t 7 | ON v.visit_date = t.transaction_date AND v.user_id = t.user_id 8 | GROUP BY v.user_id, v.visit_date 9 | ), 10 | -- get all values from 0 to max(transactions_count) done by one or more users 11 | cte AS ( 12 | SELECT MAX(c) AS c 13 | FROM tb1 14 | UNION ALL 15 | SELECT c-1 16 | FROM cte 17 | WHERE c > 0 18 | ) 19 | 20 | -- count the corresponding number of users who did a certain transactions_count in one visit to the bank. 21 | SELECT cte.c AS transactions_count, 22 | COUNT(tb1.user_id) AS visits_count 23 | FROM cte 24 | LEFT JOIN tb1 25 | ON cte.c = tb1.c 26 | GROUP BY cte.c 27 | ORDER BY transactions_count; 28 | -------------------------------------------------------------------------------- /Questions_by_ID/1341_Movie_Rating.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery 2 | SELECT MIN(name) AS results 3 | FROM Users 4 | WHERE user_id IN ( 5 | -- find users who rated greatest number of the movies 6 | SELECT TOP 1 WITH TIES user_id 7 | FROM Movie_Rating 8 | GROUP BY user_id 9 | ORDER BY COUNT(DISTINCT movie_id) DESC 10 | ) 11 | UNION ALL 12 | SELECT MIN(title) AS results 13 | FROM Movies 14 | WHERE movie_id IN ( 15 | -- find movies with highest average rating in Feb. 2020 16 | SELECT TOP 1 WITH TIES movie_id 17 | FROM Movie_Rating 18 | WHERE YEAR(created_at) = 2020 AND MONTH(created_at) = 2 19 | GROUP BY movie_id 20 | ORDER BY AVG(rating*1.0) DESC 21 | ); 22 | -------------------------------------------------------------------------------- /Questions_by_ID/1350_Students_With_Invalid_Departments.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT id, name 3 | FROM Students 4 | WHERE department_id NOT IN (SELECT id FROM Departments); 5 | 6 | 7 | 8 | -- Solution 2: Join 9 | SELECT s.id, s.name 10 | FROM Students s 11 | LEFT JOIN Departments d 12 | ON s.department_id = d.id 13 | WHERE d.id IS NULL; 14 | -------------------------------------------------------------------------------- /Questions_by_ID/1355_Activity_Participants.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT activity 3 | FROM ( 4 | SELECT activity, 5 | -- Numbering activity by number of participants in ascending and descending order 6 | RANK() OVER (ORDER BY COUNT(*)) AS r1, 7 | RANK() OVER (ORDER BY COUNT(*) DESC) AS r2 8 | FROM Friends 9 | GROUP BY activity 10 | ) tb1 11 | -- fliter out activities with minimum or maximum number of participants 12 | WHERE r1 != 1 AND r2 != 1; 13 | 14 | 15 | 16 | -- Solution 2: Subquery 17 | WITH tb1 AS ( 18 | SELECT activity, COUNT(*) AS num 19 | FROM Friends 20 | GROUP BY activity 21 | ) 22 | 23 | SELECT activity 24 | FROM tb1 25 | WHERE num NOT IN ( 26 | SELECT MAX(num) FROM tb1 27 | UNION ALL 28 | SELECT MIN(num) FROM tb1 29 | ); 30 | -------------------------------------------------------------------------------- /Questions_by_ID/1364_Number_of_Trusted_Contacts_of_a_Customer.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join, Subquery 2 | WITH tb1 AS ( 3 | SELECT c.customer_id, c.customer_name, 4 | COUNT(con.contact_name) AS contacts_cnt, 5 | COUNT(c2.customer_id) AS trusted_contacts_cnt 6 | FROM Customers c 7 | LEFT JOIN Contacts con 8 | ON c.customer_id = con.user_id 9 | LEFT JOIN Customers c2 10 | ON con.contact_email = c2.email 11 | GROUP BY c.customer_id, c.customer_name 12 | ) 13 | 14 | SELECT i.invoice_id, 15 | tb1.customer_name, 16 | i.price, 17 | tb1.contacts_cnt, 18 | tb1.trusted_contacts_cnt 19 | FROM Invoices i 20 | JOIN tb1 21 | ON i.user_id = tb1.customer_id 22 | ORDER BY i.invoice_id; 23 | -------------------------------------------------------------------------------- /Questions_by_ID/1369_Get_the_Second_Most_Recent_Activity.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT username, activity, startDate, endDate 3 | FROM ( 4 | SELECT *, 5 | ROW_NUMBER() OVER (PARTITION BY username ORDER BY endDate DESC) AS r, 6 | COUNT(*) OVER (PARTITION BY username) AS c 7 | FROM UserActivity 8 | ) tb1 9 | WHERE r = 2 OR c = 1; 10 | 11 | 12 | 13 | -- Solution 2: Join, Subquery 14 | WITH tb1 AS ( 15 | SELECT u1.username, u1.activity, u1.startDate, u1.endDate, COUNT(*) AS r 16 | FROM UserActivity u1 17 | JOIN UserActivity u2 18 | ON u1.username = u2.username AND u1.endDate <= u2.endDate 19 | GROUP BY u1.username, u1.activity, u1.startDate, u1.endDate 20 | ), 21 | tb2 AS ( 22 | SELECT username, COUNT(*) AS c 23 | FROM UserActivity 24 | GROUP BY username 25 | ) 26 | 27 | SELECT tb1.username, tb1.activity, tb1.startDate, tb1.endDate 28 | FROM tb1 29 | JOIN tb2 30 | ON tb1.username = tb2.username 31 | WHERE tb1.r = 2 OR tb2.c = 1; 32 | -------------------------------------------------------------------------------- /Questions_by_ID/1378_Replace_Employee_ID_With_The_Unique_Identifier.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT u.unique_id, e.name 3 | FROM Employees e 4 | LEFT JOIN EmployeeUNI u 5 | ON e.id = u.id; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/1384_Total_Sales_Amount_by_Year.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Recursive CTE, Join 2 | -- get all dates from MIN(period_start) to MAX(period_end) 3 | WITH cte AS ( 4 | SELECT MIN(period_start) AS date, MAX(period_end) AS end_date 5 | FROM Sales 6 | UNION ALL 7 | SELECT DATEADD(day,1,date), end_date 8 | FROM cte 9 | WHERE date < end_date 10 | ) 11 | 12 | -- after join, products will have same number of records as the number of days in sale period 13 | SELECT s.product_id AS PRODUCT_ID, 14 | p.product_name AS PRODUCT_NAME, 15 | CAST(Year(cte.date) AS CHAR(4)) AS REPORT_YEAR, 16 | SUM(average_daily_sales) AS TOTAL_AMOUNT 17 | FROM cte 18 | JOIN Sales s 19 | ON cte.date BETWEEN s.period_start AND s.period_end 20 | JOIN Product p 21 | ON s.product_id = p.product_id 22 | GROUP BY s.product_id, p.product_name, Year(cte.date) 23 | ORDER BY PRODUCT_ID, REPORT_YEAR 24 | OPTION (MAXRECURSION 0); 25 | -------------------------------------------------------------------------------- /Questions_by_ID/1393_Capital_Gain_Loss.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN 2 | -- For this question, the last operation of a stock is always "sell" 3 | -- and it is guaranteed that every "sell" has a "buy" before it, 4 | -- so we could simplify this to a CASE WHEN questions, otherwise, WINDOW FUNCTION could be a better choice 5 | SELECT stock_name, 6 | SUM( 7 | CASE 8 | WHEN operation = 'Buy' THEN -price 9 | ELSE price END 10 | ) AS capital_gain_loss 11 | FROM Stocks 12 | GROUP BY stock_name; 13 | -------------------------------------------------------------------------------- /Questions_by_ID/1398_Customers_Who_Bought_Products_A_and_B_but_Not_C.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN, Subquery 2 | WITH tb1 AS ( 3 | SELECT DISTINCT customer_id, product_name, 4 | CASE 5 | WHEN product_name IN ('A','B') THEN 1 6 | WHEN product_name = 'C' THEN -1 7 | ELSE 0 8 | END AS c 9 | FROM Orders 10 | ) 11 | 12 | SELECT * 13 | FROM Customers 14 | WHERE customer_id IN ( 15 | SELECT customer_id 16 | FROM tb1 17 | GROUP BY customer_id 18 | HAVING SUM(c) = 2 19 | ); 20 | 21 | 22 | 23 | -- Solution 2: Subquery 24 | SELECT * 25 | FROM Customers 26 | WHERE customer_id IN ( 27 | SELECT customer_id 28 | FROM Orders 29 | WHERE product_name = 'A' 30 | ) 31 | AND customer_id IN ( 32 | SELECT customer_id 33 | FROM Orders 34 | WHERE product_name = 'B' 35 | ) 36 | AND customer_id NOT IN ( 37 | SELECT customer_id 38 | FROM Orders 39 | WHERE product_name = 'C' 40 | ); 41 | -------------------------------------------------------------------------------- /Questions_by_ID/1407_Top_Travellers.sql: -------------------------------------------------------------------------------- 1 | SELECT name, 2 | -- 0 will be shown as distance if no record in table Rides 3 | COALESCE(SUM(distance),0) AS travelled_distance 4 | FROM Users 5 | LEFT JOIN Rides 6 | ON Users.id = Rides.user_id 7 | GROUP BY name 8 | ORDER BY travelled_distance DESC, name 9 | -------------------------------------------------------------------------------- /Questions_by_ID/1412_Find_The_Quiet_Students_in_All_Exams.sql: -------------------------------------------------------------------------------- 1 | -- rank scores in each exam by both ascending and descending orders 2 | -- if h_rank = 1 then the student has the highest score in according exam 3 | -- if r_rank = 1 then the student has the lowest score in that exam 4 | WITH rank_exam AS ( 5 | SELECT student_id, 6 | RANK() OVER (PARTITION BY exam_id ORDER BY score DESC) AS h_rank, 7 | RANK() OVER (PARTITION BY exam_id ORDER BY score) AS l_rank 8 | FROM Exam 9 | ) 10 | 11 | SELECT * 12 | FROM Student 13 | -- find the student who is quiet in ALL exams 14 | WHERE student_id NOT IN ( 15 | SELECT DISTINCT student_id 16 | FROM rank_exam 17 | WHERE l_rank = 1 OR h_rank = 1 18 | ) 19 | -- make sure student take at least one exam 20 | AND student_id IN (SELECT DISTINCT student_id FROM Exam) 21 | -------------------------------------------------------------------------------- /Questions_by_ID/175_Combine_Two_Tables.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT p.firstname, p.lastname, a.city, a.state 3 | FROM person p 4 | -- LEFT JOIN return all records from the left table, and the matched records from the right table 5 | LEFT JOIN address a 6 | ON p.personid = a.personid 7 | -------------------------------------------------------------------------------- /Questions_by_ID/176_Second_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT MAX(salary) AS secondhighestsalary 3 | FROM employee 4 | WHERE salary < (SELECT MAX(salary) FROM employee); 5 | 6 | 7 | 8 | -- Solution 1: Window Function 9 | SELECT AVG(salary) SecondHighestSalary 10 | FROM ( 11 | SELECT salary 12 | ,DENSE_RANK() OVER (ORDER BY salary DESC) r 13 | FROM employee 14 | ) tb1 15 | WHERE r = 2; 16 | 17 | 18 | 19 | -- Solution 1: OFFSET FETCH 20 | SELECT ( 21 | SELECT DISTINCT salary 22 | FROM employee 23 | ORDER BY salary DESC 24 | OFFSET 1 ROW 25 | FETCH NEXT 1 ROW ONLY 26 | ) AS SecondHighestSalary; 27 | -------------------------------------------------------------------------------- /Questions_by_ID/177_Nth_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function 2 | CREATE FUNCTION getNthHighestSalary(@N INT) RETURNS INT AS 3 | BEGIN 4 | RETURN ( 5 | SELECT AVG(salary) 6 | FROM ( 7 | SELECT salary, DENSE_RANK() over (ORDER BY salary DESC) r 8 | FROM employee 9 | ) tb1 10 | WHERE r = @N 11 | ); 12 | END 13 | */ 14 | 15 | -- Solution 2: OFFSET FETCH 16 | CREATE FUNCTION getNthHighestSalary(@N INT) RETURNS INT AS 17 | BEGIN 18 | RETURN ( 19 | SELECT DISTINCT salary 20 | FROM employee 21 | ORDER BY salary DESC 22 | OFFSET @N-1 ROW 23 | FETCH FIRST 1 ROW ONLY 24 | ); 25 | END 26 | -------------------------------------------------------------------------------- /Questions_by_ID/178_Rank_Scores.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Window Function 2 | SELECT score, DENSE_RANK() OVER (ORDER BY score DESC) AS Rank 3 | FROM scores; 4 | -------------------------------------------------------------------------------- /Questions_by_ID/180_Consecutive_Numbers.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Window Function 2 | SELECT DISTINCT num AS ConsecutiveNums 3 | FROM ( 4 | SELECT num, 5 | LEAD(num) OVER (ORDER BY id) AS next, 6 | LAG(num) OVER (ORDER BY id) AS prev 7 | FROM logs 8 | ) tb1 9 | WHERE num = next AND next = prev; 10 | 11 | 12 | 13 | -- Solution: Join 14 | SELECT DISTINCT l1.num AS ConsecutiveNums 15 | FROM logs l1 16 | JOIN logs l2 17 | ON l1.id = l2.id-1 AND l1.num = l2.num 18 | JOIN logs l3 19 | ON l1.id = l3.id-2 AND l2.num = l3.num; 20 | -------------------------------------------------------------------------------- /Questions_by_ID/181_Employees_Earning_More_Than_Their_Managers.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT e1.name AS Employee 3 | FROM employee e1 4 | JOIN employee e2 5 | ON e1.Managerid = e2.id 6 | WHERE e1.salary > e2.salary; 7 | -------------------------------------------------------------------------------- /Questions_by_ID/182_Duplicate_Emails.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT email 3 | FROM person 4 | GROUP BY email 5 | HAVING COUNT(*) > 1; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/183_Customers_Who_Never_Order.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join 2 | SELECT c.name AS customers 3 | FROM customers c 4 | LEFT JOIN orders o 5 | ON c.id = o.customerid 6 | WHERE o.id IS NULL; 7 | 8 | 9 | 10 | -- Solution 2: Subquery 11 | SELECT name AS customers 12 | FROM customers 13 | WHERE id NOT IN (SELECT customerid FROM Orders); 14 | -------------------------------------------------------------------------------- /Questions_by_ID/184_Department_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery, Join 2 | WITH max_salary AS ( 3 | SELECT departmentid, max(salary) AS max_salary 4 | FROM employee 5 | GROUP BY departmentid 6 | ) 7 | 8 | SELECT d.name department, e.name employee, e.salary 9 | FROM max_salary ms 10 | JOIN employee e 11 | ON ms.departmentid = e.departmentid AND ms.max_salary = e.salary 12 | JOIN department d 13 | ON e.departmentid = d.id; 14 | 15 | 16 | 17 | -- Solution: Subquery, Window Function 18 | SELECT department, employee, salary 19 | FROM ( 20 | SELECT d.name department, e.name employee ,salary, 21 | -- ranking salaries in each department 22 | -- the employee with highest salary will get r = 1 23 | DENSE_RANK() OVER ( 24 | PARTITION BY departmentid 25 | ORDER BY salary DESC) r 26 | FROM employee e 27 | JOIN department d 28 | ON e.departmentid = d.id 29 | ) AS tb1 30 | WHERE r = 1; 31 | -------------------------------------------------------------------------------- /Questions_by_ID/185_Department_Top_Three_Salaries.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Window Function 2 | SELECT department, employee, salary 3 | FROM ( 4 | SELECT d.name AS department, e.name AS employee, salary, 5 | DENSE_RANK() OVER ( 6 | PARTITION BY departmentid 7 | ORDER BY salary DESC 8 | ) AS r 9 | FROM employee e 10 | JOIN department d 11 | ON e.departmentid = d.id 12 | ) AS tb1 13 | WHERE r <= 3 14 | -------------------------------------------------------------------------------- /Questions_by_ID/196_Delete_Duplicate_Emails.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: SQL Command, Join 2 | DELETE p1 3 | FROM person p1 4 | JOIN person p2 5 | ON p1.email = p2.email AND p1.id > p2.id; 6 | 7 | 8 | 9 | -- Solution 2: SQL Command, Subquery 10 | DELETE FROM person 11 | WHERE id NOT IN ( 12 | SELECT * 13 | FROM ( 14 | SELECT MIN(id) AS id 15 | FROM person 16 | GROUP BY email 17 | ) tb1 18 | ); 19 | -------------------------------------------------------------------------------- /Questions_by_ID/197_Rising_Temperature.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join 2 | SELECT w2.id 3 | FROM weather w1 4 | JOIN weather w2 5 | ON DATEADD(day,1,w1.recorddate) = w2.recorddate 6 | WHERE w1.temperature < w2.temperature; 7 | 8 | 9 | 10 | -- Solution 2: Window Function, Subquery 11 | SELECT id 12 | FROM ( 13 | SELECT *, 14 | -- Get temperature and date of previous record date, if none get null 15 | LAG(temperature) OVER (ORDER BY recorddate) AS prev_temp, 16 | LAG(recorddate) OVER (ORDER BY recorddate) prev_date 17 | FROM weather 18 | ) tb1 19 | WHERE DATEADD(day,1,prev_date) = recorddate AND prev_temp < temperature; 20 | -------------------------------------------------------------------------------- /Questions_by_ID/262_Trips_and_Users.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, CASE WHEN 2 | WITH t1 AS ( 3 | SELECT request_at, 4 | CASE 5 | WHEN status = 'completed' then 0 6 | ELSE 1.0 7 | END AS status 8 | FROM trips t 9 | -- filter our banned client and driver and limit time frame 10 | WHERE client_id NOT IN (SELECT users_id FROM users WHERE banned = 'Yes') 11 | AND driver_id NOT IN (SELECT users_id FROM users WHERE banned = 'Yes') 12 | AND request_at BETWEEN '2013-10-01' AND '2013-10-03' 13 | ) 14 | 15 | SELECT request_at AS 'Day', 16 | CAST(AVG(status) AS DECIMAL(4,2)) AS 'Cancellation Rate' 17 | FROM t1 18 | GROUP BY request_at; 19 | 20 | 21 | 22 | -- Solution 2: Join, CASE WHEN 23 | SELECT t.Request_at AS 'Day', 24 | CAST( 25 | AVG(CASE 26 | WHEN status = 'completed' then 0 27 | ELSE 1.0 28 | END) 29 | AS DECIMAL(3,2) 30 | ) AS 'Cancellation Rate' 31 | FROM Trips AS t 32 | INNER JOIN Users c 33 | ON t.Client_Id=c.Users_Id 34 | INNER JOIN Users d 35 | ON t.Driver_Id=d.Users_Id 36 | -- filter our banned client and driver and limit time frame 37 | WHERE c.Banned='no' AND 38 | d.Banned='no' AND 39 | t.Request_at BETWEEN '2013-10-01' AND '2013-10-03' 40 | GROUP BY t.Request_at; 41 | -------------------------------------------------------------------------------- /Questions_by_ID/511_Game_Play_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT player_id, MIN(event_date) AS first_login 3 | FROM activity 4 | GROUP BY player_id; 5 | -------------------------------------------------------------------------------- /Questions_by_ID/512_Game_Play_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT player_id, device_id 3 | FROM Activity 4 | WHERE concat(player_id,event_date) IN ( 5 | SELECT concat(player_id, MIN(event_date)) 6 | FROM Activity 7 | GROUP BY player_id 8 | ); 9 | 10 | 11 | 12 | -- Solution 2: Join, Subquery 13 | SELECT a.player_id, device_id 14 | FROM Activity a 15 | JOIN ( 16 | SELECT player_id, MIN(event_date) min_date 17 | FROM Activity 18 | GROUP BY player_id 19 | ) tb1 20 | ON a.player_id = tb1.player_id AND a.event_date = tb1.min_date; 21 | 22 | 23 | 24 | -- Solution 3: Window Function, Subquery 25 | SELECT player_id, device_id 26 | FROM ( 27 | SELECT player_id, device_id, 28 | DENSE_RANK() OVER (PARTITION BY player_id ORDER BY event_date) AS r 29 | FROM Activity) tb1 30 | WHERE r = 1; 31 | 32 | -------------------------------------------------------------------------------- /Questions_by_ID/534_Game_Play_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function 2 | SELECT player_id, event_date, 3 | SUM(games_played) OVER ( 4 | PARTITION BY player_id 5 | ORDER BY event_date 6 | ) AS games_played_so_far 7 | FROM activity; 8 | 9 | 10 | 11 | -- Solution 2: Join 12 | SELECT a1.player_id, a1.event_date, SUM(a2.games_played) AS games_played_so_far 13 | FROM activity a1 14 | JOIN activity a2 15 | -- the matched data from a2 include all records happened before or exactly on a1.event_date of the according record in a1 16 | ON a1.player_id = a2.player_id AND a1.event_date >= a2. event_date 17 | GROUP BY a1.player_id, a1.event_date; 18 | -------------------------------------------------------------------------------- /Questions_by_ID/550_Game_Play_Analysis_IV.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, Join 2 | SELECT CAST( 3 | -- using DISTINCT to avoid double counting 4 | COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id) 5 | AS DECIMAL(3,2) 6 | ) AS fraction 7 | FROM ( 8 | -- get the first-logged-in date of each player 9 | SELECT player_id, MIN(event_date) AS event_date 10 | FROM Activity 11 | GROUP BY player_id 12 | ) a1 13 | -- if a player logged back in on the day right after the first-logged-in date, 14 | -- he/she would get a matched record from table a2 15 | LEFT JOIN Activity a2 16 | ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date; 17 | 18 | 19 | 20 | -- Solution 2: Subquery, Window Function 21 | WITH tb2 as ( 22 | SELECT player_id 23 | FROM ( 24 | SELECT player_id, 25 | -- the first-logged-in date 26 | MIN(event_date) OVER (PARTITION BY player_id) AS event_date, 27 | -- the next-logged-in date after first-logged-in date 28 | LEAD(event_date) OVER (PARTITION BY player_id ORDER BY event_date) AS lead_date 29 | FROM activity 30 | ) tb1 31 | -- only keep users the next-logged-in date after first-logged-in date is the day after first-logged in date 32 | WHERE dateadd(day,1, event_date) = lead_date 33 | ) 34 | 35 | SELECT CAST( 36 | COUNT(DISTINCT player_id)*1.0/(SELECT COUNT(DISTINCT player_id) FROM activity) 37 | AS DECIMAL(3,2) 38 | ) AS fraction 39 | FROM tb2; 40 | -------------------------------------------------------------------------------- /Questions_by_ID/569_Median_Employee_Salary.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT *, 4 | ROW_NUMBER() OVER (PARTITION BY company ORDER BY salary) AS r, 5 | COUNT(*) OVER (PARTITION BY company) AS num 6 | FROM employee 7 | ) 8 | 9 | SELECT id, company, salary 10 | FROM tb1 11 | -- when num % 2 = 0, the r of the median is num/2 and num/2 + 1 12 | -- when num % 2 = 1, the r of the median is (num+1)/2, between num/2 and num/2 + 1 13 | WHERE r BETWEEN num*1.0/2 AND num*1.0/2 + 1; 14 | 15 | 16 | 17 | -- Solution 2: Join, Subquery 18 | WITH tb1 AS ( 19 | SELECT e1.id, e1.company, e1.salary, COUNT(*) AS r, 20 | (SELECT COUNT(*) FROM employee WHERE company = e1.company) AS num 21 | FROM employee e1 22 | JOIN employee e2 23 | ON e1.company = e2.company 24 | AND (e1.salary > e2.salary OR (e1.salary = e2.salary AND e1.id >= e2.id)) 25 | GROUP BY e1.id, e1.company, e1.salary 26 | ) 27 | 28 | SELECT id, company, salary 29 | FROM tb1 30 | -- when num % 2 = 0, the r of the median is num/2 and num/2 + 1 31 | -- when num % 2 = 1, the r of the median is (num+1)/2, between num/2 and num/2 + 1 32 | WHERE r BETWEEN num*1.0/2 AND num*1.0/2 + 1; 33 | 34 | 35 | -- Will solve it without using any built-in SQL functions later on. 36 | -------------------------------------------------------------------------------- /Questions_by_ID/570_Managers_with_at_Least_5_Direct_Reports.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT name 3 | FROM employee 4 | WHERE id in ( 5 | SELECT managerid 6 | FROM employee 7 | GROUP BY managerid 8 | HAVING COUNT(*) >=5 9 | ); 10 | 11 | 12 | 13 | -- Solution 2: Join 14 | SELECT e2.name 15 | FROM employee e1 16 | JOIN employee e2 17 | ON e1.managerid = e2.id 18 | GROUP BY e2.id, e2.name 19 | HAVING COUNT(e1.id) >= 5; 20 | -------------------------------------------------------------------------------- /Questions_by_ID/571_Find_Median_Given_Frequency_of_Numbers.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT *, 4 | -- There are cum_num numbers in TABLE numbers less than or equal to number in that record 5 | -- e.g. There are cum_num = 8 numbers in TABLE numbers less than or equal to 1 6 | -- so you will see [1,1,8,12] AS [Number, Frequency, cum_num, num] 7 | SUM(frequency) OVER (ORDER BY number) AS cum_num, 8 | SUM(frequency) OVER () AS num 9 | FROM numbers 10 | ) 11 | 12 | SELECT AVG(number*1.0) AS median 13 | FROM tb1 14 | WHERE num / 2.0 BETWEEN cum_num - frequency AND cum_num; 15 | -------------------------------------------------------------------------------- /Questions_by_ID/574_Winning_Candidate.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT Name 3 | FROM Candidate 4 | WHERE id = ( 5 | SELECT TOP 1 CandidateId 6 | FROM Vote 7 | GROUP BY CandidateId 8 | ORDER BY COUNT(*) DESC 9 | ); 10 | 11 | 12 | 13 | -- Solution 2: Join 14 | SELECT TOP 1 c.Name 15 | FROM Candidate c 16 | JOIN Vote v 17 | ON c.id = v.CandidateId 18 | GROUP BY c.id, c.Name 19 | ORDER BY COUNT(*) DESC; 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Questions_by_ID/577_Employee_Bonus.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT e.name, b.bonus 3 | FROM Employee e 4 | LEFT JOIN Bonus b 5 | ON e.empId = b.empId 6 | -- when employee has no bonus, his/her bonus will be null after left join 7 | WHERE b.bonus IS NULL 8 | OR b.bonus < 1000; 9 | -------------------------------------------------------------------------------- /Questions_by_ID/578_Get_Highest_Answer_Rate_Question.sql: -------------------------------------------------------------------------------- 1 | -- Note: answer rate = answer actions / total non-answer actions 2 | -- If LeetCode change answer for the test case, plz let me know 3 | 4 | -- Solution: Basics 5 | SELECT TOP 1 question_id AS survey_log 6 | FROM survey_log 7 | GROUP BY question_id 8 | ORDER BY COUNT(answer_id)*1.0/(COUNT(*)-COUNT(answer_id)) DESC; 9 | -------------------------------------------------------------------------------- /Questions_by_ID/579_Find_Cumulative_Salary_of_an_Employee.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT e.id, month, 3 | SUM(Salary) OVER ( 4 | PARTITION BY id 5 | ORDER BY month 6 | -- get the cumulative sum of an employee's salary over a period of 3 months 7 | ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS Salary 8 | FROM Employee e 9 | -- exclude the most recent month for each employee 10 | WHERE month != (SELECT MAX(Month) FROM Employee WHERE id = e.id) 11 | ORDER BY id, month DESC; 12 | 13 | 14 | 15 | -- Solution 2: Join, Subquery 16 | SELECT e1.id, e1.month, SUM(e2.salary) AS Salary 17 | FROM Employee e1 18 | JOIN Employee e2 19 | -- data from table e2 only contained salary over a period of 3 months until e1.month 20 | ON e1.id = e2.id AND e1.month >= e2.month AND e1.month <= e2.month + 2 21 | -- exclude the most recent month for each employee 22 | WHERE e1.month != (SELECT MAX(month) FROM Employee WHERE id = e1.id) 23 | GROUP BY e1.id, e1.month 24 | ORDER BY e1.id, e1.month DESC; 25 | -------------------------------------------------------------------------------- /Questions_by_ID/580_Count_Student_Number_in_Departments.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join 2 | SELECT d.dept_name, COUNT(student_id) AS student_number 3 | FROM department d 4 | LEFT JOIN student s 5 | ON d.dept_id = s.dept_id 6 | GROUP BY d.dept_id, d.dept_name 7 | ORDER BY student_number DESC, d.dept_name; 8 | 9 | 10 | 11 | -- Solution 2: Subquery 12 | SELECT DISTINCT d.dept_name, 13 | (SELECT COUNT(*) FROM student where dept_id = d.dept_id) AS student_number 14 | FROM department d 15 | ORDER BY student_number DESC, d.dept_name; 16 | -------------------------------------------------------------------------------- /Questions_by_ID/584_Find_Customer_Referee.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Basics 2 | SELECT name 3 | FROM customer 4 | WHERE ISNULL(referee_id,0) != 2; 5 | 6 | 7 | 8 | -- Solution 2: Basics 9 | SELECT name 10 | FROM customer 11 | WHERE COALESCE(referee_id,0) != 2; 12 | 13 | 14 | 15 | -- Solution 3: Basics 16 | SELECT name 17 | FROM customer 18 | WHERE referee_id != 2 OR referee_id IS NULL; 19 | -------------------------------------------------------------------------------- /Questions_by_ID/585_Investments_in_2016.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT CAST(SUM(TIV_2016) AS DECIMAL(10,2)) AS TIV_2016 3 | FROM ( 4 | SELECT TIV_2016, 5 | COUNT(*) OVER (PARTITION BY TIV_2015) AS count_2015, 6 | COUNT(*) OVER (PARTITION BY LAT, LON) AS count_loc 7 | FROM insurance 8 | ) tb1 9 | WHERE count_2015 > 1 AND count_loc = 1; 10 | 11 | 12 | 13 | -- Solution 2: Subquery 14 | SELECT CAST(SUM(TIV_2016) AS DECIMAL(10,2)) AS TIV_2016 15 | FROM insurance 16 | WHERE TIV_2015 IN ( 17 | SELECT TIV_2015 18 | FROM insurance 19 | GROUP BY TIV_2015 20 | HAVING COUNT(*) > 1 21 | ) 22 | AND CONCAT(LAT,'_',LON) IN ( 23 | SELECT CONCAT(LAT,'_',LON) 24 | FROM insurance 25 | GROUP BY LAT, LON 26 | HAVING COUNT(*) = 1 27 | ); 28 | -------------------------------------------------------------------------------- /Questions_by_ID/586_Customer_Placing_the_Largest_Number_of_Orders.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT TOP 1 customer_number 3 | FROM orders 4 | GROUP BY customer_number 5 | ORDER BY COUNT(*) DESC; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/595_Big_Countries.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT name, population, area 3 | FROM World 4 | WHERE area > 3000000 OR population > 25000000; 5 | -------------------------------------------------------------------------------- /Questions_by_ID/596_Classes_More_Than_5_Students.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT class 3 | FROM courses 4 | GROUP BY class 5 | HAVING COUNT(DISTINCT student) >= 5; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/597_Friend_Requests_I_Overall_Acceptance_Rate.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN 2 | SELECT 3 | CAST( 4 | CASE 5 | WHEN COUNT(DISTINCT CONCAT(sender_id,'_',send_to_id)) = 0 THEN 0 6 | ELSE 7 | COUNT(DISTINCT CONCAT(requester_id,'_',accepter_id))*1.0 8 | / 9 | COUNT(DISTINCT CONCAT(sender_id,'_',send_to_id)) 10 | END 11 | AS DECIMAL(3,2) 12 | ) AS accept_rate 13 | FROM request_accepted, friend_request; 14 | 15 | 16 | 17 | -- Solution 2: CASE WHEN, Subquery 18 | WITH send AS ( 19 | SELECT distinct sender_id, send_to_id 20 | FROM friend_request 21 | ), 22 | accept AS ( 23 | SELECT distinct requester_id, accepter_id 24 | FROM request_accepted 25 | ) 26 | 27 | SELECT 28 | CASE 29 | WHEN (SELECT COUNT(*) FROM send)=0 THEN 0.0 30 | ELSE 31 | CAST( 32 | (SELECT COUNT(*) FROM accept)*1.0/(SELECT COUNT(*) FROM send) 33 | AS DECIMAL(3,2) 34 | ) 35 | END AS accept_rate; 36 | 37 | 38 | 39 | -- Solution 3: Variable, Subquery, IIF 40 | DECLARE @accept DECIMAL(10,2); 41 | DECLARE @send DECIMAL(10,2); 42 | 43 | SELECT @accept = COUNT(*) 44 | FROM ( 45 | SELECT DISTINCT requester_id, accepter_id 46 | FROM request_accepted 47 | ) AS tb1; 48 | 49 | SELECT @send = IIF(COUNT(*) < 1, 1, COUNT(*)) 50 | FROM ( 51 | SELECT DISTINCT sender_id, send_to_id 52 | FROM friend_request 53 | ) AS tb2; 54 | 55 | Select CAST(@accept / @send AS DECIMAL(3,2)) AS accept_rate; 56 | 57 | -------------------------------------------------------------------------------- /Questions_by_ID/601_Human_Traffic_of_Stadium.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS r 4 | FROM stadium 5 | WHERE people >=100 6 | ), 7 | tb2 AS ( 8 | SELECT id, visit_date, people, COUNT(*) OVER (PARTITION BY id-r) AS num 9 | FROM tb1 10 | ) 11 | 12 | SELECT id, visit_date, people 13 | FROM tb2 14 | WHERE num >= 3; 15 | 16 | 17 | 18 | -- Solution 2: Join, Subquery 19 | WITH tb1 AS ( 20 | SELECT s1.id AS id1, s2.id AS id2, s3.id AS id3 21 | FROM stadium s1, stadium s2, stadium s3 22 | WHERE s1.id + 1 = s2.id AND s2.id + 1 = s3.id 23 | AND s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100 24 | ) 25 | 26 | 27 | SELECT * 28 | FROM stadium 29 | WHERE id IN (SELECT id1 id FROM tb1 30 | UNION 31 | SELECT id2 FROM tb1 32 | UNION 33 | SELECT id3 FROM tb1); 34 | -------------------------------------------------------------------------------- /Questions_by_ID/602_Friend_Requests_II_Who_Has_the_Most_Friends.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | WITH tb1 AS ( 3 | SELECT requester_id AS id 4 | FROM request_accepted 5 | UNION ALL 6 | SELECT accepter_id 7 | FROM request_accepted 8 | ) 9 | 10 | SELECT TOP 1 id, COUNT(*) AS num 11 | FROM tb1 12 | GROUP BY id 13 | ORDER BY COUNT(*) DESC; 14 | 15 | 16 | 17 | -- Solution 2: PIVOT/UNPIVOT 18 | SELECT TOP 1 upvt.id, COUNT(*) AS num 19 | FROM request_accepted 20 | UNPIVOT ( 21 | id FOR ids IN (requester_id, accepter_id) 22 | ) upvt 23 | GROUP BY upvt.id 24 | ORDER BY COUNT(*) DESC; 25 | -------------------------------------------------------------------------------- /Questions_by_ID/603_Consecutive_Available_Seats.sql: -------------------------------------------------------------------------------- 1 | -- Soltuion 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT seat_id, row_number() OVER (ORDER BY seat_id) AS r 4 | FROM cinema 5 | WHERE free = 1 6 | ), 7 | tb2 AS ( 8 | SELECT seat_id, COUNT(*) OVER (PARTITION BY (seat_id - r)) AS num 9 | FROM tb1 10 | ) 11 | 12 | SELECT seat_id 13 | FROM tb2 14 | WHERE num >= 2; 15 | 16 | 17 | 18 | -- Soltuion 2: Window Function, Subquery 19 | WITH tb1 AS ( 20 | SELECT seat_id, free AS free1, 21 | LEAD(free) OVER (ORDER BY seat_id) AS free2, 22 | LAG(free) OVER (ORDER BY seat_id) AS free0 23 | FROM cinema 24 | ) 25 | 26 | SELECT seat_id 27 | FROM tb1 28 | WHERE free1 = 1 AND (free2 = 1 OR free0 = 1); 29 | 30 | 31 | 32 | -- Soltuion 3: Join 33 | SELECT c2.seat_id 34 | FROM cinema c1 35 | RIGHT JOIN cinema c2 36 | ON c1.seat_id + 1 = c2.seat_id 37 | LEFT JOIN cinema c3 38 | ON c2.seat_id + 1 = c3.seat_id 39 | WHERE c2.free = 1 AND (c1.free = 1 OR c3.free = 1); 40 | -------------------------------------------------------------------------------- /Questions_by_ID/607_Sales_Person.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join, Subquery 2 | SELECT name 3 | FROM salesperson 4 | WHERE sales_id NOT IN ( 5 | SELECT o.sales_id 6 | FROM orders o 7 | JOIN company c 8 | ON o.com_id = c.com_id 9 | WHERE c.name = 'RED' 10 | ); 11 | -------------------------------------------------------------------------------- /Questions_by_ID/608_Tree_Node.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN, Subquery 2 | SELECT id, 3 | CASE 4 | WHEN p_id IS NULL THEN 'Root' 5 | WHEN id IN (SELECT p_id FROM tree) THEN 'Inner' 6 | ELSE 'Leaf' 7 | END AS Type 8 | FROM tree 9 | ORDER BY id; 10 | -------------------------------------------------------------------------------- /Questions_by_ID/610_Triangle_Judgement.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN 2 | SELECT *, 3 | CASE 4 | -- the sum of any 2 sides of a triangle must be greater than the measure of the third side 5 | WHEN x+y > z AND y+z > x AND z+x > y THEN 'Yes' 6 | ELSE 'No' 7 | END AS triangle 8 | FROM triangle; 9 | -------------------------------------------------------------------------------- /Questions_by_ID/612_Shortest_Distance_in_a_Plane.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Join 2 | SELECT CAST( 3 | MIN( 4 | SQRT( 5 | POWER(p1.x-p2.x,2)+POWER(p1.y-p2.y,2) 6 | ) 7 | ) 8 | AS DECIMAL(10,2) 9 | ) AS shortest 10 | FROM point_2d p1 11 | JOIN point_2d p2 12 | ON p1.x != p2.x OR p1.y != p2.y; 13 | -------------------------------------------------------------------------------- /Questions_by_ID/613_Shortest_Distance_in_a_Line.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT MIN(next-x) AS shortest 3 | FROM ( 4 | SELECT x, LEAD(x) OVER (ORDER BY x) AS next 5 | FROM point 6 | ) tb1; 7 | 8 | 9 | 10 | -- Solution 2: Join 11 | SELECT MIN(ABS(p1.x-p2.x)) AS shortest 12 | FROM point p1 13 | JOIN point p2 14 | ON p1.x != p2.x; 15 | -------------------------------------------------------------------------------- /Questions_by_ID/614_Second_Degree_Follower.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT followee AS follower, COUNT(DISTINCT follower) AS num 3 | FROM follow 4 | GROUP BY followee 5 | HAVING followee IN (SELECT follower FROM follow) 6 | ORDER BY followee; 7 | 8 | 9 | 10 | -- Solution 2: Join 11 | SELECT f1.follower, COUNT(DISTINCT f2.follower) AS num 12 | FROM follow f1 13 | JOIN follow f2 14 | ON f1.follower = f2.followee 15 | GROUP BY f1.follower 16 | ORDER BY f1.follower; 17 | -------------------------------------------------------------------------------- /Questions_by_ID/615_Average_Salary_Departments_VS_Company.sql: -------------------------------------------------------------------------------- 1 | -- If need to extract date in other format in the future, FORMAT() function could be used 2 | 3 | -- Solution 1: Join, Window Function, Subquery, CASE WHEN 4 | WITH tb1 AS ( 5 | SELECT DISTINCT department_id, LEFT(pay_date,7) AS pay_month, 6 | AVG(amount) OVER (PARTITION BY department_id, LEFT(pay_date,7))AS avg_dept, 7 | AVG(amount) OVER (PARTITION BY LEFT(pay_date,7)) AS avg_comp 8 | FROM salary s 9 | JOIN employee e 10 | ON s.employee_id = e.employee_id 11 | ) 12 | 13 | SELECT pay_month, department_id, 14 | CASE 15 | WHEN avg_dept > avg_comp THEN 'higher' 16 | WHEN avg_dept < avg_comp THEN 'lower' 17 | ELSE 'same' 18 | END AS comparison 19 | FROM tb1; 20 | 21 | 22 | 23 | -- Solution 2: Join, Subquery, CASE WHEN 24 | WITH dept AS ( 25 | SELECT e.department_id, LEFT(s.pay_date,7) AS pay_month, AVG(s.amount) AS avg_dept 26 | FROM salary s 27 | JOIN employee e 28 | ON s.employee_id = e.employee_id 29 | GROUP BY e.department_id, LEFT(s.pay_date,7) 30 | ), 31 | comp AS ( 32 | SELECT LEFT(pay_date,7) AS pay_month, AVG(amount) AS avg_comp 33 | FROM salary 34 | GROUP BY LEFT(pay_date,7) 35 | ) 36 | 37 | SELECT d.department_id, d.pay_month, 38 | CASE 39 | WHEN d.avg_dept > c.avg_comp THEN 'higher' 40 | WHEN d.avg_dept < c.avg_comp THEN 'lower' 41 | ELSE 'same' 42 | END AS comparison 43 | FROM dept d 44 | JOIN comp c 45 | ON d.pay_month = c.pay_month; 46 | -------------------------------------------------------------------------------- /Questions_by_ID/618_Students_Report_By_Geography.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, PIVOT/UNPIVOT 2 | WITH tb1 AS ( 3 | -- Numbering student from each continent separately by their name alphabetically 4 | SELECT *, ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r 5 | FROM student 6 | ) 7 | 8 | -- each row will be a group of student name of whom from different continent and have same numbering 9 | SELECT [America],[Asia],[Europe] 10 | FROM tb1 11 | PIVOT ( 12 | MIN(name) FOR continent IN ([America],[Asia],[Europe]) 13 | ) pvt; 14 | 15 | 16 | 17 | -- Solution 2: Window Function, Subquery, IFF 18 | WITH tb1 AS ( 19 | -- Numbering student from each continent separately by their name alphabetically 20 | SELECT ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r, 21 | IIF(continent = 'America', name, NULL) AS America, 22 | IIF(continent = 'Asia', name, NULL) AS Asia, 23 | IIF(continent = 'Europe', name, NULL) AS Europe 24 | FROM student 25 | ) 26 | 27 | -- Since numbering is unique in each continent, 28 | -- in each numbering group (1-3 rows), there ia only one cell contained student name in each column (e.g. America, Asia, Europe) 29 | SELECT MIN(America) AS America, MIN(Asia) AS Asia, MIN(Europe) AS Europe 30 | FROM tb1 31 | GROUP BY r; 32 | -------------------------------------------------------------------------------- /Questions_by_ID/619_Biggest_Single_Number.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT MAX(num) AS num 3 | FROM ( 4 | -- Select numbers appear only once 5 | SELECT num 6 | FROM my_numbers 7 | GROUP BY num 8 | HAVING COUNT(*) = 1 9 | ) tb1; 10 | -------------------------------------------------------------------------------- /Questions_by_ID/620_Not_Boring_Movies.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Basics 2 | SELECT * 3 | FROM cinema 4 | WHERE id % 2 = 1 AND description != 'boring' 5 | ORDER BY rating DESC; 6 | -------------------------------------------------------------------------------- /Questions_by_ID/626_Exchange_Seats.sql: -------------------------------------------------------------------------------- 1 | -- Solution: CASE WHEN, Subquery 2 | SELECT 3 | CASE 4 | WHEN id % 2 = 1 AND id = (SELECT MAX(id) FROM seat) THEN id 5 | WHEN id % 2 = 1 THEN id + 1 6 | ELSE id - 1 7 | END AS id, 8 | student 9 | FROM seat 10 | ORDER BY 1; 11 | -------------------------------------------------------------------------------- /Questions_by_ID/627_Swap_Salary.sql: -------------------------------------------------------------------------------- 1 | -- Solution: SQL Command, CASE WHEN 2 | UPDATE salary 3 | SET sex = CASE WHEN sex = 'm' THEN 'f' ELSE 'm' END; 4 | -------------------------------------------------------------------------------- /SQL-Command/196_Delete_Duplicate_Emails.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: SQL Command, Join 2 | DELETE p1 3 | FROM person p1 4 | JOIN person p2 5 | ON p1.email = p2.email AND p1.id > p2.id; 6 | 7 | 8 | 9 | -- Solution 2: SQL Command, Subquery 10 | DELETE FROM person 11 | WHERE id NOT IN ( 12 | SELECT * 13 | FROM ( 14 | SELECT MIN(id) AS id 15 | FROM person 16 | GROUP BY email 17 | ) tb1 18 | ); 19 | -------------------------------------------------------------------------------- /SQL-Command/627_Swap_Salary.sql: -------------------------------------------------------------------------------- 1 | UPDATE salary 2 | SET sex = CASE WHEN sex = 'm' THEN 'f' ELSE 'm' END; 3 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/1077_Project_Employees_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, Window Function, Subquery 2 | SELECT project_id, employee_id 3 | FROM ( 4 | SELECT p.project_id, p.employee_id, 5 | RANK() OVER (PARTITION BY project_id ORDER BY experience_years DESC) AS r 6 | FROM Project p 7 | JOIN Employee e 8 | ON p.employee_id = e.employee_id 9 | ) tb1 10 | WHERE r = 1; 11 | 12 | 13 | 14 | -- Solution 2: Join, Subquery 15 | WITH tb1 AS ( 16 | SELECT p.project_id, p.employee_id, e.experience_years 17 | FROM Project p 18 | JOIN Employee e 19 | ON p.employee_id = e.employee_id 20 | ), 21 | tb2 AS ( 22 | SELECT project_id, MAX(experience_years) AS max_years 23 | FROM tb1 24 | GROUP BY project_id 25 | ) 26 | 27 | SELECT project_id, employee_id 28 | FROM tb1 29 | WHERE experience_years = (SELECT max_years FROM tb2 WHERE project_id = tb1.project_id); 30 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/1127_User_Purchase_Platform.sql: -------------------------------------------------------------------------------- 1 | -- judge whether user used mobile only, desktop only or both mobile and desktop together for each date 2 | WITH tb1 AS ( 3 | SELECT user_id,spend_date,amount, 4 | CASE 5 | WHEN COUNT(*) OVER (PARTITION BY user_id, spend_date) = 1 THEN platform 6 | ELSE 'both' 7 | END AS platform 8 | FROM Spending 9 | ), 10 | -- calculate the total amount each user spent by date along with platform information 11 | tb2 AS ( 12 | SELECT spend_date, platform, 13 | SUM(amount) AS total_amount, 14 | COUNT(DISTINCT user_id) AS total_users 15 | FROM tb1 16 | GROUP BY spend_date, platform 17 | ), 18 | d AS ( 19 | SELECT DISTINCT spend_date 20 | FROM tb2 21 | ), 22 | p AS ( 23 | SELECT 'desktop' AS platform 24 | UNION 25 | SELECT 'mobile' 26 | UNION 27 | SELECT 'both' 28 | ) 29 | 30 | SELECT d.spend_date, p.platform, 31 | ISNULL(total_amount,0) AS total_amount, 32 | ISNULL(total_users,0) AS total_users 33 | FROM d 34 | CROSS JOIN p 35 | LEFT JOIN tb2 36 | ON d.spend_date = tb2.spend_date and p.platform = tb2.platform; 37 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/1159_Market_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, Join, CASE WHEN 2 | -- get item_id of the second item (by date) they sold for each user 3 | WITH tb1 AS ( 4 | SELECT seller_id, item_id 5 | FROM ( 6 | SELECT seller_id, item_id, 7 | ROW_NUMBER() OVER (PARTITION BY seller_id ORDER BY order_date) AS r 8 | FROM Orders 9 | ) rank 10 | WHERE r = 2 11 | ) 12 | 13 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 14 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 15 | SELECT u.user_id AS seller_id, 16 | CASE 17 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 18 | ELSE 'no' 19 | END AS '2nd_item_fav_brand' 20 | FROM Users u 21 | LEFT JOIN tb1 22 | ON u.user_id = tb1.seller_id 23 | LEFT JOIN Items i 24 | ON tb1.item_id = i.item_id; 25 | 26 | 27 | 28 | -- Solution 2: Join, Subquery, CASE WHEN 29 | -- get item_id of the second item (by date) they sold for each user (having only two sales records on or before o1.order_date) 30 | WITH tb1 AS ( 31 | SELECT o1.seller_id, o1.item_id 32 | FROM Orders o1 33 | JOIN orders o2 34 | ON o1.seller_id = o2.seller_id AND o1.order_date >= o2.order_date 35 | GROUP BY o1.seller_id, o1.order_date, o1.item_id 36 | HAVING COUNT(*) = 2 37 | ) 38 | 39 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 40 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 41 | SELECT u.user_id AS seller_id, 42 | CASE 43 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 44 | ELSE 'no' 45 | END AS '2nd_item_fav_brand' 46 | FROM Users u 47 | LEFT JOIN tb1 48 | ON u.user_id = tb1.seller_id 49 | LEFT JOIN Items i 50 | ON tb1.item_id = i.item_id; 51 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/1205_Monthly_Transactions_II.sql: -------------------------------------------------------------------------------- 1 | -- find the number of approved transactions and their total amount for each month and country 2 | WITH tb1 AS ( 3 | SELECT LEFT(trans_date,7) AS month, country, 4 | COUNT(state) AS approved_count, 5 | SUM(amount) AS approved_amount 6 | FROM Transactions 7 | WHERE state = 'approved' 8 | GROUP BY LEFT(trans_date,7), country 9 | ), 10 | -- find the number of chargebacks and their total amount for each month and country 11 | tb2 AS ( 12 | SELECT LEFT(c.trans_date,7) AS month, country, 13 | COUNT(c.trans_id) AS chargeback_count, 14 | SUM(t.amount) AS chargeback_amount 15 | FROM Chargebacks c 16 | JOIN Transactions t 17 | ON c.trans_id = t.id 18 | GROUP BY LEFT(c.trans_date,7), country 19 | ) 20 | 21 | -- when there is no approved transactions or chargebacks for a country in a certain month, 22 | -- replace the NULL with 0 23 | SELECT COALESCE(tb1.month,tb2.month) AS month, 24 | COALESCE(tb1.country,tb2.country) AS country, 25 | ISNULL(tb1.approved_count,0) AS approved_count, 26 | ISNULL(tb1.approved_amount,0) AS approved_amount, 27 | ISNULL(tb2.chargeback_count,0) AS chargeback_count, 28 | ISNULL(tb2.chargeback_amount,0) AS chargeback_amount 29 | FROM tb1 30 | FULL OUTER JOIN tb2 31 | ON tb1.month = tb2.month AND tb1.country = tb2.country; 32 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/1270_All_People_Report_to_the_Given_Manager.sql: -------------------------------------------------------------------------------- 1 | With tb1 AS ( 2 | SELECT employee_id 3 | FROM Employees 4 | WHERE manager_id = 1 AND employee_id != manager_id 5 | ), 6 | tb2 AS ( 7 | SELECT employee_id 8 | FROM Employees 9 | WHERE manager_id IN (SELECT * FROM tb1) 10 | ), 11 | tb3 AS ( 12 | SELECT employee_id 13 | FROM Employees 14 | WHERE manager_id IN (SELECT * FROM tb2) 15 | ) 16 | 17 | SELECT * 18 | FROM tb1 19 | UNION 20 | SELECT * 21 | FROM tb2 22 | UNION 23 | SELECT * 24 | FROM tb3; 25 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/1398_Customers_Who_Bought_Products_A_and_B_but_Not_C.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN, Subquery 2 | WITH tb1 AS ( 3 | SELECT DISTINCT customer_id, product_name, 4 | CASE 5 | WHEN product_name IN ('A','B') THEN 1 6 | WHEN product_name = 'C' THEN -1 7 | ELSE 0 8 | END AS c 9 | FROM Orders 10 | ) 11 | 12 | SELECT * 13 | FROM Customers 14 | WHERE customer_id IN ( 15 | SELECT customer_id 16 | FROM tb1 17 | GROUP BY customer_id 18 | HAVING SUM(c) = 2 19 | ); 20 | 21 | 22 | 23 | -- Solution 2: Subquery 24 | SELECT * 25 | FROM Customers 26 | WHERE customer_id IN ( 27 | SELECT customer_id 28 | FROM Orders 29 | WHERE product_name = 'A' 30 | ) 31 | AND customer_id IN ( 32 | SELECT customer_id 33 | FROM Orders 34 | WHERE product_name = 'B' 35 | ) 36 | AND customer_id NOT IN ( 37 | SELECT customer_id 38 | FROM Orders 39 | WHERE product_name = 'C' 40 | ); 41 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/262_Trips_and_Users.sql: -------------------------------------------------------------------------------- 1 | WITH t1 AS ( 2 | SELECT request_at, 3 | CASE 4 | WHEN status = 'completed' then 0 5 | ELSE 1.0 6 | END AS status 7 | FROM trips t 8 | -- filter our banned client and driver and limit time frame 9 | WHERE client_id NOT IN (SELECT users_id FROM users WHERE banned = 'Yes') 10 | AND driver_id NOT IN (SELECT users_id FROM users WHERE banned = 'Yes') 11 | AND request_at BETWEEN '2013-10-01' AND '2013-10-03' 12 | ) 13 | 14 | SELECT request_at AS 'Day', 15 | CAST(AVG(status) AS DECIMAL(4,2)) AS 'Cancellation Rate' 16 | FROM t1 17 | GROUP BY request_at; 18 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/550_Game_Play_Analysis_IV.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, Join 2 | SELECT CAST( 3 | -- using DISTINCT to avoid double counting 4 | COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id) 5 | AS DECIMAL(3,2) 6 | ) AS fraction 7 | FROM ( 8 | -- get the first-logged-in date of each player 9 | SELECT player_id, MIN(event_date) AS event_date 10 | FROM Activity 11 | GROUP BY player_id 12 | ) a1 13 | -- if a player logged back in on the day right after the first-logged-in date, 14 | -- he/she would get a matched record from table a2 15 | LEFT JOIN Activity a2 16 | ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date; 17 | 18 | 19 | 20 | -- Solution 2: Subquery, Window Function 21 | WITH tb2 as ( 22 | SELECT player_id 23 | FROM ( 24 | SELECT player_id, 25 | -- the first-logged-in date 26 | MIN(event_date) OVER (PARTITION BY player_id) AS event_date, 27 | -- the next-logged-in date after first-logged-in date 28 | LEAD(event_date) OVER (PARTITION BY player_id ORDER BY event_date) AS lead_date 29 | FROM activity 30 | ) tb1 31 | -- only keep users the next-logged-in date after first-logged-in date is the day after first-logged in date 32 | WHERE dateadd(day,1, event_date) = lead_date 33 | ) 34 | 35 | SELECT CAST( 36 | COUNT(DISTINCT player_id)*1.0/(SELECT COUNT(DISTINCT player_id) FROM activity) 37 | AS DECIMAL(3,2) 38 | ) AS fraction 39 | FROM tb2; 40 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/569_Median_Employee_Salary.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT e1.id, e1.company, e1.salary, COUNT(*) AS r, 3 | (SELECT COUNT(*) FROM employee WHERE company = e1.company) AS num 4 | FROM employee e1 5 | JOIN employee e2 6 | ON e1.company = e2.company 7 | AND (e1.salary > e2.salary OR (e1.salary = e2.salary AND e1.id >= e2.id)) 8 | GROUP BY e1.id, e1.company, e1.salary 9 | ) 10 | 11 | SELECT id, company, salary 12 | FROM tb1 13 | -- when num % 2 = 0, the r of the median is num/2 and num/2 + 1 14 | -- when num % 2 = 1, the r of the median is (num+1)/2, between num/2 and num/2 + 1 15 | WHERE r BETWEEN num*1.0/2 AND num*1.0/2 + 1; 16 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/585_Investments_in_2016.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT CAST(SUM(TIV_2016) AS DECIMAL(10,2)) AS TIV_2016 3 | FROM ( 4 | SELECT TIV_2016, 5 | COUNT(*) OVER (PARTITION BY TIV_2015) AS count_2015, 6 | COUNT(*) OVER (PARTITION BY LAT, LON) AS count_loc 7 | FROM insurance 8 | ) tb1 9 | WHERE count_2015 > 1 AND count_loc = 1; 10 | 11 | 12 | 13 | -- Solution 2: Subquery 14 | SELECT CAST(SUM(TIV_2016) AS DECIMAL(10,2)) AS TIV_2016 15 | FROM insurance 16 | WHERE TIV_2015 IN ( 17 | SELECT TIV_2015 18 | FROM insurance 19 | GROUP BY TIV_2015 20 | HAVING COUNT(*) > 1 21 | ) 22 | AND CONCAT(LAT,'_',LON) IN ( 23 | SELECT CONCAT(LAT,'_',LON) 24 | FROM insurance 25 | GROUP BY LAT, LON 26 | HAVING COUNT(*) = 1 27 | ); 28 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/597_Friend_Requests_I_Overall_Acceptance_Rate.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: CASE WHEN, Subquery 2 | WITH send AS ( 3 | SELECT distinct sender_id, send_to_id 4 | FROM friend_request 5 | ), 6 | accept AS ( 7 | SELECT distinct requester_id, accepter_id 8 | FROM request_accepted 9 | ) 10 | 11 | SELECT 12 | CASE 13 | WHEN (SELECT COUNT(*) FROM send)=0 THEN 0.0 14 | ELSE 15 | CAST( 16 | (SELECT COUNT(*) FROM accept)*1.0/(SELECT COUNT(*) FROM send) 17 | AS DECIMAL(3,2) 18 | ) 19 | END AS accept_rate; 20 | 21 | 22 | 23 | -- Solution 2: Variable, Subquery, IIF 24 | DECLARE @accept DECIMAL(10,2); 25 | DECLARE @send DECIMAL(10,2); 26 | 27 | SELECT @accept = COUNT(*) 28 | FROM ( 29 | SELECT DISTINCT requester_id, accepter_id 30 | FROM request_accepted 31 | ) AS tb1; 32 | 33 | SELECT @send = IIF(COUNT(*) < 1, 1, COUNT(*)) 34 | FROM ( 35 | SELECT DISTINCT sender_id, send_to_id 36 | FROM friend_request 37 | ) AS tb2; 38 | 39 | Select CAST(@accept / @send AS DECIMAL(3,2)) AS accept_rate; 40 | -------------------------------------------------------------------------------- /Subquery/Advanced-Subquery/601_Human_Traffic_of_Stadium.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS r 4 | FROM stadium 5 | WHERE people >=100 6 | ), 7 | tb2 AS ( 8 | SELECT id, visit_date, people, COUNT(*) OVER (PARTITION BY id-r) AS num 9 | FROM tb1 10 | ) 11 | 12 | SELECT id, visit_date, people 13 | FROM tb2 14 | WHERE num >= 3; 15 | 16 | 17 | 18 | -- Solution 2: Join, Subquery 19 | WITH tb1 AS ( 20 | SELECT s1.id AS id1, s2.id AS id2, s3.id AS id3 21 | FROM stadium s1, stadium s2, stadium s3 22 | WHERE s1.id + 1 = s2.id AND s2.id + 1 = s3.id 23 | AND s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100 24 | ) 25 | 26 | 27 | SELECT * 28 | FROM stadium 29 | WHERE id IN (SELECT id1 id FROM tb1 30 | UNION 31 | SELECT id2 FROM tb1 32 | UNION 33 | SELECT id3 FROM tb1); 34 | -------------------------------------------------------------------------------- /Subquery/Recursive-CTE/1270_All_People_Report_to_the_Given_Manager.sql: -------------------------------------------------------------------------------- 1 | -- find employees directly report to managers directly, 2 | -- and then find people who report to managers indirectly using cte 3 | WITH cte AS ( 4 | SELECT employee_id 5 | FROM Employees 6 | WHERE manager_id = 1 AND employee_id != manager_id 7 | UNION ALL 8 | SELECT e.employee_id 9 | FROM Employees e 10 | JOIN cte 11 | ON e.manager_id = cte.employee_id 12 | ) 13 | 14 | SELECT employee_id 15 | FROM cte 16 | OPTION (MAXRECURSION 3); 17 | -------------------------------------------------------------------------------- /Subquery/Recursive-CTE/1336_Number_of_Transactions_per_Visit.sql: -------------------------------------------------------------------------------- 1 | -- find number of transactions done for each visit 2 | WITH tb1 AS ( 3 | SELECT v.user_id, v.visit_date, COUNT(t.transaction_date) AS c 4 | FROM Visits v 5 | LEFT JOIN Transactions t 6 | ON v.visit_date = t.transaction_date AND v.user_id = t.user_id 7 | GROUP BY v.user_id, v.visit_date 8 | ), 9 | -- get all values from 0 to max(transactions_count) done by one or more users 10 | cte AS ( 11 | SELECT MAX(c) AS c 12 | FROM tb1 13 | UNION ALL 14 | SELECT c-1 15 | FROM cte 16 | WHERE c > 0 17 | ) 18 | 19 | -- count the corresponding number of users who did a certain transactions_count in one visit to the bank. 20 | SELECT cte.c AS transactions_count, 21 | COUNT(tb1.user_id) AS visits_count 22 | FROM cte 23 | LEFT JOIN tb1 24 | ON cte.c = tb1.c 25 | GROUP BY cte.c 26 | ORDER BY transactions_count; 27 | -------------------------------------------------------------------------------- /Subquery/Recursive-CTE/1384_Total_Sales_Amount_by_Year.sql: -------------------------------------------------------------------------------- 1 | -- get all dates from MIN(period_start) to MAX(period_end) 2 | WITH cte AS ( 3 | SELECT MIN(period_start) AS date, MAX(period_end) AS end_date 4 | FROM Sales 5 | UNION ALL 6 | SELECT DATEADD(day,1,date), end_date 7 | FROM cte 8 | WHERE date < end_date 9 | ) 10 | 11 | -- after join, products will have same number of records as the number of days in sale period 12 | SELECT s.product_id AS PRODUCT_ID, 13 | p.product_name AS PRODUCT_NAME, 14 | CAST(Year(cte.date) AS CHAR(4)) AS REPORT_YEAR, 15 | SUM(average_daily_sales) AS TOTAL_AMOUNT 16 | FROM cte 17 | JOIN Sales s 18 | ON cte.date BETWEEN s.period_start AND s.period_end 19 | JOIN Product p 20 | ON s.product_id = p.product_id 21 | GROUP BY s.product_id, p.product_name, Year(cte.date) 22 | ORDER BY PRODUCT_ID, REPORT_YEAR 23 | OPTION (MAXRECURSION 0); 24 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1045_Customers_Who_Bought_All_Products.sql: -------------------------------------------------------------------------------- 1 | SELECT customer_id 2 | FROM customer 3 | GROUP BY customer_id 4 | -- the number of different products bought by customer equals to number of existing products 5 | HAVING COUNT(DISTINCT product_key) = (SELECT COUNT(*) FROM product); 6 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1070_Product_Sales_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT product_id, year AS first_year, quantity, price 3 | FROM ( 4 | SELECT *, DENSE_RANK() OVER (PARTITION BY product_id ORDER BY year) AS r 5 | FROM Sales 6 | ) tb1 7 | WHERE r = 1; 8 | 9 | 10 | 11 | -- Solution 2: Subquery 12 | SELECT product_id, year AS first_year, quantity, price 13 | FROM Sales s 14 | WHERE year = ( 15 | SELECT TOP 1 year 16 | FROM Sales 17 | WHERE product_id = s.product_id 18 | ORDER BY year 19 | ); 20 | 21 | 22 | 23 | -- Solution 3: Subquery, Join 24 | WITH tb1 AS ( 25 | SELECT product_id, MIN(year) AS first_year 26 | FROM Sales 27 | GROUP BY product_id 28 | ) 29 | 30 | SELECT s.product_id, first_year, quantity, price 31 | FROM Sales s 32 | JOIN tb1 33 | ON s.product_id = tb1.product_id AND s.year = tb1.first_year; 34 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1083_Sales_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Join, Subquery 2 | WITH tb1 AS ( 3 | SELECT s.buyer_id, p.product_name 4 | FROM Sales s 5 | JOIN Product p 6 | ON s.product_id = p.product_id 7 | ) 8 | 9 | SELECT buyer_id 10 | FROM tb1 11 | WHERE product_name = 'S8' 12 | EXCEPT 13 | SELECT buyer_id 14 | FROM tb1 15 | WHERE product_name = 'iPhone'; 16 | 17 | 18 | 19 | -- Solution 2: Join, Subquery 20 | WITH tb1 AS ( 21 | SELECT s.buyer_id, p.product_name 22 | FROM Sales s 23 | JOIN Product p 24 | ON s.product_id = p.product_id 25 | ) 26 | 27 | SELECT DISTINCT buyer_id 28 | FROM tb1 29 | WHERE product_name = 'S8' AND buyer_id NOT IN ( 30 | SELECT buyer_id 31 | FROM tb1 32 | WHERE product_name = 'iPhone' 33 | ); 34 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1084_Sales_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | SELECT product_id, product_name 2 | FROM Product 3 | WHERE product_id IN ( 4 | SELECT product_id 5 | FROM Sales 6 | WHERE sale_date BETWEEN '2019-01-01' AND '2019-03-31' 7 | EXCEPT 8 | SELECT product_id 9 | FROM Sales 10 | WHERE NOT sale_date BETWEEN '2019-01-01' AND '2019-03-31' 11 | ); 12 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1097_Game_Play_Analysis_V.sql: -------------------------------------------------------------------------------- 1 | SELECT a1.event_date AS install_dt, 2 | COUNT(DISTINCT a1.player_id) AS installs, 3 | CAST( 4 | -- The number of players logged back in the day after / the number of players first logined on that date 5 | -- using DISTINCT to avoid double counting 6 | COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id) 7 | AS DECIMAL(3,2) 8 | ) AS Day1_retention 9 | FROM ( 10 | -- get install date of each player 11 | SELECT player_id, MIN(event_date) AS event_date 12 | FROM Activity 13 | GROUP BY player_id 14 | ) a1 15 | -- if a player logged back in on the day right after install date, he/she would get a matched record from table a2 16 | LEFT JOIN Activity a2 17 | ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date 18 | GROUP BY a1.event_date; 19 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1098_Unpopular_Books.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT book_id, name 3 | FROM Books 4 | WHERE available_from <= '2019-05-23' 5 | -- find books that have sold more than 10 copies in the last year 6 | AND book_id NOT IN ( 7 | SELECT book_id 8 | FROM Orders 9 | WHERE dispatch_date >= '2018-06-24' 10 | GROUP BY book_id 11 | HAVING SUM(quantity) >= 10 12 | ); 13 | 14 | 15 | 16 | -- Solution 2: Subquery, Variable 17 | 18 | -- Solution 2 is better in terms of automation. 19 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 20 | 21 | DECLARE @d date; 22 | SET @d = '2019-06-23'; 23 | 24 | SELECT book_id, name 25 | FROM Books 26 | WHERE available_from <= DATEADD(month, -1, @d) 27 | -- find books that have sold more than 10 copies in the last year 28 | AND book_id NOT IN ( 29 | SELECT book_id 30 | FROM Orders 31 | WHERE dispatch_date > DATEADD(year, -1, @d) 32 | GROUP BY book_id 33 | HAVING SUM(quantity) >= 10 34 | ); 35 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1107_New_Users_Daily_Count.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | -- Solution 1: Subquery, Variable 4 | DECLARE @d date; 5 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 6 | 7 | WITH tb1 AS ( 8 | SELECT user_id, MIN(activity_date) AS login_date 9 | FROM traffic 10 | WHERE activity = 'login' 11 | GROUP BY user_id) 12 | 13 | SELECT login_date, COUNT(*) AS user_count 14 | FROM tb1 15 | GROUP BY login_date 16 | HAVING login_date >= @d; 17 | 18 | 19 | 20 | -- Solution 2: Window Function, Subquery, Variable 21 | 22 | -- Using ROW_NUMBER() instead of RANK() or DENSE_RANK() 23 | -- to avoid return several rows when user login more than once at the first date 24 | 25 | DECLARE @d date; 26 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 27 | 28 | WITH tb1 AS ( 29 | SELECT *, 30 | ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY activity_date) AS r 31 | FROM Traffic 32 | WHERE activity = 'login' 33 | ) 34 | 35 | SELECT activity_date AS login_date, COUNT(*) AS user_count 36 | FROM tb1 37 | WHERE r = 1 38 | GROUP BY activity_date 39 | HAVING activity_date >= @d; 40 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1112_Highest_Grade_For_Each_Student.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT *, 4 | ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY grade DESC, course_id) AS r 5 | FROM Enrollments 6 | ) 7 | 8 | SELECT student_id, course_id, grade 9 | FROM tb1 10 | WHERE r = 1 11 | ORDER BY student_id; 12 | 13 | 14 | 15 | -- Solution 2: Subquery, Join 16 | WITH tb1 AS ( 17 | SELECT student_id, MAX(grade) AS grade 18 | FROM Enrollments 19 | GROUP BY student_id 20 | ) 21 | 22 | SELECT e.student_id, MIN(course_id) AS course_id, e.grade 23 | FROM Enrollments e 24 | JOIN tb1 25 | ON e.student_id = tb1.student_id AND e.grade = tb1.grade 26 | GROUP BY e.student_id, e.grade 27 | ORDER BY e.student_id; 28 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1126_Active_Businesses.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, CASE WHEN 2 | -- calculate average occurences of event types amont all business 3 | WITH tb1 AS ( 4 | SELECT *, 5 | AVG(occurences*1.0) OVER (PARTITION BY event_type) AS avg_oc 6 | FROM Events 7 | ) 8 | 9 | SELECT business_id 10 | FROM tb1 11 | GROUP BY business_id 12 | -- count number of event types of a business with occurences 13 | -- greater than the average occurences of that event type among all businesses 14 | HAVING SUM(CASE WHEN occurences > avg_oc THEN 1 ELSE 0 END) > 1; 15 | 16 | 17 | 18 | -- Solution 2: Subquery, Join 19 | -- calculate average occurences of event types amont all business 20 | WITH tb1 AS ( 21 | SELECT event_type, AVG(occurences*1.0) AS avg_oc 22 | FROM Events 23 | GROUP BY event_type 24 | ) 25 | 26 | SELECT business_id 27 | FROM Events e 28 | JOIN tb1 29 | -- use join to keep only records in which event type of a business with occurences 30 | -- greater than the average occurences of that event type among all businesses 31 | ON e.event_type = tb1.event_type AND e.occurences > tb1.avg_oc 32 | GROUP BY business_id 33 | HAVING COUNT(*) > 1; 34 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1132_Reported_Posts_II.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT COUNT(DISTINCT r.post_id)*100.0/COUNT(DISTINCT a.post_id) AS daily_p 3 | FROM Actions a 4 | LEFT JOIN Removals r 5 | ON a.post_id = r.post_id 6 | WHERE a.action = 'report' AND a.extra = 'spam' 7 | GROUP BY a.action_date 8 | ) 9 | 10 | SELECT CAST(AVG(daily_p) AS DECIMAL(5,2)) AS average_daily_percent 11 | FROM tb1; 12 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1142_User_Activity_for_the_Past_30_Days_II.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS( 2 | SELECT COUNT(DISTINCT session_id) AS num 3 | FROM activity 4 | WHERE activity_date BETWEEN DATEADD(day,-29,'2019-07-27') and '2019-07-27' 5 | GROUP BY user_id 6 | ) 7 | 8 | SELECT CAST( 9 | ISNULL(AVG(num*1.0),0) 10 | AS DECIMAL(10,2) 11 | ) AS average_sessions_per_user 12 | FROM tb1; 13 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1158_Market_Analysis_I.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT buyer_id, COUNT(*) AS num 3 | FROM orders 4 | WHERE YEAR(order_date) = 2019 5 | GROUP BY buyer_id 6 | ) 7 | 8 | SELECT u.user_id AS buyer_id, u.join_date, ISNULL(num, 0) AS orders_in_2019 9 | FROM users u 10 | LEFT JOIN tb1 o 11 | ON u.user_id = o.buyer_id; 12 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1174_Immediate_Food_Delivery_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, CASE WHEN 2 | WITH tb1 AS ( 3 | -- fod refers to first order date, and fdd refers to first delivery date 4 | SELECT MIN(order_date) AS fod, MIN(customer_pref_delivery_date) AS fdd 5 | FROM Delivery 6 | GROUP BY customer_id 7 | ) 8 | 9 | -- Since it is guaranteed that a customer has exactly one first order, 10 | -- when fod = fdd, the first order of that customer must be immediate order 11 | SELECT CAST( 12 | AVG( 13 | CASE 14 | WHEN fod = fdd THEN 100.0 15 | ELSE 0 16 | END 17 | ) 18 | AS DECIMAL(5,2) 19 | ) AS immediate_percentage 20 | FROM tb1; 21 | 22 | 23 | 24 | -- Solution 2: Window Function, Subquery, CASE WHEN 25 | WITH tb1 AS ( 26 | SELECT order_date, customer_pref_delivery_date, 27 | -- identify first order of each customer 28 | ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS r 29 | FROM delivery 30 | ) 31 | 32 | SELECT CAST( 33 | AVG( 34 | CASE 35 | WHEN order_date = customer_pref_delivery_date THEN 100.0 36 | ELSE 0 37 | END 38 | ) 39 | AS DECIMAL(5,2) 40 | ) AS immediate_percentage 41 | FROM tb1 42 | WHERE r = 1; 43 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1204_Last_Person_to_Fit_in_the_Elevator.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 person_name 2 | FROM ( 3 | SELECT person_name, turn, 4 | SUM(weight) OVER (ORDER BY turn) AS tw 5 | FROM Queue 6 | ) tb1 7 | WHERE tw <= 1000 8 | ORDER BY turn DESC; 9 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1225_Report_Contiguous_Dates.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, Window Function 2 | WITH tb1 AS ( 3 | SELECT fail_date AS date, 'failed' AS s 4 | FROM Failed 5 | UNION 6 | SELECT success_date AS date, 'succeeded' AS s 7 | FROM Succeeded 8 | ), 9 | tb2 AS ( 10 | SELECT *, 11 | ROW_NUMBER() OVER (PARTITION BY s ORDER BY date) AS r, 12 | ROW_NUMBER() OVER (ORDER BY date) AS r2 13 | FROM tb1 14 | WHERE Year(date) = 2019 15 | ) 16 | 17 | -- contiguous dates with same period state share the same r2-r, 18 | -- so in a group with same r2-4, the smallest date is start date and the largest date is end date 19 | SELECT s AS period_state, MIN(date) AS start_date, MAX(date) AS end_date 20 | FROM tb2 21 | GROUP BY r2-r, s 22 | ORDER BY start_date; 23 | 24 | 25 | 26 | -- Solution 2: Join, Subquery 27 | WITH tb1 AS ( 28 | -- numbering date with different states in chronological order separately 29 | SELECT f1.fail_date AS date, 'failed' AS s, COUNT(*) AS r 30 | FROM Failed f1 31 | JOIN Failed f2 32 | ON f1.fail_date >= f2.fail_date 33 | GROUP BY f1.fail_date 34 | UNION 35 | SELECT s1.success_date AS date, 'succeeded' AS s, COUNT(*) AS r 36 | FROM Succeeded s1 37 | JOIN Succeeded s2 38 | ON s1.success_date >= s2.success_date 39 | GROUP BY s1.success_date 40 | ), 41 | tb2 AS ( 42 | SELECT *, 43 | -- numbering date in chronological order 44 | DATEPART(dayofyear, date) AS r2 45 | FROM tb1 46 | WHERE Year(date) = 2019 47 | ) 48 | 49 | -- contiguous dates with same period state share the same r2-r, 50 | -- so in a group with same r2-4, the smallest date is start date and the largest date is end date 51 | SELECT s AS period_state, MIN(date) AS start_date, MAX(date) AS end_date 52 | FROM tb2 53 | GROUP BY r2-r, s 54 | ORDER BY start_date; 55 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1264_Page_Recommendations.sql: -------------------------------------------------------------------------------- 1 | WITH f AS ( 2 | SELECT CASE WHEN user1_id = 1 THEN user2_id ELSE user1_id END AS fid 3 | FROM Friendship 4 | WHERE user1_id = 1 OR user2_id =1 5 | ) 6 | 7 | SELECT DISTINCT page_id AS recommended_page 8 | FROM Likes 9 | WHERE user_id IN (SELECT * FROM f) 10 | EXCEPT 11 | SELECT page_id 12 | FROM Likes 13 | WHERE user_id = 1; 14 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1280_Students_and_Examinations.sql: -------------------------------------------------------------------------------- 1 | SELECT s.student_id, s.student_name, b.subject_name, 2 | ( 3 | SELECT COUNT(*) 4 | From Examinations 5 | WHERE student_id = s.student_id AND subject_name = b.subject_name 6 | ) AS attended_exams 7 | FROM Students s, Subjects b 8 | ORDER BY s.student_id, b.subject_name; 9 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | -- when the number is continous with the last one, both log_id and r add 1 3 | -- Therefore, continuous numbers share the same log_id - r 4 | -- when grouped by log_id - r, the start number is the samllest number in group and the end is the largest 5 | WITH tb1 AS ( 6 | SELECT log_id, ROW_NUMBER() OVER (ORDER BY log_id) AS r 7 | FROM Logs 8 | ) 9 | 10 | SELECT MIN(log_id) AS START_ID, MAX(log_id) AS END_ID 11 | FROM tb1 12 | GROUP BY log_id-r; 13 | 14 | 15 | 16 | -- Solution 2: Join, Subquery 17 | WITH tb1 AS ( 18 | SELECT l1.log_id, COUNT(*) AS r 19 | FROM Logs l1 20 | JOIN Logs l2 21 | ON l1.log_id >= l2.log_id 22 | GROUP BY l1.log_id 23 | ) 24 | 25 | SELECT MIN(log_id) AS START_ID, MAX(log_id) AS END_ID 26 | FROM tb1 27 | GROUP BY log_id-r; 28 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1294_Weather_Type_in_Each_Country.sql: -------------------------------------------------------------------------------- 1 | SELECT c.country_name, w.weather_type 2 | FROM ( 3 | SELECT country_id, 4 | CASE 5 | WHEN AVG(weather_state*1.0) <= 15 THEN 'Cold' 6 | WHEN AVG(weather_state*1.0) >= 25 THEN 'Hot' 7 | ELSE 'Warm' 8 | END AS weather_type 9 | FROM Weather 10 | WHERE LEFT(day,7) = '2019-11' 11 | GROUP BY country_id 12 | ) w 13 | JOIN Countries c 14 | ON w.country_id = c.country_id; 15 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1321_Restaurant_Growth.sql: -------------------------------------------------------------------------------- 1 | WITH total AS ( 2 | SELECT visited_on, SUM(amount) AS amount 3 | FROM Customer 4 | GROUP BY visited_on 5 | ) 6 | 7 | SELECT t1.visited_on, 8 | SUM(t2.amount) AS amount, 9 | CAST(AVG(t2.amount*1.0) AS DECIMAL(10,2)) AS average_amount 10 | FROM total t1 11 | JOIN total t2 12 | ON t1.visited_on >= t2.visited_on AND t1.visited_on <= DATEADD(day,6,t2.visited_on) 13 | GROUP BY t1.visited_on 14 | HAVING COUNT(t2.visited_on) = 7 15 | ORDER BY t1.visited_on; 16 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1322_Ads_Performance.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT ad_id, [Clicked], [Viewed], [Ignored] 3 | FROM Ads 4 | PIVOT ( 5 | COUNT(action) FOR action IN ([Clicked], [Viewed], [Ignored]) 6 | ) pvt 7 | ) 8 | 9 | SELECT ad_id, 10 | CASE 11 | WHEN SUM(Clicked+Viewed) = 0 THEN 0.0 12 | ELSE CAST(SUM(Clicked)*100.0/SUM(Clicked+Viewed) AS DECIMAL(5,2)) 13 | END AS ctr 14 | FROM tb1 15 | GROUP BY ad_id 16 | ORDER BY ctr DESC, ad_id; 17 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1336_Number_of_Transactions_per_Visit.sql: -------------------------------------------------------------------------------- 1 | -- find number of transactions done for each visit 2 | WITH tb1 AS ( 3 | SELECT v.user_id, v.visit_date, COUNT(t.transaction_date) AS c 4 | FROM Visits v 5 | LEFT JOIN Transactions t 6 | ON v.visit_date = t.transaction_date AND v.user_id = t.user_id 7 | GROUP BY v.user_id, v.visit_date 8 | ), 9 | -- get all values from 0 to max(transactions_count) done by one or more users 10 | cte AS ( 11 | SELECT MAX(c) AS c 12 | FROM tb1 13 | UNION ALL 14 | SELECT c-1 15 | FROM cte 16 | WHERE c > 0 17 | ) 18 | 19 | -- count the corresponding number of users who did a certain transactions_count in one visit to the bank. 20 | SELECT cte.c AS transactions_count, 21 | COUNT(tb1.user_id) AS visits_count 22 | FROM cte 23 | LEFT JOIN tb1 24 | ON cte.c = tb1.c 25 | GROUP BY cte.c 26 | ORDER BY transactions_count; 27 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1341_Movie_Rating.sql: -------------------------------------------------------------------------------- 1 | SELECT MIN(name) AS results 2 | FROM Users 3 | WHERE user_id IN ( 4 | -- find users who rated greatest number of the movies 5 | SELECT TOP 1 WITH TIES user_id 6 | FROM Movie_Rating 7 | GROUP BY user_id 8 | ORDER BY COUNT(DISTINCT movie_id) DESC 9 | ) 10 | UNION ALL 11 | SELECT MIN(title) AS results 12 | FROM Movies 13 | WHERE movie_id IN ( 14 | -- find movies with highest average rating in Feb. 2020 15 | SELECT TOP 1 WITH TIES movie_id 16 | FROM Movie_Rating 17 | WHERE YEAR(created_at) = 2020 AND MONTH(created_at) = 2 18 | GROUP BY movie_id 19 | ORDER BY AVG(rating*1.0) DESC 20 | ); 21 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1350_Students_With_Invalid_Departments.sql: -------------------------------------------------------------------------------- 1 | SELECT id, name 2 | FROM Students 3 | WHERE department_id NOT IN (SELECT id FROM Departments); 4 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1355_Activity_Participants.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT activity 3 | FROM ( 4 | SELECT activity, 5 | -- Numbering activity by number of participants in ascending and descending order 6 | RANK() OVER (ORDER BY COUNT(*)) AS r1, 7 | RANK() OVER (ORDER BY COUNT(*) DESC) AS r2 8 | FROM Friends 9 | GROUP BY activity 10 | ) tb1 11 | -- fliter out activities with minimum or maximum number of participants 12 | WHERE r1 != 1 AND r2 != 1; 13 | 14 | 15 | 16 | -- Solution 2: Subquery 17 | WITH tb1 AS ( 18 | SELECT activity, COUNT(*) AS num 19 | FROM Friends 20 | GROUP BY activity 21 | ) 22 | 23 | SELECT activity 24 | FROM tb1 25 | WHERE num NOT IN ( 26 | SELECT MAX(num) FROM tb1 27 | UNION ALL 28 | SELECT MIN(num) FROM tb1 29 | ); 30 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1364_Number_of_Trusted_Contacts_of_a_Customer.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT c.customer_id, c.customer_name, 3 | COUNT(con.contact_name) AS contacts_cnt, 4 | COUNT(c2.customer_id) AS trusted_contacts_cnt 5 | FROM Customers c 6 | LEFT JOIN Contacts con 7 | ON c.customer_id = con.user_id 8 | LEFT JOIN Customers c2 9 | ON con.contact_email = c2.email 10 | GROUP BY c.customer_id, c.customer_name 11 | ) 12 | 13 | SELECT i.invoice_id, 14 | tb1.customer_name, 15 | i.price, 16 | tb1.contacts_cnt, 17 | tb1.trusted_contacts_cnt 18 | FROM Invoices i 19 | JOIN tb1 20 | ON i.user_id = tb1.customer_id 21 | ORDER BY i.invoice_id; 22 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/1369_Get_the_Second_Most_Recent_Activity.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT username, activity, startDate, endDate 3 | FROM ( 4 | SELECT *, 5 | ROW_NUMBER() OVER (PARTITION BY username ORDER BY endDate DESC) AS r, 6 | COUNT(*) OVER (PARTITION BY username) AS c 7 | FROM UserActivity 8 | ) tb1 9 | WHERE r = 2 OR c = 1; 10 | 11 | 12 | 13 | -- Solution 2: Join, Subquery 14 | WITH tb1 AS ( 15 | SELECT u1.username, u1.activity, u1.startDate, u1.endDate, COUNT(*) AS r 16 | FROM UserActivity u1 17 | JOIN UserActivity u2 18 | ON u1.username = u2.username AND u1.endDate <= u2.endDate 19 | GROUP BY u1.username, u1.activity, u1.startDate, u1.endDate 20 | ), 21 | tb2 AS ( 22 | SELECT username, COUNT(*) AS c 23 | FROM UserActivity 24 | GROUP BY username 25 | ) 26 | 27 | SELECT tb1.username, tb1.activity, tb1.startDate, tb1.endDate 28 | FROM tb1 29 | JOIN tb2 30 | ON tb1.username = tb2.username 31 | WHERE tb1.r = 2 OR tb2.c = 1; 32 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/176_Second_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | SELECT MAX(salary) AS secondhighestsalary 2 | FROM employee 3 | WHERE salary < (SELECT MAX(salary) FROM employee); 4 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/183_Customers_Who_Never_Order.sql: -------------------------------------------------------------------------------- 1 | SELECT name AS customers 2 | FROM customers 3 | WHERE id NOT IN (SELECT customerid FROM Orders); 4 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/184_Department_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | -- Solution: Subquery, Join 2 | WITH max_salary AS ( 3 | SELECT departmentid, max(salary) AS max_salary 4 | FROM employee 5 | GROUP BY departmentid 6 | ) 7 | 8 | SELECT d.name department, e.name employee, e.salary 9 | FROM max_salary ms 10 | JOIN employee e 11 | ON ms.departmentid = e.departmentid AND ms.max_salary = e.salary 12 | JOIN department d 13 | ON e.departmentid = d.id; 14 | 15 | 16 | 17 | -- Solution: Subquery, Window Function 18 | SELECT department, employee, salary 19 | FROM ( 20 | SELECT d.name department, e.name employee ,salary, 21 | -- ranking salaries in each department 22 | -- the employee with highest salary will get r = 1 23 | DENSE_RANK() OVER ( 24 | PARTITION BY departmentid 25 | ORDER BY salary DESC) r 26 | FROM employee e 27 | JOIN department d 28 | ON e.departmentid = d.id 29 | ) AS tb1 30 | WHERE r = 1; 31 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/196_Delete_Duplicate_Emails.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM person 2 | WHERE id NOT IN ( 3 | SELECT * 4 | FROM ( 5 | SELECT MIN(id) AS id 6 | FROM person 7 | GROUP BY email 8 | ) tb1 9 | ); 10 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/197_Rising_Temperature.sql: -------------------------------------------------------------------------------- 1 | SELECT id 2 | FROM ( 3 | SELECT *, 4 | -- Get temperature and date of previous record date, if none get null 5 | LAG(temperature) OVER (ORDER BY recorddate) AS prev_temp, 6 | LAG(recorddate) OVER (ORDER BY recorddate) prev_date 7 | FROM weather 8 | ) tb1 9 | WHERE DATEADD(day,1,prev_date) = recorddate AND prev_temp < temperature; 10 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/512_Game_Play_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery 2 | SELECT player_id, device_id 3 | FROM Activity 4 | WHERE concat(player_id,event_date) IN ( 5 | SELECT concat(player_id, MIN(event_date)) 6 | FROM Activity 7 | GROUP BY player_id 8 | ); 9 | 10 | 11 | 12 | -- Solution 2: Join, Subquery 13 | SELECT a.player_id, device_id 14 | FROM Activity a 15 | JOIN ( 16 | SELECT player_id, MIN(event_date) min_date 17 | FROM Activity 18 | GROUP BY player_id 19 | ) tb1 20 | ON a.player_id = tb1.player_id AND a.event_date = tb1.min_date; 21 | 22 | 23 | 24 | -- Solution 3: Window Function, Subquery 25 | SELECT player_id, device_id 26 | FROM ( 27 | SELECT player_id, device_id, 28 | DENSE_RANK() OVER (PARTITION BY player_id ORDER BY event_date) AS r 29 | FROM Activity) tb1 30 | WHERE r = 1; 31 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/569_Median_Employee_Salary.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT *, 3 | ROW_NUMBER() OVER (PARTITION BY company ORDER BY salary) AS r, 4 | COUNT(*) OVER (PARTITION BY company) AS num 5 | FROM employee 6 | ) 7 | 8 | SELECT id, company, salary 9 | FROM tb1 10 | -- when num % 2 = 0, the r of the median is num/2 and num/2 + 1 11 | -- when num % 2 = 1, the r of the median is (num+1)/2, between num/2 and num/2 + 1 12 | WHERE r BETWEEN num*1.0/2 AND num*1.0/2 + 1; 13 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/570_Managers_with_at_Least_5_Direct_Reports.sql: -------------------------------------------------------------------------------- 1 | SELECT name 2 | FROM employee 3 | WHERE id in ( 4 | SELECT managerid 5 | FROM employee 6 | GROUP BY managerid 7 | HAVING COUNT(*) >=5 8 | ); 9 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/571_Find_Median_Given_Frequency_of_Numbers.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT *, 3 | -- There are cum_num numbers in TABLE numbers less than or equal to number in that record 4 | -- e.g. There are cum_num = 8 numbers in TABLE numbers less than or equal to 1 5 | -- so you will see [1,1,8,12] AS [Number, Frequency, cum_num, num] 6 | SUM(frequency) OVER (ORDER BY number) AS cum_num, 7 | SUM(frequency) OVER () AS num 8 | FROM numbers 9 | ) 10 | 11 | SELECT AVG(number*1.0) AS median 12 | FROM tb1 13 | WHERE num / 2.0 BETWEEN cum_num - frequency AND cum_num; 14 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/574_Winning_Candidate.sql: -------------------------------------------------------------------------------- 1 | SELECT Name 2 | FROM Candidate 3 | WHERE id = ( 4 | SELECT TOP 1 CandidateId 5 | FROM Vote 6 | GROUP BY CandidateId 7 | ORDER BY COUNT(*) DESC 8 | ); 9 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/579_Find_Cumulative_Salary_of_an_Employee.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery 2 | SELECT e.id, month, 3 | SUM(Salary) OVER ( 4 | PARTITION BY id 5 | ORDER BY month 6 | -- get the cumulative sum of an employee's salary over a period of 3 months 7 | ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS Salary 8 | FROM Employee e 9 | -- exclude the most recent month for each employee 10 | WHERE month != (SELECT MAX(Month) FROM Employee WHERE id = e.id) 11 | ORDER BY id, month DESC; 12 | 13 | 14 | 15 | -- Solution 2: Join, Subquery 16 | SELECT e1.id, e1.month, SUM(e2.salary) AS Salary 17 | FROM Employee e1 18 | JOIN Employee e2 19 | -- data from table e2 only contained salary over a period of 3 months until e1.month 20 | ON e1.id = e2.id AND e1.month >= e2.month AND e1.month <= e2.month + 2 21 | -- exclude the most recent month for each employee 22 | WHERE e1.month != (SELECT MAX(month) FROM Employee WHERE id = e1.id) 23 | GROUP BY e1.id, e1.month 24 | ORDER BY e1.id, e1.month DESC; 25 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/580_Count_Student_Number_in_Departments.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT d.dept_name, 2 | (SELECT COUNT(*) FROM student where dept_id = d.dept_id) AS student_number 3 | FROM department d 4 | ORDER BY student_number DESC, d.dept_name; 5 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/602_Friend_Requests_II_Who_Has_the_Most_Friends.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT requester_id AS id 3 | FROM request_accepted 4 | UNION ALL 5 | SELECT accepter_id 6 | FROM request_accepted 7 | ) 8 | 9 | SELECT TOP 1 id, COUNT(*) AS num 10 | FROM tb1 11 | GROUP BY id 12 | ORDER BY COUNT(*) DESC; 13 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/603_Consecutive_Available_Seats.sql: -------------------------------------------------------------------------------- 1 | -- Soltuion 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT seat_id, row_number() OVER (ORDER BY seat_id) AS r 4 | FROM cinema 5 | WHERE free = 1 6 | ), 7 | tb2 AS ( 8 | SELECT seat_id, COUNT(*) OVER (PARTITION BY (seat_id - r)) AS num 9 | FROM tb1 10 | ) 11 | 12 | SELECT seat_id 13 | FROM tb2 14 | WHERE num >= 2; 15 | 16 | 17 | 18 | -- Soltuion 2: Window Function, Subquery 19 | WITH tb1 AS ( 20 | SELECT seat_id, free AS free1, 21 | LEAD(free) OVER (ORDER BY seat_id) AS free2, 22 | LAG(free) OVER (ORDER BY seat_id) AS free0 23 | FROM cinema 24 | ) 25 | 26 | SELECT seat_id 27 | FROM tb1 28 | WHERE free1 = 1 AND (free2 = 1 OR free0 = 1); 29 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/607_Sales_Person.sql: -------------------------------------------------------------------------------- 1 | SELECT name 2 | FROM salesperson 3 | WHERE sales_id NOT IN ( 4 | SELECT o.sales_id 5 | FROM orders o 6 | JOIN company c 7 | ON o.com_id = c.com_id 8 | WHERE c.name = 'RED' 9 | ); 10 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/608_Tree_Node.sql: -------------------------------------------------------------------------------- 1 | SELECT id, 2 | CASE 3 | WHEN p_id IS NULL THEN 'Root' 4 | WHEN id IN (SELECT p_id FROM tree) THEN 'Inner' 5 | ELSE 'Leaf' 6 | END AS Type 7 | FROM tree 8 | ORDER BY id; 9 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/613_Shortest_Distance_in_a_Line.sql: -------------------------------------------------------------------------------- 1 | SELECT MIN(next-x) AS shortest 2 | FROM ( 3 | SELECT x, LEAD(x) OVER (ORDER BY x) AS next 4 | FROM point 5 | ) tb1; 6 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/614_Second_Degree_Follower.sql: -------------------------------------------------------------------------------- 1 | SELECT followee AS follower, COUNT(DISTINCT follower) AS num 2 | FROM follow 3 | GROUP BY followee 4 | HAVING followee IN (SELECT follower FROM follow) 5 | ORDER BY followee; 6 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/615_Average_Salary_Departments_VS_Company.sql: -------------------------------------------------------------------------------- 1 | -- If need to extract date in other format in the future, FORMAT() function could be used 2 | 3 | -- Solution 1: Join, Window Function, Subquery, CASE WHEN 4 | WITH tb1 AS ( 5 | SELECT DISTINCT department_id, LEFT(pay_date,7) AS pay_month, 6 | AVG(amount) OVER (PARTITION BY department_id, LEFT(pay_date,7))AS avg_dept, 7 | AVG(amount) OVER (PARTITION BY LEFT(pay_date,7)) AS avg_comp 8 | FROM salary s 9 | JOIN employee e 10 | ON s.employee_id = e.employee_id 11 | ) 12 | 13 | SELECT pay_month, department_id, 14 | CASE 15 | WHEN avg_dept > avg_comp THEN 'higher' 16 | WHEN avg_dept < avg_comp THEN 'lower' 17 | ELSE 'same' 18 | END AS comparison 19 | FROM tb1; 20 | 21 | 22 | 23 | -- Solution 2: Join, Subquery, CASE WHEN 24 | WITH dept AS ( 25 | SELECT e.department_id, LEFT(s.pay_date,7) AS pay_month, AVG(s.amount) AS avg_dept 26 | FROM salary s 27 | JOIN employee e 28 | ON s.employee_id = e.employee_id 29 | GROUP BY e.department_id, LEFT(s.pay_date,7) 30 | ), 31 | comp AS ( 32 | SELECT LEFT(pay_date,7) AS pay_month, AVG(amount) AS avg_comp 33 | FROM salary 34 | GROUP BY LEFT(pay_date,7) 35 | ) 36 | 37 | SELECT d.department_id, d.pay_month, 38 | CASE 39 | WHEN d.avg_dept > c.avg_comp THEN 'higher' 40 | WHEN d.avg_dept < c.avg_comp THEN 'lower' 41 | ELSE 'same' 42 | END AS comparison 43 | FROM dept d 44 | JOIN comp c 45 | ON d.pay_month = c.pay_month; 46 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/618_Students_Report_By_Geography.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, PIVOT/UNPIVOT 2 | WITH tb1 AS ( 3 | -- Numbering student from each continent separately by their name alphabetically 4 | SELECT *, ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r 5 | FROM student 6 | ) 7 | 8 | -- each row will be a group of student name of whom from different continent and have same numbering 9 | SELECT [America],[Asia],[Europe] 10 | FROM tb1 11 | PIVOT ( 12 | MIN(name) FOR continent IN ([America],[Asia],[Europe]) 13 | ) pvt; 14 | 15 | 16 | 17 | -- Solution 2: Window Function, Subquery, IFF 18 | WITH tb1 AS ( 19 | -- Numbering student from each continent separately by their name alphabetically 20 | SELECT ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r, 21 | IIF(continent = 'America', name, NULL) AS America, 22 | IIF(continent = 'Asia', name, NULL) AS Asia, 23 | IIF(continent = 'Europe', name, NULL) AS Europe 24 | FROM student 25 | ) 26 | 27 | -- Since numbering is unique in each continent, 28 | -- in each numbering group (1-3 rows), there ia only one cell contained student name in each column (e.g. America, Asia, Europe) 29 | SELECT MIN(America) AS America, MIN(Asia) AS Asia, MIN(Europe) AS Europe 30 | FROM tb1 31 | GROUP BY r; 32 | -------------------------------------------------------------------------------- /Subquery/Simple-Subquery/626_Exchange_Seats.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | CASE 3 | WHEN id % 2 = 1 AND id = (SELECT MAX(id) FROM seat) THEN id 4 | WHEN id % 2 = 1 THEN id + 1 5 | ELSE id - 1 6 | END AS id, 7 | student 8 | FROM seat 9 | ORDER BY 1; 10 | -------------------------------------------------------------------------------- /Subquery/Subquery.md: -------------------------------------------------------------------------------- 1 | # Subquery 2 | 3 | ## Basic Structure 4 | 5 | ```SQL 6 | SELECT AVG(total_spent) 7 | FROM ( 8 | SELECT TOP 10 a.name, SUM(total_amt_usd) AS total_spent 9 | FROM accounts a 10 | JOIN orders o 11 | ON o.account_id = a.id 12 | GROUP BY a.name 13 | ORDER BY total_spent DESC 14 | ) tbl1 15 | ``` 16 | 17 | ## Using WITH 18 | 19 | ``` SQL 20 | WITH tbl1 AS ( 21 | SELECT AVG(total_amt_usd) avg_spent 22 | FROM orders 23 | ), 24 | tbl2 AS( 25 | SELECT a.name, AVG(total_amt_usd) total_spent 26 | FROM accounts a 27 | JOIN orders o 28 | ON o.account_id = a.id 29 | GROUP BY a.name 30 | HAVING AVG(total_amt_usd) > (SELECT * FROM tbl1) 31 | ) 32 | 33 | SELECT AVG(total_spent) 34 | FROM tbl2 35 | ``` 36 | -------------------------------------------------------------------------------- /Variable/1098_Unpopular_Books.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | DECLARE @d date; 4 | SET @d = '2019-06-23'; 5 | 6 | SELECT book_id, name 7 | FROM Books 8 | WHERE available_from <= DATEADD(month, -1, @d) 9 | -- find books that have sold more than 10 copies in the last year 10 | AND book_id NOT IN ( 11 | SELECT book_id 12 | FROM Orders 13 | WHERE dispatch_date > DATEADD(year, -1, @d) 14 | GROUP BY book_id 15 | HAVING SUM(quantity) >= 10 16 | ); 17 | -------------------------------------------------------------------------------- /Variable/1107_New_Users_Daily_Count.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | -- Solution 1: Subquery, Variable 4 | DECLARE @d date; 5 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 6 | 7 | WITH tb1 AS ( 8 | SELECT user_id, MIN(activity_date) AS login_date 9 | FROM traffic 10 | WHERE activity = 'login' 11 | GROUP BY user_id) 12 | 13 | SELECT login_date, COUNT(*) AS user_count 14 | FROM tb1 15 | GROUP BY login_date 16 | HAVING login_date >= @d; 17 | 18 | 19 | 20 | -- Solution 2: Window Function, Subquery, Variable 21 | 22 | -- Using ROW_NUMBER() instead of RANK() or DENSE_RANK() 23 | -- to avoid return several rows when user login more than once at the first date 24 | 25 | DECLARE @d date; 26 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 27 | 28 | WITH tb1 AS ( 29 | SELECT *, 30 | ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY activity_date) AS r 31 | FROM Traffic 32 | WHERE activity = 'login' 33 | ) 34 | 35 | SELECT activity_date AS login_date, COUNT(*) AS user_count 36 | FROM tb1 37 | WHERE r = 1 38 | GROUP BY activity_date 39 | HAVING activity_date >= @d; 40 | -------------------------------------------------------------------------------- /Variable/1113_Reported_Posts.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | -- Solution: Variable 4 | DECLARE @d date; 5 | SET @d = DATEADD(day,-1,'2019-07-05'); 6 | 7 | SELECT extra AS report_reason, 8 | COUNT(DISTINCT post_id) AS report_count 9 | FROM Actions 10 | WHERE Action_date = @d AND action = 'report' 11 | GROUP BY extra; 12 | -------------------------------------------------------------------------------- /Variable/597_Friend_Requests_I_Overall_Acceptance_Rate.sql: -------------------------------------------------------------------------------- 1 | DECLARE @accept DECIMAL(10,2); 2 | DECLARE @send DECIMAL(10,2); 3 | 4 | SELECT @accept = COUNT(*) 5 | FROM ( 6 | SELECT DISTINCT requester_id, accepter_id 7 | FROM request_accepted 8 | ) AS tb1; 9 | 10 | SELECT @send = IIF(COUNT(*) < 1, 1, COUNT(*)) 11 | FROM ( 12 | SELECT DISTINCT sender_id, send_to_id 13 | FROM friend_request 14 | ) AS tb2; 15 | 16 | Select CAST(@accept / @send AS DECIMAL(3,2)) AS accept_rate; 17 | -------------------------------------------------------------------------------- /Window-Function/1070_Product_Sales_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | SELECT product_id, year AS first_year, quantity, price 2 | FROM ( 3 | SELECT *, DENSE_RANK() OVER (PARTITION BY product_id ORDER BY year) AS r 4 | FROM Sales 5 | ) tb1 6 | WHERE r = 1; 7 | -------------------------------------------------------------------------------- /Window-Function/1077_Project_Employees_III.sql: -------------------------------------------------------------------------------- 1 | SELECT project_id, employee_id 2 | FROM ( 3 | SELECT p.project_id, p.employee_id, 4 | RANK() OVER (PARTITION BY project_id ORDER BY experience_years DESC) AS r 5 | FROM Project p 6 | JOIN Employee e 7 | ON p.employee_id = e.employee_id 8 | ) tb1 9 | WHERE r = 1; 10 | -------------------------------------------------------------------------------- /Window-Function/1107_New_Users_Daily_Count.sql: -------------------------------------------------------------------------------- 1 | -- You could update the variable to any date you want or GETDATE(), and then same analysis will be done for the new date 2 | 3 | -- Using ROW_NUMBER() instead of RANK() or DENSE_RANK() 4 | -- to avoid return several rows when user login more than once at the first date 5 | 6 | DECLARE @d date; 7 | SET @d = DATEADD(DAY,-90, '2019-06-30'); 8 | 9 | WITH tb1 AS ( 10 | SELECT *, 11 | ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY activity_date) AS r 12 | FROM Traffic 13 | WHERE activity = 'login' 14 | ) 15 | 16 | SELECT activity_date AS login_date, COUNT(*) AS user_count 17 | FROM tb1 18 | WHERE r = 1 19 | GROUP BY activity_date 20 | HAVING activity_date >= @d; 21 | -------------------------------------------------------------------------------- /Window-Function/1112_Highest_Grade_For_Each_Student.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT *, 3 | ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY grade DESC, course_id) AS r 4 | FROM Enrollments 5 | ) 6 | 7 | SELECT student_id, course_id, grade 8 | FROM tb1 9 | WHERE r = 1 10 | ORDER BY student_id; 11 | -------------------------------------------------------------------------------- /Window-Function/1126_Active_Businesses.sql: -------------------------------------------------------------------------------- 1 | -- calculate average occurences of event types amont all business 2 | WITH tb1 AS ( 3 | SELECT *, 4 | AVG(occurences*1.0) OVER (PARTITION BY event_type) AS avg_oc 5 | FROM Events 6 | ) 7 | 8 | SELECT business_id 9 | FROM tb1 10 | GROUP BY business_id 11 | -- count number of event types of a business with occurences 12 | -- greater than the average occurences of that event type among all businesses 13 | HAVING SUM(CASE WHEN occurences > avg_oc THEN 1 ELSE 0 END) > 1; 14 | -------------------------------------------------------------------------------- /Window-Function/1127_User_Purchase_Platform.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT user_id,spend_date,amount, 3 | CASE 4 | WHEN COUNT(*) OVER (PARTITION BY user_id, spend_date) = 1 THEN platform 5 | ELSE 'both' 6 | END AS platform 7 | FROM Spending 8 | ), 9 | tb2 AS ( 10 | SELECT spend_date, platform, 11 | SUM(amount) AS total_amount, 12 | COUNT(DISTINCT user_id) AS total_users 13 | FROM tb1 14 | GROUP BY spend_date, platform 15 | ), 16 | d AS ( 17 | SELECT DISTINCT spend_date 18 | FROM tb2 19 | ), 20 | p AS ( 21 | SELECT 'desktop' AS platform 22 | UNION 23 | SELECT 'mobile' 24 | UNION 25 | SELECT 'both' 26 | ) 27 | 28 | SELECT d.spend_date, p.platform, 29 | ISNULL(total_amount,0) AS total_amount, 30 | ISNULL(total_users,0) AS total_users 31 | FROM d 32 | CROSS JOIN p 33 | LEFT JOIN tb2 34 | ON d.spend_date = tb2.spend_date and p.platform = tb2.platform; 35 | -------------------------------------------------------------------------------- /Window-Function/1159_Market_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | -- get item_id of the second item (by date) they sold for each user 2 | WITH tb1 AS ( 3 | SELECT seller_id, item_id 4 | FROM ( 5 | SELECT seller_id, item_id, 6 | ROW_NUMBER() OVER (PARTITION BY seller_id ORDER BY order_date) AS r 7 | FROM Orders 8 | ) rank 9 | WHERE r = 2 10 | ) 11 | 12 | -- compare the brand of the second item (by date) they sold with their favorite brand for each user 13 | -- if a user sold less than two items, he/she will have no data from tb1, and thus will be assigned 'no' 14 | SELECT u.user_id AS seller_id, 15 | CASE 16 | WHEN u.favorite_brand = i.item_brand THEN 'yes' 17 | ELSE 'no' 18 | END AS '2nd_item_fav_brand' 19 | FROM Users u 20 | LEFT JOIN tb1 21 | ON u.user_id = tb1.seller_id 22 | LEFT JOIN Items i 23 | ON tb1.item_id = i.item_id; 24 | -------------------------------------------------------------------------------- /Window-Function/1164_Product_Price_at_a_Given_Date.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT product_id, new_price 3 | FROM ( 4 | SELECT product_id, new_price, 5 | -- use ROW_NUMBER() to find the last time when the price of each product was changed before '2019-08-16' 6 | -- so if the price of a product had not been changed before '2019-08-16', the product will not be included in tb1 7 | ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY change_date DESC) AS r 8 | FROM Products 9 | WHERE change_date <= '2019-08-16' 10 | ) rank 11 | WHERE r = 1 12 | ) 13 | 14 | -- if a product does not in tb1, which means it has no price change before '2019-08-16' 15 | -- assign the original price 10 to that product 16 | SELECT p.product_id, ISNULL(new_price,10) AS price 17 | FROM ( 18 | SELECT DISTINCT product_id 19 | FROM Products 20 | ) p 21 | LEFT JOIN tb1 22 | ON p.product_id = tb1.product_id; 23 | -------------------------------------------------------------------------------- /Window-Function/1174_Immediate_Food_Delivery_II.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT order_date, customer_pref_delivery_date, 3 | -- identify first order of each customer 4 | ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS r 5 | FROM delivery 6 | ) 7 | 8 | SELECT CAST( 9 | AVG( 10 | CASE 11 | WHEN order_date = customer_pref_delivery_date THEN 100.0 12 | ELSE 0 13 | END 14 | ) 15 | AS DECIMAL(5,2) 16 | ) AS immediate_percentage 17 | FROM tb1 18 | WHERE r = 1; 19 | -------------------------------------------------------------------------------- /Window-Function/1194_Tournament_Winners.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Subquery, Join, Window Function 2 | -- merge first and second players and their scores into two columns 3 | WITH tb1 AS ( 4 | SELECT first_player AS player, first_score as score 5 | FROM Matches 6 | UNION ALL 7 | SELECT second_player, second_score 8 | FROM Matches 9 | ), 10 | -- calculate total points scored by each user along with their group information 11 | tb2 AS ( 12 | SELECT p.player_id, p.group_id, SUM(tb1.score) AS tp 13 | FROM Players p 14 | LEFT JOIN tb1 15 | ON p.player_id = tb1.player 16 | GROUP BY p.player_id, p.group_id 17 | ) 18 | 19 | -- find the winner with lowest player_id in each group who scored the maximum total points within the group 20 | SELECT group_id, player_id 21 | FROM ( 22 | SELECT player_id, group_id, 23 | ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY tp DESC, player_id) AS r 24 | FROM tb2 25 | ) tb3 26 | WHERE r = 1; 27 | 28 | 29 | 30 | -- Solution 2: Subquery, Join, CASE WEHN, Window Function 31 | -- calculate total points scored by each user along with their group information 32 | WITH tb1 AS ( 33 | SELECT player_id, group_id, 34 | SUM( 35 | CASE 36 | WHEN player_id = first_player THEN first_score 37 | ELSE second_score 38 | END 39 | ) AS tp 40 | FROM players p 41 | LEFT JOIN matches m 42 | ON p.player_id = m.first_player OR p.player_id = m.second_player 43 | GROUP BY player_id, group_id 44 | ) 45 | 46 | -- find the winner with lowest player_id in each group who scored the maximum total points within the group 47 | SELECT group_id, player_id 48 | FROM ( 49 | SELECT player_id, group_id, 50 | ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY tp DESC, player_id) AS r 51 | FROM tb1 52 | ) tb2 53 | WHERE r = 1; 54 | -------------------------------------------------------------------------------- /Window-Function/1204_Last_Person_to_Fit_in_the_Elevator.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 1 person_name 2 | FROM ( 3 | SELECT person_name, turn, 4 | SUM(weight) OVER (ORDER BY turn) AS tw 5 | FROM Queue 6 | ) tb1 7 | WHERE tw <= 1000 8 | ORDER BY turn DESC; 9 | -------------------------------------------------------------------------------- /Window-Function/1225_Report_Contiguous_Dates.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT fail_date AS date, 'failed' AS s 3 | FROM Failed 4 | UNION 5 | SELECT success_date AS date, 'succeeded' AS s 6 | FROM Succeeded 7 | ), 8 | tb2 AS ( 9 | SELECT *, 10 | ROW_NUMBER() OVER (PARTITION BY s ORDER BY date) AS r, 11 | ROW_NUMBER() OVER (ORDER BY date) AS r2 12 | FROM tb1 13 | WHERE Year(date) = 2019 14 | ) 15 | 16 | -- contiguous dates with same period state share the same r2-r, 17 | -- so in a group with same r2-4, the smallest date is start date and the largest date is end date 18 | SELECT s AS period_state, MIN(date) AS start_date, MAX(date) AS end_date 19 | FROM tb2 20 | GROUP BY r2-r, s 21 | ORDER BY start_date; 22 | -------------------------------------------------------------------------------- /Window-Function/1285_Find_the_Start_and_End_Number_of_Continuous_Ranges.sql: -------------------------------------------------------------------------------- 1 | -- when the number is continous with the last one, both log_id and r add 1 2 | -- Therefore, continuous numbers share the same log_id - r 3 | -- when grouped by log_id - r, the start number is the samllest number in group and the end is the largest 4 | WITH tb1 AS ( 5 | SELECT log_id, ROW_NUMBER() OVER (ORDER BY log_id) AS r 6 | FROM Logs 7 | ) 8 | 9 | SELECT MIN(log_id) AS START_ID, MAX(log_id) AS END_ID 10 | FROM tb1 11 | GROUP BY log_id-r; 12 | -------------------------------------------------------------------------------- /Window-Function/1303_Find_the_Team_Size.sql: -------------------------------------------------------------------------------- 1 | SELECT employee_id, 2 | COUNT(*) OVER (PARTITION BY team_id) AS team_size 3 | FROM Employee; 4 | -------------------------------------------------------------------------------- /Window-Function/1308_Running_Total_for_Different_Genders.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT gender, day, 2 | SUM(score_points) OVER (PARTITION BY gender ORDER BY day) AS total 3 | FROM Scores 4 | ORDER BY gender, day; 5 | -------------------------------------------------------------------------------- /Window-Function/1321_Restaurant_Growth.sql: -------------------------------------------------------------------------------- 1 | SELECT visited_on, 2 | SUM(SUM(amount)) OVER ( 3 | ORDER BY visited_on 4 | ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 5 | ) AS amount, 6 | CAST( 7 | SUM(SUM(amount)) OVER ( 8 | ORDER BY visited_on 9 | ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 10 | )/7.0 11 | AS DECIMAL(10,2) 12 | ) AS average_amount 13 | FROM Customer 14 | GROUP BY visited_on 15 | ORDER BY visited_on 16 | OFFSET 6 ROWS; 17 | -------------------------------------------------------------------------------- /Window-Function/1355_Activity_Participants.sql: -------------------------------------------------------------------------------- 1 | SELECT activity 2 | FROM ( 3 | SELECT activity, 4 | -- Numbering activity by number of participants in ascending and descending order 5 | RANK() OVER (ORDER BY COUNT(*)) AS r1, 6 | RANK() OVER (ORDER BY COUNT(*) DESC) AS r2 7 | FROM Friends 8 | GROUP BY activity 9 | ) tb1 10 | -- fliter out activities with minimum or maximum number of participants 11 | WHERE r1 != 1 AND r2 != 1; 12 | -------------------------------------------------------------------------------- /Window-Function/1369_Get_the_Second_Most_Recent_Activity.sql: -------------------------------------------------------------------------------- 1 | SELECT username, activity, startDate, endDate 2 | FROM ( 3 | SELECT *, 4 | ROW_NUMBER() OVER (PARTITION BY username ORDER BY endDate DESC) AS r, 5 | COUNT(*) OVER (PARTITION BY username) AS c 6 | FROM UserActivity 7 | ) tb1 8 | WHERE r = 2 OR c = 1; 9 | -------------------------------------------------------------------------------- /Window-Function/1412_Find_The_Quiet_Students_in_All_Exams.sql: -------------------------------------------------------------------------------- 1 | -- rank scores in each exam by both ascending and descending orders 2 | -- if h_rank = 1 then the student has the highest score in according exam 3 | -- if r_rank = 1 then the student has the lowest score in that exam 4 | WITH rank_exam AS ( 5 | SELECT student_id, 6 | RANK() OVER (PARTITION BY exam_id ORDER BY score DESC) AS h_rank, 7 | RANK() OVER (PARTITION BY exam_id ORDER BY score) AS l_rank 8 | FROM Exam 9 | ) 10 | 11 | SELECT * 12 | FROM Student 13 | -- find the student who is quiet in ALL exams 14 | WHERE student_id NOT IN ( 15 | SELECT DISTINCT student_id 16 | FROM rank_exam 17 | WHERE l_rank = 1 OR h_rank = 1 18 | ) 19 | -- make sure student take at least one exam 20 | AND student_id IN (SELECT DISTINCT student_id FROM Exam) 21 | -------------------------------------------------------------------------------- /Window-Function/176_Second_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | SELECT AVG(salary) SecondHighestSalary 2 | FROM ( 3 | SELECT salary 4 | ,DENSE_RANK() OVER (ORDER BY salary DESC) r 5 | FROM employee 6 | ) tb1 7 | WHERE r = 2; 8 | -------------------------------------------------------------------------------- /Window-Function/177_Nth_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION getNthHighestSalary(@N INT) RETURNS INT AS 2 | BEGIN 3 | RETURN ( 4 | SELECT AVG(salary) 5 | FROM ( 6 | SELECT salary, DENSE_RANK() over (ORDER BY salary DESC) r 7 | FROM employee 8 | ) tb1 9 | WHERE r = @N 10 | ); 11 | END 12 | -------------------------------------------------------------------------------- /Window-Function/178_Rank_Scores.sql: -------------------------------------------------------------------------------- 1 | SELECT score, DENSE_RANK() OVER (ORDER BY score DESC) AS Rank 2 | FROM scores; 3 | -------------------------------------------------------------------------------- /Window-Function/180_Consecutive_Numbers.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT num AS ConsecutiveNums 2 | FROM ( 3 | SELECT num, 4 | LEAD(num) OVER (ORDER BY id) AS next, 5 | LAG(num) OVER (ORDER BY id) AS prev 6 | FROM logs 7 | ) tb1 8 | WHERE num = next AND next = prev; 9 | -------------------------------------------------------------------------------- /Window-Function/184_Department_Highest_Salary.sql: -------------------------------------------------------------------------------- 1 | SELECT department, employee, salary 2 | FROM ( 3 | SELECT d.name department, e.name employee ,salary, 4 | -- ranking salaries in each department 5 | -- the employee with highest salary will get r = 1 6 | DENSE_RANK() OVER ( 7 | PARTITION BY departmentid 8 | ORDER BY salary DESC) r 9 | FROM employee e 10 | JOIN department d 11 | ON e.departmentid = d.id 12 | ) AS tb1 13 | WHERE r = 1; 14 | -------------------------------------------------------------------------------- /Window-Function/185_Department_Top_Three_Salaries.sql: -------------------------------------------------------------------------------- 1 | SELECT department, employee, salary 2 | FROM ( 3 | SELECT d.name AS department, e.name AS employee, salary, 4 | DENSE_RANK() OVER ( 5 | PARTITION BY departmentid 6 | ORDER BY salary DESC 7 | ) AS r 8 | FROM employee e 9 | JOIN department d 10 | ON e.departmentid = d.id 11 | ) AS tb1 12 | WHERE r <= 3 13 | -------------------------------------------------------------------------------- /Window-Function/197_Rising_Temperature.sql: -------------------------------------------------------------------------------- 1 | SELECT id 2 | FROM ( 3 | SELECT *, 4 | -- Get temperature and date of previous record date, if none get null 5 | LAG(temperature) OVER (ORDER BY recorddate) AS prev_temp, 6 | LAG(recorddate) OVER (ORDER BY recorddate) prev_date 7 | FROM weather 8 | ) tb1 9 | WHERE DATEADD(day,1,prev_date) = recorddate AND prev_temp < temperature; 10 | -------------------------------------------------------------------------------- /Window-Function/512_Game_Play_Analysis_II.sql: -------------------------------------------------------------------------------- 1 | SELECT player_id, device_id 2 | FROM ( 3 | SELECT player_id, device_id, 4 | DENSE_RANK() OVER (PARTITION BY player_id ORDER BY event_date) AS r 5 | FROM Activity) tb1 6 | WHERE r = 1; 7 | -------------------------------------------------------------------------------- /Window-Function/534_Game_Play_Analysis_III.sql: -------------------------------------------------------------------------------- 1 | SELECT player_id, event_date, 2 | SUM(games_played) OVER ( 3 | PARTITION BY player_id 4 | ORDER BY event_date 5 | ) AS games_played_so_far 6 | FROM activity; 7 | -------------------------------------------------------------------------------- /Window-Function/550_Game_Play_Analysis_IV.sql: -------------------------------------------------------------------------------- 1 | WITH tb2 as ( 2 | SELECT player_id 3 | FROM ( 4 | SELECT player_id, 5 | -- the first-logged-in date 6 | MIN(event_date) OVER (PARTITION BY player_id) AS event_date, 7 | -- the next-logged-in date after first-logged-in date 8 | LEAD(event_date) OVER (PARTITION BY player_id ORDER BY event_date) AS lead_date 9 | FROM activity 10 | ) tb1 11 | -- only keep users the next-logged-in date after first-logged-in date is the day after first-logged in date 12 | WHERE dateadd(day,1, event_date) = lead_date 13 | ) 14 | 15 | SELECT CAST( 16 | COUNT(DISTINCT player_id)*1.0/(SELECT COUNT(DISTINCT player_id) FROM activity) 17 | AS DECIMAL(3,2) 18 | ) AS fraction 19 | FROM tb2; 20 | -------------------------------------------------------------------------------- /Window-Function/569_Median_Employee_Salary.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT *, 3 | ROW_NUMBER() OVER (PARTITION BY company ORDER BY salary) AS r, 4 | COUNT(*) OVER (PARTITION BY company) AS num 5 | FROM employee 6 | ) 7 | 8 | SELECT id, company, salary 9 | FROM tb1 10 | -- when num % 2 = 0, the r of the median is num/2 and num/2 + 1 11 | -- when num % 2 = 1, the r of the median is (num+1)/2, between num/2 and num/2 + 1 12 | WHERE r BETWEEN num*1.0/2 AND num*1.0/2 + 1; 13 | -------------------------------------------------------------------------------- /Window-Function/571_Find_Median_Given_Frequency_of_Numbers.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT *, 3 | -- There are cum_num numbers in TABLE numbers less than or equal to number in that record 4 | -- e.g. There are cum_num = 8 numbers in TABLE numbers less than or equal to 1 5 | -- so you will see [1,1,8,12] AS [Number, Frequency, cum_num, num] 6 | SUM(frequency) OVER (ORDER BY number) AS cum_num, 7 | SUM(frequency) OVER () AS num 8 | FROM numbers 9 | ) 10 | 11 | SELECT AVG(number*1.0) AS median 12 | FROM tb1 13 | WHERE num / 2.0 BETWEEN cum_num - frequency AND cum_num; 14 | -------------------------------------------------------------------------------- /Window-Function/579_Find_Cumulative_Salary_of_an_Employee.sql: -------------------------------------------------------------------------------- 1 | SELECT e.id, month, 2 | SUM(Salary) OVER ( 3 | PARTITION BY id 4 | ORDER BY month 5 | -- get the cumulative sum of an employee's salary over a period of 3 months 6 | ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS Salary 7 | FROM Employee e 8 | -- exclude the most recent month for each employee 9 | WHERE month != (SELECT MAX(Month) FROM Employee WHERE id = e.id) 10 | ORDER BY id, month DESC; 11 | -------------------------------------------------------------------------------- /Window-Function/585_Investments_in_2016.sql: -------------------------------------------------------------------------------- 1 | SELECT CAST(SUM(TIV_2016) AS DECIMAL(10,2)) AS TIV_2016 2 | FROM ( 3 | SELECT TIV_2016, 4 | COUNT(*) OVER (PARTITION BY TIV_2015) AS count_2015, 5 | COUNT(*) OVER (PARTITION BY LAT, LON) AS count_loc 6 | FROM insurance 7 | ) tb1 8 | WHERE count_2015 > 1 AND count_loc = 1; 9 | -------------------------------------------------------------------------------- /Window-Function/601_Human_Traffic_of_Stadium.sql: -------------------------------------------------------------------------------- 1 | WITH tb1 AS ( 2 | SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS r 3 | FROM stadium 4 | WHERE people >=100 5 | ), 6 | tb2 AS ( 7 | SELECT id, visit_date, people, COUNT(*) OVER (PARTITION BY id-r) AS num 8 | FROM tb1 9 | ) 10 | 11 | SELECT id, visit_date, people 12 | FROM tb2 13 | WHERE num >= 3; 14 | -------------------------------------------------------------------------------- /Window-Function/603_Consecutive_Available_Seats.sql: -------------------------------------------------------------------------------- 1 | -- Soltuion 1: Window Function, Subquery 2 | WITH tb1 AS ( 3 | SELECT seat_id, row_number() OVER (ORDER BY seat_id) AS r 4 | FROM cinema 5 | WHERE free = 1 6 | ), 7 | tb2 AS ( 8 | SELECT seat_id, COUNT(*) OVER (PARTITION BY (seat_id - r)) AS num 9 | FROM tb1 10 | ) 11 | 12 | SELECT seat_id 13 | FROM tb2 14 | WHERE num >= 2; 15 | 16 | 17 | 18 | -- Soltuion 2: Window Function, Subquery 19 | WITH tb1 AS ( 20 | SELECT seat_id, free AS free1, 21 | LEAD(free) OVER (ORDER BY seat_id) AS free2, 22 | LAG(free) OVER (ORDER BY seat_id) AS free0 23 | FROM cinema 24 | ) 25 | 26 | SELECT seat_id 27 | FROM tb1 28 | WHERE free1 = 1 AND (free2 = 1 OR free0 = 1); 29 | -------------------------------------------------------------------------------- /Window-Function/613_Shortest_Distance_in_a_Line.sql: -------------------------------------------------------------------------------- 1 | SELECT MIN(next-x) AS shortest 2 | FROM ( 3 | SELECT x, LEAD(x) OVER (ORDER BY x) AS next 4 | FROM point 5 | ) tb1; 6 | -------------------------------------------------------------------------------- /Window-Function/615_Average_Salary_Departments_VS_Company.sql: -------------------------------------------------------------------------------- 1 | -- If need to extract date in other format in the future, FORMAT() function could be used 2 | 3 | WITH tb1 AS ( 4 | SELECT DISTINCT department_id, LEFT(pay_date,7) AS pay_month, 5 | AVG(amount) OVER (PARTITION BY department_id, LEFT(pay_date,7))AS avg_dept, 6 | AVG(amount) OVER (PARTITION BY LEFT(pay_date,7)) AS avg_comp 7 | FROM salary s 8 | JOIN employee e 9 | ON s.employee_id = e.employee_id 10 | ) 11 | 12 | SELECT pay_month, department_id, 13 | CASE 14 | WHEN avg_dept > avg_comp THEN 'higher' 15 | WHEN avg_dept < avg_comp THEN 'lower' 16 | ELSE 'same' 17 | END AS comparison 18 | FROM tb1; 19 | -------------------------------------------------------------------------------- /Window-Function/618_Students_Report_By_Geography.sql: -------------------------------------------------------------------------------- 1 | -- Solution 1: Window Function, Subquery, PIVOT/UNPIVOT 2 | WITH tb1 AS ( 3 | -- Numbering student from each continent separately by their name alphabetically 4 | SELECT *, ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r 5 | FROM student 6 | ) 7 | 8 | -- each row will be a group of student name of whom from different continent and have same numbering 9 | SELECT [America],[Asia],[Europe] 10 | FROM tb1 11 | PIVOT ( 12 | MIN(name) FOR continent IN ([America],[Asia],[Europe]) 13 | ) pvt; 14 | 15 | 16 | 17 | -- Solution 2: Window Function, Subquery, IFF 18 | WITH tb1 AS ( 19 | -- Numbering student from each continent separately by their name alphabetically 20 | SELECT ROW_NUMBER() OVER (PARTITION BY continent ORDER BY name) AS r, 21 | IIF(continent = 'America', name, NULL) AS America, 22 | IIF(continent = 'Asia', name, NULL) AS Asia, 23 | IIF(continent = 'Europe', name, NULL) AS Europe 24 | FROM student 25 | ) 26 | 27 | -- Since numbering is unique in each continent, 28 | -- in each numbering group (1-3 rows), there ia only one cell contained student name in each column (e.g. America, Asia, Europe) 29 | SELECT MIN(America) AS America, MIN(Asia) AS Asia, MIN(Europe) AS Europe 30 | FROM tb1 31 | GROUP BY r; 32 | --------------------------------------------------------------------------------