Skip to content

Commit ad07f6a

Browse files
authored
Added task 3705
1 parent 4ab0f78 commit ad07f6a

File tree

3 files changed

+230
-0
lines changed

3 files changed

+230
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
3705\. Find Golden Hour Customers
2+
3+
Medium
4+
5+
Table: `restaurant_orders`
6+
7+
+------------------+----------+
8+
| Column Name | Type |
9+
+------------------+----------+
10+
| order_id | int |
11+
| customer_id | int |
12+
| order_timestamp | datetime |
13+
| order_amount | decimal |
14+
| payment_method | varchar |
15+
| order_rating | int |
16+
+------------------+----------+
17+
order_id is the unique identifier for this table.
18+
payment_method can be cash, card, or app.
19+
order_rating is between 1 and 5, where 5 is the best (NULL if not rated).
20+
order_timestamp contains both date and time information.
21+
22+
Write a solution to find **golden hour customers** - customers who consistently order during peak hours and provide high satisfaction. A customer is a **golden hour customer** if they meet ALL the following criteria:
23+
24+
* Made **at least** `3` orders.
25+
* **At least** `60%` of their orders are during **peak hours **(`11:00`\-`14:00` or `18:00`\-`21:00`).
26+
* Their **average rating** for rated orders is at least `4.0,` round it to `2` decimal places.
27+
* Have rated **at least** `50%` of their orders.
28+
29+
Return _the result table ordered by_ `average_rating` _in **descending** order, then by_ `customer_id` _in **descending** order_.
30+
31+
The result format is in the following example.
32+
33+
**Example:**
34+
35+
**Input:**
36+
37+
restaurant\_orders table:
38+
39+
+----------+-------------+---------------------+--------------+----------------+--------------+
40+
| order_id | customer_id | order_timestamp | order_amount | payment_method | order_rating |
41+
+----------+-------------+---------------------+--------------+----------------+--------------+
42+
| 1 | 101 | 2024-03-01 12:30:00 | 25.50 | card | 5 |
43+
| 2 | 101 | 2024-03-02 19:15:00 | 32.00 | app | 4 |
44+
| 3 | 101 | 2024-03-03 13:45:00 | 28.75 | card | 5 |
45+
| 4 | 101 | 2024-03-04 20:30:00 | 41.00 | app | NULL |
46+
| 5 | 102 | 2024-03-01 11:30:00 | 18.50 | cash | 4 |
47+
| 6 | 102 | 2024-03-02 12:00:00 | 22.00 | card | 3 |
48+
| 7 | 102 | 2024-03-03 15:30:00 | 19.75 | cash | NULL |
49+
| 8 | 103 | 2024-03-01 19:00:00 | 55.00 | app | 5 |
50+
| 9 | 103 | 2024-03-02 20:45:00 | 48.50 | app | 4 |
51+
| 10 | 103 | 2024-03-03 18:30:00 | 62.00 | card | 5 |
52+
| 11 | 104 | 2024-03-01 10:00:00 | 15.00 | cash | 3 |
53+
| 12 | 104 | 2024-03-02 09:30:00 | 18.00 | cash | 2 |
54+
| 13 | 104 | 2024-03-03 16:00:00 | 20.00 | card | 3 |
55+
| 14 | 105 | 2024-03-01 12:15:00 | 30.00 | app | 4 |
56+
| 15 | 105 | 2024-03-02 13:00:00 | 35.50 | app | 5 |
57+
| 16 | 105 | 2024-03-03 11:45:00 | 28.00 | card | 4 |
58+
+----------+-------------+---------------------+--------------+----------------+--------------+
59+
60+
**Output:**
61+
62+
+-------------+--------------+----------------------+----------------+
63+
| customer_id | total_orders | peak_hour_percentage | average_rating |
64+
+-------------+--------------+----------------------+----------------+
65+
| 103 | 3 | 100 | 4.67 |
66+
| 101 | 4 | 75 | 4.67 |
67+
| 105 | 3 | 100 | 4.33 |
68+
+-------------+--------------+----------------------+----------------+
69+
70+
**Explanation:**
71+
72+
* **Customer 101**:
73+
* Total orders: 4 (at least 3)
74+
* Peak hour orders: 3 out of 4 (12:30, 19:15, 13:45, and 20:30 are in peak hours)
75+
* Peak hour percentage: 3/4 = 75% (at least 60%)
76+
* Rated orders: 3 out of 4 (75% rating completion)
77+
* Average rating: (5+4+5)/3 = 4.67 (at least 4.0)
78+
* Result: **Golden hour customer**
79+
* **Customer 102**:
80+
* Total orders: 3 (at least 3)
81+
* Peak hour orders: 2 out of 3 (11:30, 12:00 are in peak hours; 15:30 is not)
82+
* Peak hour percentage: 2/3 = 66.67% (at least 60%)
83+
* Rated orders: 2 out of 3 (66.67% rating completion)
84+
* Average rating: (4+3)/2 = 3.5 (less than 4.0)
85+
* Result: **Not a golden hour customer** (average rating too low)
86+
* **Customer 103**:
87+
* Total orders: 3 (at least 3)
88+
* Peak hour orders: 3 out of 3 (19:00, 20:45, 18:30 all in evening peak)
89+
* Peak hour percentage: 3/3 = 100% (at least 60%)
90+
* Rated orders: 3 out of 3 (100% rating completion)
91+
* Average rating: (5+4+5)/3 = 4.67 (at least 4.0)
92+
* Result: **Golden hour customer**
93+
* **Customer 104**:
94+
* Total orders: 3 (at least 3)
95+
* Peak hour orders: 0 out of 3 (10:00, 09:30, 16:00 all outside peak hours)
96+
* Peak hour percentage: 0/3 = 0% (less than 60%)
97+
* Result: **Not a golden hour customer** (insufficient peak hour orders)
98+
* **Customer 105**:
99+
* Total orders: 3 (at least 3)
100+
* Peak hour orders: 3 out of 3 (12:15, 13:00, 11:45 all in lunch peak)
101+
* Peak hour percentage: 3/3 = 100% (at least 60%)
102+
* Rated orders: 3 out of 3 (100% rating completion)
103+
* Average rating: (4+5+4)/3 = 4.33 (at least 4.0)
104+
* Result: **Golden hour customer**
105+
106+
The results table is ordered by average\_rating DESC, then customer\_id DESC.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Write your MySQL query statement below
2+
# #Medium #Database #2025_10_10_Time_281_ms_(71.26%)_Space_0.0_MB_(100.00%)
3+
SELECT
4+
customer_id,
5+
COUNT(order_id) AS total_orders,
6+
ROUND(
7+
(
8+
SUM(
9+
CASE
10+
WHEN HOUR(order_timestamp) BETWEEN 11 AND 13
11+
OR HOUR(order_timestamp) BETWEEN 18 AND 20
12+
THEN 1 ELSE 0
13+
END
14+
) * 100.0
15+
) / COUNT(order_id)
16+
) AS peak_hour_percentage,
17+
ROUND(AVG(order_rating), 2) AS average_rating
18+
FROM restaurant_orders
19+
GROUP BY customer_id
20+
HAVING
21+
(SUM(CASE WHEN order_rating IS NOT NULL THEN 1 ELSE 0 END) * 1.0 / COUNT(order_id)) >= 0.5
22+
AND COUNT(order_id) >= 3
23+
AND (
24+
(
25+
SUM(
26+
CASE
27+
WHEN HOUR(order_timestamp) BETWEEN 11 AND 13
28+
OR HOUR(order_timestamp) BETWEEN 18 AND 20
29+
THEN 1 ELSE 0
30+
END
31+
) * 100.0
32+
) / COUNT(order_id)
33+
) >= 60
34+
AND AVG(order_rating) >= 4.0
35+
ORDER BY AVG(order_rating) DESC, customer_id DESC;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package g3701_3800.s3705_find_golden_hour_customers
2+
3+
import org.hamcrest.CoreMatchers
4+
import org.hamcrest.MatcherAssert
5+
import org.junit.jupiter.api.Test
6+
import org.zapodot.junit.db.annotations.EmbeddedDatabase
7+
import org.zapodot.junit.db.annotations.EmbeddedDatabaseTest
8+
import org.zapodot.junit.db.common.CompatibilityMode
9+
import java.io.BufferedReader
10+
import java.io.FileNotFoundException
11+
import java.io.FileReader
12+
import java.sql.SQLException
13+
import java.util.stream.Collectors
14+
import javax.sql.DataSource
15+
16+
@EmbeddedDatabaseTest(
17+
compatibilityMode = CompatibilityMode.MySQL,
18+
initialSqls = [
19+
(
20+
"CREATE TABLE restaurant_orders (" +
21+
" order_id INTEGER," +
22+
" customer_id INTEGER NOT NULL," +
23+
" order_timestamp DATETIME NOT NULL," +
24+
" order_amount DECIMAL(10,2) NOT NULL," +
25+
" payment_method VARCHAR(20) NOT NULL," +
26+
" order_rating INTEGER" +
27+
");" +
28+
"INSERT INTO restaurant_orders (order_id, customer_id, " +
29+
"order_timestamp, order_amount, payment_method, order_rating) VALUES" +
30+
"(1, 101, '2024-03-01 12:30:00', 25.50, 'card', 5)," +
31+
"(2, 101, '2024-03-02 19:15:00', 32.00, 'app', 4)," +
32+
"(3, 101, '2024-03-03 13:45:00', 28.75, 'card', 5)," +
33+
"(4, 101, '2024-03-04 20:30:00', 41.00, 'app', NULL)," +
34+
"(5, 102, '2024-03-01 11:30:00', 18.50, 'cash', 4)," +
35+
"(6, 102, '2024-03-02 12:00:00', 22.00, 'card', 3)," +
36+
"(7, 102, '2024-03-03 15:30:00', 19.75, 'cash', NULL)," +
37+
"(8, 103, '2024-03-01 19:00:00', 55.00, 'app', 5)," +
38+
"(9, 103, '2024-03-02 20:45:00', 48.50, 'app', 4)," +
39+
"(10, 103, '2024-03-03 18:30:00', 62.00, 'card', 5)," +
40+
"(11, 104, '2024-03-01 10:00:00', 15.00, 'cash', 3)," +
41+
"(12, 104, '2024-03-02 09:30:00', 18.00, 'cash', 2)," +
42+
"(13, 104, '2024-03-03 16:00:00', 20.00, 'card', 3)," +
43+
"(14, 105, '2024-03-01 12:15:00', 30.00, 'app', 4)," +
44+
"(15, 105, '2024-03-02 13:00:00', 35.50, 'app', 5)," +
45+
"(16, 105, '2024-03-03 11:45:00', 28.00, 'card', 4);"
46+
),
47+
],
48+
)
49+
internal class MysqlTest {
50+
@Test
51+
@Throws(SQLException::class, FileNotFoundException::class)
52+
fun testScript(@EmbeddedDatabase dataSource: DataSource) {
53+
dataSource.connection.use { connection ->
54+
connection.createStatement().use { statement ->
55+
statement.executeQuery(
56+
BufferedReader(
57+
FileReader(
58+
(
59+
"src/main/kotlin/g3701_3800/" +
60+
"s3705_find_golden_hour_customers/" +
61+
"script.sql"
62+
),
63+
),
64+
)
65+
.lines()
66+
.collect(Collectors.joining("\n"))
67+
.replace("#.*?\\r?\\n".toRegex(), ""),
68+
).use { resultSet ->
69+
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
70+
MatcherAssert.assertThat<String>(resultSet.getString(1), CoreMatchers.equalTo<String>("103"))
71+
MatcherAssert.assertThat<String>(resultSet.getString(2), CoreMatchers.equalTo<String>("3"))
72+
MatcherAssert.assertThat<String>(resultSet.getString(3), CoreMatchers.equalTo<String>("100"))
73+
MatcherAssert.assertThat<String>(resultSet.getString(4), CoreMatchers.equalTo<String>("4.67"))
74+
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
75+
MatcherAssert.assertThat<String>(resultSet.getString(1), CoreMatchers.equalTo<String>("101"))
76+
MatcherAssert.assertThat<String>(resultSet.getString(2), CoreMatchers.equalTo<String>("4"))
77+
MatcherAssert.assertThat<String>(resultSet.getString(3), CoreMatchers.equalTo<String>("100"))
78+
MatcherAssert.assertThat<String>(resultSet.getString(4), CoreMatchers.equalTo<String>("4.67"))
79+
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
80+
MatcherAssert.assertThat<String>(resultSet.getString(1), CoreMatchers.equalTo<String>("105"))
81+
MatcherAssert.assertThat<String>(resultSet.getString(2), CoreMatchers.equalTo<String>("3"))
82+
MatcherAssert.assertThat<String>(resultSet.getString(3), CoreMatchers.equalTo<String>("100"))
83+
MatcherAssert.assertThat<String>(resultSet.getString(4), CoreMatchers.equalTo<String>("4.33"))
84+
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(false))
85+
}
86+
}
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)