Skip to content

Commit f4ea973

Browse files
committed
Added task 3657
1 parent 7459e05 commit f4ea973

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
3657\. Find Loyal Customers
2+
3+
Medium
4+
5+
Table: `customer_transactions`
6+
7+
+------------------+---------+
8+
| Column Name | Type |
9+
+------------------+---------+
10+
| transaction_id | int |
11+
| customer_id | int |
12+
| transaction_date | date |
13+
| amount | decimal |
14+
| transaction_type | varchar |
15+
+------------------+---------+
16+
transaction_id is the unique identifier for this table. transaction_type can be either 'purchase' or 'refund'.
17+
18+
Write a solution to find **loyal customers**. A customer is considered **loyal** if they meet ALL the following criteria:
19+
20+
* Made **at least** `3` purchase transactions.
21+
* Have been active for **at least** `30` days.
22+
* Their **refund rate** is less than `20%` .
23+
24+
Return _the result table ordered by_ `customer_id` _in **ascending** order_.
25+
26+
The result format is in the following example.
27+
28+
**Example:**
29+
30+
**Input:**
31+
32+
customer\_transactions table:
33+
34+
+----------------+-------------+------------------+--------+------------------+
35+
| transaction_id | customer_id | transaction_date | amount | transaction_type |
36+
|----------------|-------------|------------------|--------|------------------|
37+
| 1 | 101 | 2024-01-05 | 150.00 | purchase |
38+
| 2 | 101 | 2024-01-15 | 200.00 | purchase |
39+
| 3 | 101 | 2024-02-10 | 180.00 | purchase |
40+
| 4 | 101 | 2024-02-20 | 250.00 | purchase |
41+
| 5 | 102 | 2024-01-10 | 100.00 | purchase |
42+
| 6 | 102 | 2024-01-12 | 120.00 | purchase |
43+
| 7 | 102 | 2024-01-15 | 80.00 | refund |
44+
| 8 | 102 | 2024-01-18 | 90.00 | refund |
45+
| 9 | 102 | 2024-02-15 | 130.00 | purchase |
46+
| 10 | 103 | 2024-01-01 | 500.00 | purchase |
47+
| 11 | 103 | 2024-01-02 | 450.00 | purchase |
48+
| 12 | 103 | 2024-01-03 | 400.00 | purchase |
49+
| 13 | 104 | 2024-01-01 | 200.00 | purchase |
50+
| 14 | 104 | 2024-02-01 | 250.00 | purchase |
51+
| 15 | 104 | 2024-02-15 | 300.00 | purchase |
52+
| 16 | 104 | 2024-03-01 | 350.00 | purchase |
53+
| 17 | 104 | 2024-03-10 | 280.00 | purchase |
54+
| 18 | 104 | 2024-03-15 | 100.00 | refund |
55+
+----------------+-------------+------------------+--------+------------------+
56+
57+
58+
**Output:**
59+
60+
+-------------+
61+
| customer_id |
62+
|-------------|
63+
| 101 |
64+
| 104 |
65+
+-------------+
66+
67+
**Explanation:**
68+
69+
* **Customer 101**:
70+
* Purchase transactions: 4 (IDs: 1, 2, 3, 4)
71+
* Refund transactions: 0
72+
* Refund rate: 0/4 = 0% (less than 20%)
73+
* Active period: Jan 5 to Feb 20 = 46 days (at least 30 days)
74+
* Qualifies as loyal
75+
* **Customer 102**:
76+
* Purchase transactions: 3 (IDs: 5, 6, 9)
77+
* Refund transactions: 2 (IDs: 7, 8)
78+
* Refund rate: 2/5 = 40% (exceeds 20%)
79+
* Not loyal
80+
* **Customer 103**:
81+
* Purchase transactions: 3 (IDs: 10, 11, 12)
82+
* Refund transactions: 0
83+
* Refund rate: 0/3 = 0% (less than 20%)
84+
* Active period: Jan 1 to Jan 3 = 2 days (less than 30 days)
85+
* Not loyal
86+
* **Customer 104**:
87+
* Purchase transactions: 5 (IDs: 13, 14, 15, 16, 17)
88+
* Refund transactions: 1 (ID: 18)
89+
* Refund rate: 1/6 = 16.67% (less than 20%)
90+
* Active period: Jan 1 to Mar 15 = 73 days (at least 30 days)
91+
* Qualifies as loyal
92+
93+
The result table is ordered by customer\_id in ascending order.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Write your MySQL query statement below
2+
# #Medium #Database #2025_08_25_Time_297_ms_(100.00%)_Space_0.0_MB_(100.00%)
3+
SELECT
4+
customer_id
5+
FROM
6+
customer_transactions
7+
GROUP BY
8+
customer_id
9+
HAVING
10+
COUNT(CASE WHEN transaction_type = 'purchase' THEN 1 END) > 2
11+
AND TIMESTAMPDIFF(DAY, MIN(transaction_date), MAX(transaction_date)) > 29
12+
AND (COUNT(CASE WHEN transaction_type = 'refund' THEN 1 END) * 1.0 / COUNT(*)) < 0.2
13+
ORDER BY
14+
customer_id ASC;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package g3601_3700.s3657_find_loyal_customers
2+
3+
import org.hamcrest.CoreMatchers.equalTo
4+
import org.hamcrest.MatcherAssert.assertThat
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 customer_transactions (" +
21+
" transaction_id INT PRIMARY KEY," +
22+
" customer_id INT NOT NULL," +
23+
" transaction_date DATE NOT NULL," +
24+
" amount DECIMAL(10,2) NOT NULL," +
25+
" transaction_type ENUM('purchase', 'refund') NOT NULL" +
26+
");" +
27+
"INSERT INTO customer_transactions" +
28+
"(transaction_id, customer_id, transaction_date, amount, transaction_type)" +
29+
"VALUES" +
30+
"(1, 101, '2024-01-05', 150.00, 'purchase')," +
31+
"(2, 101, '2024-01-15', 200.00, 'purchase')," +
32+
"(3, 101, '2024-02-10', 180.00, 'purchase')," +
33+
"(4, 101, '2024-02-20', 250.00, 'purchase')," +
34+
"(5, 102, '2024-01-10', 100.00, 'purchase')," +
35+
"(6, 102, '2024-01-12', 120.00, 'purchase')," +
36+
"(7, 102, '2024-01-15', 80.00, 'refund')," +
37+
"(8, 102, '2024-01-18', 90.00, 'refund')," +
38+
"(9, 102, '2024-02-15', 130.00, 'purchase')," +
39+
"(10, 103, '2024-01-01', 500.00, 'purchase')," +
40+
"(11, 103, '2024-01-02', 450.00, 'purchase')," +
41+
"(12, 103, '2024-01-03', 400.00, 'purchase')," +
42+
"(13, 104, '2024-01-01', 200.00, 'purchase')," +
43+
"(14, 104, '2024-02-01', 250.00, 'purchase')," +
44+
"(15, 104, '2024-02-15', 300.00, 'purchase')," +
45+
"(16, 104, '2024-03-01', 350.00, 'purchase')," +
46+
"(17, 104, '2024-03-10', 280.00, 'purchase')," +
47+
"(18, 104, '2024-03-15', 100.00, 'refund');"
48+
),
49+
],
50+
)
51+
internal class MysqlTest {
52+
@Test
53+
@Throws(SQLException::class, FileNotFoundException::class)
54+
fun testScript(@EmbeddedDatabase dataSource: DataSource) {
55+
dataSource.connection.use { connection ->
56+
connection.createStatement().use { statement ->
57+
statement.executeQuery(
58+
BufferedReader(
59+
FileReader(
60+
(
61+
"src/main/kotlin/g3601_3700/" +
62+
"s3657_find_loyal_customers/" +
63+
"script.sql"
64+
),
65+
),
66+
)
67+
.lines()
68+
.collect(Collectors.joining("\n"))
69+
.replace("#.*?\\r?\\n".toRegex(), ""),
70+
).use { resultSet ->
71+
assertThat<Boolean>(resultSet.next(), equalTo<Boolean>(true))
72+
assertThat<String>(resultSet.getNString(1), equalTo<String>("101"))
73+
assertThat<Boolean>(resultSet.next(), equalTo<Boolean>(true))
74+
assertThat<String>(resultSet.getNString(1), equalTo<String>("104"))
75+
assertThat<Boolean>(resultSet.next(), equalTo<Boolean>(false))
76+
}
77+
}
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)