diff --git a/sql/task1.sql b/sql/task1.sql index 90de336ca..14a6c394e 100644 --- a/sql/task1.sql +++ b/sql/task1.sql @@ -1,14 +1,35 @@ -- Problem 1: Retrieve all products in the Sports category -- Write an SQL query to retrieve all products in a specific category. +SELECT P.product_id, P.product_name, P.description, P.price, P.category_id +FROM Products P +JOIN Categories C ON P.category_id = C.category_id +WHERE C.category_name LIKE '%Sports%'; -- 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. +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 +ORDER BY U.user_id; -- 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. +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 P.product_id; -- 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. + +SELECT U.user_id, U.username, SUM(O.total_amount) AS total_spent +FROM Users U +JOIN Orders O ON U.user_id = O.user_id +GROUP BY U.user_id, U.username +ORDER BY total_spent DESC +LIMIT 5; diff --git a/sql/task2.sql b/sql/task2.sql index ad2596731..b773bdcaa 100644 --- a/sql/task2.sql +++ b/sql/task2.sql @@ -3,17 +3,77 @@ -- 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. +DROP VIEW IF EXISTS ProductAverageRatings CASCADE; +CREATE VIEW ProductAverageRatings AS +SELECT product_id, AVG(rating) AS average_rating +FROM Reviews +GROUP BY product_id; + +SELECT P.product_id, P.product_name, PAR.average_rating +FROM Products P +JOIN ProductAverageRatings PAR ON P.product_id = PAR.product_id +WHERE PAR.average_rating = (SELECT MAX(average_rating) FROM ProductAverageRatings); + + -- 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. +DROP VIEW IF EXISTS UserCategories CASCADE; +DROP VIEW IF EXISTS UniqueCategories CASCADE; +CREATE VIEW UniqueCategories AS +SELECT DISTINCT category_id +FROM Categories; + +CREATE VIEW UserCategories AS +SELECT DISTINCT U.user_id, P.category_id +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; + +SELECT U.user_id, U.username +FROM Users U +WHERE NOT EXISTS ( + SELECT 1 + FROM UniqueCategories UC + WHERE NOT EXISTS ( + SELECT 1 + FROM UserCategories UC2 + WHERE UC2.user_id = U.user_id AND UC2.category_id = UC.category_id + ) +) +GROUP BY U.user_id, U.username; + -- 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. +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. + +DROP VIEW IF EXISTS UserOrderDates CASCADE; +DROP VIEW IF EXISTS ConsecutiveUserOrders CASCADE; + +CREATE VIEW UserOrderDates AS +SELECT + user_id, + order_date, + LAG(order_date) OVER (PARTITION BY user_id ORDER BY order_date) AS previous_order_date +FROM Orders; +CREATE VIEW ConsecutiveUserOrders AS +SELECT + user_id +FROM UserOrderDates +WHERE order_date - previous_order_date = 1; +SELECT DISTINCT U.user_id, U.username +FROM Users U +JOIN ConsecutiveUserOrders CUO ON U.user_id = CUO.user_id; diff --git a/sql/task3.sql b/sql/task3.sql index f078a9439..1749813d9 100644 --- a/sql/task3.sql +++ b/sql/task3.sql @@ -3,17 +3,102 @@ -- 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. +SELECT + C.category_id, + C.category_name, + SUM(OI.quantity * OI.unit_price) AS total_sales_amount +FROM + Categories C +JOIN Products P ON C.category_id = P.category_id +JOIN Order_Items OI ON P.product_id = OI.product_id +GROUP BY + C.category_id, + C.category_name +ORDER BY + total_sales_amount 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. +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 +JOIN Categories C ON P.category_id = C.category_id +WHERE C.category_name = 'Toys & Games' +GROUP BY U.user_id, U.username +HAVING COUNT(DISTINCT P.product_id) = ( + SELECT COUNT(DISTINCT product_id) + FROM Products P + JOIN Categories C ON P.category_id = C.category_id + WHERE C.category_name = 'Toys & Games' +); -- 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. +DROP VIEW IF EXISTS HighestPricedProducts CASCADE; +CREATE VIEW HighestPricedProducts AS +WITH RankedProducts AS ( + SELECT + product_id, + product_name, + category_id, + price, + RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS price_rank + FROM Products +) +SELECT + product_id, + product_name, + category_id, + price +FROM RankedProducts +WHERE price_rank = 1; +SELECT * FROM HighestPricedProducts; -- 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. +DROP VIEW IF EXISTS UserConsecutiveOrders CASCADE; +DROP VIEW IF EXISTS UserConsecutiveStreaks CASCADE; +DROP VIEW IF EXISTS UserStreakLengths CASCADE; +DROP VIEW IF EXISTS UsersWith3DayStreaks CASCADE; +CREATE VIEW UserConsecutiveOrders AS +SELECT + user_id, + order_date, + LAG(order_date) OVER (PARTITION BY user_id ORDER BY order_date) AS previous_order_date +FROM Orders; +CREATE VIEW UserConsecutiveStreaks AS +SELECT + user_id, + order_date, + CASE + WHEN order_date - previous_order_date = 1 THEN 0 + ELSE 1 + END AS streak_start +FROM UserConsecutiveOrders; +CREATE VIEW UserStreakLengths AS +SELECT + user_id, + order_date, + SUM(streak_start) OVER (PARTITION BY user_id ORDER BY order_date) AS streak_id +FROM UserConsecutiveStreaks; +CREATE VIEW UsersWith3DayStreaks AS +SELECT + user_id, + COUNT(*) AS streak_length +FROM UserStreakLengths +GROUP BY user_id, streak_id +HAVING COUNT(*) >= 3; +SELECT DISTINCT U.user_id, U.username +FROM Users U +JOIN UsersWith3DayStreaks S ON U.user_id = S.user_id; diff --git a/tests/test_sql_queries.py b/tests/test_sql_queries.py index 22b25d546..3abef7c18 100644 --- a/tests/test_sql_queries.py +++ b/tests/test_sql_queries.py @@ -6,11 +6,11 @@ class TestSQLQueries(unittest.TestCase): def setUp(self): # Establish a connection to your test database self.conn = psycopg2.connect( - dbname='your_dbname', - user='your_username', - password='your_password', - host='your_host', - port='your_port' + dbname='postgres', + user='postgres', + password='toor', + host='127.0.0.1', + port='5432' ) self.cur = self.conn.cursor() @@ -21,7 +21,7 @@ def tearDown(self): def test_task1(self): # Task 1: Example SQL query in task1.sql - with open('/sql/task1.sql', 'r') as file: + with open('./sql/task1.sql', 'r') as file: sql_query = file.read() self.cur.execute(sql_query) @@ -36,7 +36,7 @@ def test_task1(self): def test_task2(self): # Task 2: Example SQL query in task2.sql - with open('/sql/task2.sql', 'r') as file: + with open('./sql/task2.sql', 'r') as file: sql_query = file.read() self.cur.execute(sql_query)