diff --git a/sql/task1.sql b/sql/task1.sql index 90de336ca..f9ff77831 100644 --- a/sql/task1.sql +++ b/sql/task1.sql @@ -1,14 +1,71 @@ -- Problem 1: Retrieve all products in the Sports category -- Write an SQL query to retrieve all products in a specific category. +-- Select the name from products to be outputted. Category id is related in Categories and Products so join them +-- Looking for the category id that is equal to 8 +SELECT + P.product_name +FROM + Products P +INNER JOIN + Categories C ON P.category_id = C.category_id +WHERE + C.category_id = 8; + + -- Problem 2: Retrieve the total number of orders for each user -- Write an SQL query to retrieve the total number of orders for each user. -- The result should include the user ID, username, and the total number of orders. +--Need User ID, Username and keep count of the number of orders for each user ID +-- Joining user_id in both orders and users +SELECT + U.user_id, + U.username, + COUNT(O.order_id) AS total_orders +FROM + Users U +LEFT JOIN + Orders O ON U.user_id = O.user_id +GROUP BY + U.user_id, U.username; + + -- Problem 3: Retrieve the average rating for each product -- Write an SQL query to retrieve the average rating for each product. -- The result should include the product ID, product name, and the average rating. +--Need to Average the ratings +--Join the product_id from reviews to products +SELECT + P.product_id, + P.product_name, + AVG(R.rating) AS Avg_Ratings +FROM + Products P +JOIN + Reviews R ON P.product_id = R.product_id +GROUP BY + P.product_id, P.Product_name; + -- Problem 4: Retrieve the top 5 users with the highest total amount spent on orders -- Write an SQL query to retrieve the top 5 users with the highest total amount spent on orders. -- The result should include the user ID, username, and the total amount spent. + +--LIMIT 5 at the end for the top 5 users +--Need the SUM of the total amount in Orders +--Join user_id from users and orders to have corresponding users to orders +--Filter the amount spent in a descending order from most spent to least amount spent +SELECT + U.user_id, + U.username, + SUM(O.total_amount) AS total_amount_spent +FROM + Users U +INNER JOIN + Orders O ON U.user_id = O.user_id +GROUP BY + U.user_id, U.username +ORDER BY + total_amount_spent DESC +LIMIT 5; \ No newline at end of file diff --git a/sql/task2.sql b/sql/task2.sql index ad2596731..e170de38a 100644 --- a/sql/task2.sql +++ b/sql/task2.sql @@ -3,17 +3,102 @@ -- The result should include the product ID, product name, and the average rating. -- Hint: You may need to use subqueries or common table expressions (CTEs) to solve this problem. +--Same idea as problem 3 but order the average rating in descending order from highest avg rating to lowest avg rating +SELECT + P.product_id, + P.product_name, + AVG(R.rating) AS average_rating +FROM + Products P +LEFT JOIN + Reviews R ON P.product_id = R.product_id +GROUP BY + P.product_id, P.product_name +ORDER BY + average_rating DESC; + + -- Problem 6: Retrieve the users who have made at least one order in each category -- Write an SQL query to retrieve the users who have made at least one order in each category. -- The result should include the user ID and username. -- Hint: You may need to use subqueries or joins to solve this problem. +--Join Users, Orders, Order Items, Products and Categories tables together +--Use subquery in WHERE to filter users who have made at least one order in each category by checking +-- counts of distinct categories for each users +--HAVING ensures the count for distinct categories matches the number of distinct categories in the Categories table +SELECT DISTINCT + U.user_id, + U.username, +FROM + Users U +JOIN + Orders O ON U.user_id = O.user_id +JOIN + Order_Items OI ON O.order_id = OI.order_id +JOIN + Products P ON OI.product_id = P.product_id +JOIN + Categories C ON P.category_id = C.category_id +WHERE + U.user_id IN ( + SELECT DISTINCT + U2.user_id + FROM + Users U2 + JOIN + Orders O2 ON U2.user_id = O2.user_id + JOIN + Order_Items OI2 ON O2.order_id = OI2.order_id + JOIN + Products P2 ON OI2.product_id = P2.product_id + JOIN + Categories C2 ON P2.category_id = C2.category_id + GROUP BY + U2.user_id, C2.category_id + HAVING + COUNT(DISTINCT C2.category_id) = (SELECT COUNT(DISTINCT category_id)FROM Categories) +); + -- Problem 7: Retrieve the products that have not received any reviews -- Write an SQL query to retrieve the products that have not received any reviews. -- The result should include the product ID and product name. -- Hint: You may need to use subqueries or left joins to solve this problem. +--Join product_id from reviews and products +--only output the product_id and name if the review_id is NULL (empty/not exist) for any product_id in Products +SELECT + P.product_id, P.product_name +FROM + Products P +LEFT JOIN + Reviews R ON P.product_id = R.product_id +WHERE + R.review_id IS NULL; + -- Problem 8: Retrieve the users who have made consecutive orders on consecutive days -- Write an SQL query to retrieve the users who have made consecutive orders on consecutive days. -- The result should include the user ID and username. --- Hint: You may need to use subqueries or window functions to solve this problem. \ No newline at end of file +-- Hint: You may need to use subqueries or window functions to solve this problem. + +--Using CTE to create a new table for OrderedOrders +--Use LEAD() window function to get next order_date for each row from the result set +--Partition result set by user id so the lead function is applied independently to each user and order the rows by order date within each partition +--Assign the above results into a new column called next_order_date +--WHERE filters wanted results that have a difference between consecutive orders of 1 day or next order date is NULL +WITH OrderedOrders AS ( + SELECT + user_id, + order_id, + order_date, + LEAD(order_date) OVER (PARTITION BY user_id ORDER BY order_date) AS next_order_date + FROM + Orders +) +SELECT DISTINCT U.user_id, U.username +FROM + Users U +JOIN + OrderedOrders O ON U.user_id = O.user_id +WHERE + DATEDIFF(next_order_date, order_date) = 1 OR next_order_date IS NULL; diff --git a/sql/task3.sql b/sql/task3.sql index f078a9439..252945bcf 100644 --- a/sql/task3.sql +++ b/sql/task3.sql @@ -3,17 +3,96 @@ -- The result should include the category ID, category name, and the total sales amount. -- Hint: You may need to use subqueries, joins, and aggregate functions to solve this problem. +--Use CTE called Category_Sales to include category_id, category_name and the sum of total_amount which would be the total_sales +--join all corresponding ids (such as category, product and order) from categories with products, order_items and orders +WITH Category_Sales AS ( + SELECT + C.category_id, + C.category_name, + SUM(O.total_amount) AS total_sales + FROM + Categories C + JOIN + Products P ON C.category_id = P.category_id + JOIN + Order_Items OI ON P.product_id = OI.product_id + JOIN + Orders O ON OI.order_id = O.order_id + GROUP BY + C.category_id, C.category_name +) + +--Select the category id, name and total sales as output from the new table and order it by having the highest total sales at the top +SELECT + category_id, + category_name, + total_sales +FROM + Category_Sales +ORDER BY + total_sales DESC +LIMIT 3; + -- Problem 10: Retrieve the users who have placed orders for all products in the Toys & Games -- Write an SQL query to retrieve the users who have placed orders for all products in the Toys & Games -- The result should include the user ID and username. -- Hint: You may need to use subqueries, joins, and aggregate functions to solve this problem. +--Filter products to those in "Toys & Games" +--HAVING used to make sure the count of distinct product IDs for each user is = total number of products in "Toys & Games" category +SELECT + U.user_id, + U.username +FROM + Users U +JOIN + Orders O ON U.user_id = O.user_id +JOIN + Order_Items OI ON O.order_id = OI.order_id +JOIN + Products P ON OI.product_id = P.product_id +WHERE + P.category_id = 5 +GROUP BY + U.user_id, U.username +HAVING + COUNT(DISTINCT P.product_id) = ( + SELECT COUNT(*) + FROM Products + WHERE category_id = 5 + ); + -- Problem 11: Retrieve the products that have the highest price within each category -- Write an SQL query to retrieve the products that have the highest price within each category. -- The result should include the product ID, product name, category ID, and price. -- Hint: You may need to use subqueries, joins, and window functions to solve this problem. +--Make a CTE called Ranked_Products and use ROW_NUMBER() function to assign ranks to each product within its category based on prices in desc order +--ORDER BY in OVER clause ensures that the ranking is reset for each category +--Main query selects products from the CTW where row_num will equal 1 -> meaning it'll select the products has the highest price in each category +WITH Ranked_Products AS ( + SELECT + product_id, + product_name, + category_id, + price, + ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num + FROM + Products +) + +SELECT + product_id, + product_name, + category_id, + price +FROM + Ranked_Products +WHERE + row_num = 1; + -- Problem 12: Retrieve the users who have placed orders on consecutive days for at least 3 days -- Write an SQL query to retrieve the users who have placed orders on consecutive days for at least 3 days. -- The result should include the user ID and username. -- Hint: You may need to use subqueries, joins, and window functions to solve this problem. +