Skip to content

Commit 64c794d

Browse files
committed
Update readme.md
1 parent 2b7acdb commit 64c794d

File tree

1 file changed

+229
-0
lines changed
  • LeetCode SQL 50 Solution/1251. Average Selling Price

1 file changed

+229
-0
lines changed
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
Here's a well-structured `README.md` file for **LeetCode 1251 - Average Selling Price**, formatted for a GitHub repository:
2+
3+
```md
4+
# 🛒 Average Selling Price - LeetCode 1251
5+
6+
## 📌 Problem Statement
7+
You are given two tables, **Prices** and **UnitsSold**, which contain information about product pricing and sales.
8+
9+
### 📊 Prices Table
10+
| Column Name | Type |
11+
| ----------- | ---- |
12+
| product_id | int |
13+
| start_date | date |
14+
| end_date | date |
15+
| price | int |
16+
17+
- `(product_id, start_date, end_date)` is the **primary key**.
18+
- Each row defines the price for `product_id` **within a specific date range**.
19+
- **No two price periods overlap** for the same product.
20+
21+
### 📊 UnitsSold Table
22+
| Column Name | Type |
23+
| ------------- | ---- |
24+
| product_id | int |
25+
| purchase_date | date |
26+
| units | int |
27+
28+
- Each row records the number of units sold for `product_id` on `purchase_date`.
29+
- **Table may contain duplicate rows**.
30+
31+
### 🔢 Goal:
32+
Find the **average selling price** for each `product_id`, rounded to **2 decimal places**.
33+
If a product has **no sales**, its average price should be **0**.
34+
35+
---
36+
37+
## 📊 Example 1:
38+
### Input:
39+
### **Prices Table**
40+
| product_id | start_date | end_date | price |
41+
| ---------- | ---------- | ---------- | ----- |
42+
| 1 | 2019-02-17 | 2019-02-28 | 5 |
43+
| 1 | 2019-03-01 | 2019-03-22 | 20 |
44+
| 2 | 2019-02-01 | 2019-02-20 | 15 |
45+
| 2 | 2019-02-21 | 2019-03-31 | 30 |
46+
47+
### **UnitsSold Table**
48+
| product_id | purchase_date | units |
49+
| ---------- | ------------- | ----- |
50+
| 1 | 2019-02-25 | 100 |
51+
| 1 | 2019-03-01 | 15 |
52+
| 2 | 2019-02-10 | 200 |
53+
| 2 | 2019-03-22 | 30 |
54+
55+
### Output:
56+
| product_id | average_price |
57+
| ---------- | ------------- |
58+
| 1 | 6.96 |
59+
| 2 | 16.96 |
60+
61+
---
62+
63+
## 🔍 Explanation:
64+
### **Formula**
65+
\[
66+
\text{Average Selling Price} = \frac{\sum (\text{price} \times \text{units sold})}{\sum (\text{units sold})}
67+
\]
68+
69+
### **Product 1 Calculation**
70+
- **Feb 25, 2019:** 100 units sold at **$5**
71+
- **Mar 01, 2019:** 15 units sold at **$20**
72+
- **Total Price Contribution:**
73+
\[
74+
(100 \times 5) + (15 \times 20) = 500 + 300 = 800
75+
\]
76+
- **Total Units Sold:**
77+
\[
78+
100 + 15 = 115
79+
\]
80+
- **Average Price:**
81+
\[
82+
800 / 115 = 6.96
83+
\]
84+
85+
### **Product 2 Calculation**
86+
- **Feb 10, 2019:** 200 units sold at **$15**
87+
- **Mar 22, 2019:** 30 units sold at **$30**
88+
- **Total Price Contribution:**
89+
\[
90+
(200 \times 15) + (30 \times 30) = 3000 + 900 = 3900
91+
\]
92+
- **Total Units Sold:**
93+
\[
94+
200 + 30 = 230
95+
\]
96+
- **Average Price:**
97+
\[
98+
3900 / 230 = 16.96
99+
\]
100+
101+
---
102+
103+
## 🖥 SQL Solution
104+
105+
### 1️⃣ Standard MySQL Query
106+
#### **Explanation:**
107+
- **Join `Prices` and `UnitsSold`** on `product_id`, ensuring `purchase_date` falls **within the valid price period** (`start_date` ≤ `purchase_date` ≤ `end_date`).
108+
- **Multiply `price * units`** for total revenue.
109+
- **Sum total units** for each product.
110+
- **Use `ROUND(..., 2)`** to get 2 decimal places.
111+
- **Use `IFNULL(..., 0)`** to handle cases where no units were sold.
112+
113+
```sql
114+
SELECT p.product_id,
115+
IFNULL(ROUND(SUM(p.price * u.units) / SUM(u.units), 2), 0) AS average_price
116+
FROM Prices p
117+
LEFT JOIN UnitsSold u
118+
ON p.product_id = u.product_id
119+
AND u.purchase_date BETWEEN p.start_date AND p.end_date
120+
GROUP BY p.product_id;
121+
```
122+
123+
---
124+
125+
### 📝 Step-by-Step Breakdown:
126+
127+
1️⃣ **Join Tables Based on Matching Date Ranges**
128+
```sql
129+
LEFT JOIN UnitsSold u
130+
ON p.product_id = u.product_id
131+
AND u.purchase_date BETWEEN p.start_date AND p.end_date
132+
```
133+
- Ensures we only match **valid** sales based on pricing periods.
134+
135+
2️⃣ **Calculate Revenue Per Product**
136+
```sql
137+
SUM(p.price * u.units)
138+
```
139+
- Computes total revenue for each product.
140+
141+
3️⃣ **Compute Total Sold Units Per Product**
142+
```sql
143+
SUM(u.units)
144+
```
145+
- Sums up all sold units.
146+
147+
4️⃣ **Calculate Average Price and Handle Edge Cases**
148+
```sql
149+
ROUND(SUM(p.price * u.units) / SUM(u.units), 2)
150+
```
151+
- Ensures precision with 2 decimal places.
152+
153+
5️⃣ **Handle Products with No Sales**
154+
```sql
155+
IFNULL(..., 0)
156+
```
157+
- If `SUM(u.units)` is `NULL`, return `0`.
158+
159+
---
160+
161+
### 2️⃣ Alternative MySQL Query (Using `COALESCE`)
162+
```sql
163+
SELECT p.product_id,
164+
ROUND(SUM(COALESCE(p.price, 0) * COALESCE(u.units, 0)) / SUM(COALESCE(u.units, 0)), 2) AS average_price
165+
FROM Prices p
166+
LEFT JOIN UnitsSold u
167+
ON p.product_id = u.product_id
168+
AND u.purchase_date BETWEEN p.start_date AND p.end_date
169+
GROUP BY p.product_id;
170+
```
171+
- Uses **`COALESCE(value, 0)`** instead of `IFNULL()` for robustness.
172+
173+
---
174+
175+
## 🐍 Pandas Solution (Python)
176+
#### **Explanation:**
177+
- **Merge DataFrames on `product_id`** where `purchase_date` falls in the price range.
178+
- **Compute total price & units**.
179+
- **Handle cases where no units were sold**.
180+
181+
```python
182+
import pandas as pd
183+
184+
def average_selling_price(prices: pd.DataFrame, units_sold: pd.DataFrame) -> pd.DataFrame:
185+
# Merge on product_id where purchase_date is within the valid price period
186+
merged = prices.merge(units_sold, on="product_id")
187+
merged = merged[(merged["purchase_date"] >= merged["start_date"]) &
188+
(merged["purchase_date"] <= merged["end_date"])]
189+
190+
# Calculate total revenue and total units per product
191+
merged["total_price"] = merged["price"] * merged["units"]
192+
result = merged.groupby("product_id").agg(
193+
average_price=("total_price", lambda x: round(x.sum() / merged.loc[x.index, "units"].sum(), 2))
194+
).reset_index()
195+
196+
# Handle products with no sales
197+
result["average_price"] = result["average_price"].fillna(0)
198+
199+
return result
200+
```
201+
202+
---
203+
204+
## 📁 File Structure
205+
```
206+
📂 Average-Selling-Price
207+
│── 📜 README.md
208+
│── 📜 solution.sql
209+
│── 📜 solution_pandas.py
210+
│── 📜 test_cases.sql
211+
```
212+
213+
---
214+
215+
## 🔗 Useful Links
216+
- 📖 [LeetCode Problem](https://leetcode.com/problems/average-selling-price/)
217+
- 📚 [SQL `LEFT JOIN` Documentation](https://www.w3schools.com/sql/sql_join_left.asp)
218+
- 🐍 [Pandas Merge Documentation](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.merge.html)
219+
```
220+
221+
### Features of this `README.md`:
222+
✅ **Clear problem statement with table structure**
223+
✅ **Examples with detailed calculations**
224+
✅ **SQL and Pandas solutions with explanations**
225+
✅ **Alternative SQL query for flexibility**
226+
✅ **File structure for GitHub organization**
227+
✅ **Useful reference links**
228+
229+
Would you like any refinements? 🚀

0 commit comments

Comments
 (0)