Skip to content

Commit 7e5c5c4

Browse files
committed
Added task 3673
1 parent 994791a commit 7e5c5c4

File tree

3 files changed

+214
-0
lines changed

3 files changed

+214
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
3673\. Find Zombie Sessions
2+
3+
Hard
4+
5+
Table: `app_events`
6+
7+
+------------------+----------+
8+
| Column Name | Type |
9+
+------------------+----------+
10+
| event_id | int |
11+
| user_id | int |
12+
| event_timestamp | datetime |
13+
| event_type | varchar |
14+
| session_id | varchar |
15+
| event_value | int |
16+
+------------------+----------+
17+
event_id is the unique identifier for this table.
18+
event_type can be app_open, click, scroll, purchase, or app_close.
19+
session_id groups events within the same user session.
20+
event_value represents: for purchase - amount in dollars, for scroll - pixels scrolled, for others - NULL.
21+
22+
Write a solution to identify **zombie sessions, **sessions where users appear active but show abnormal behavior patterns. A session is considered a **zombie session** if it meets ALL the following criteria:
23+
24+
* The session duration is **more than** `30` minutes.
25+
* Has **at least** `5` scroll events.
26+
* The **click-to-scroll ratio** is less than `0.20` .
27+
* **No purchases** were made during the session.
28+
29+
Return _the result table ordered by_ `scroll_count` _in **descending** order, then by_ `session_id` _in **ascending** order_.
30+
31+
The result format is in the following example.
32+
33+
**Example:**
34+
35+
**Input:**
36+
37+
app\_events table:
38+
39+
+----------+---------+---------------------+------------+------------+-------------+
40+
| event_id | user_id | event_timestamp | event_type | session_id | event_value |
41+
+----------+---------+---------------------+------------+------------+-------------+
42+
| 1 | 201 | 2024-03-01 10:00:00 | app_open | S001 | NULL |
43+
| 2 | 201 | 2024-03-01 10:05:00 | scroll | S001 | 500 |
44+
| 3 | 201 | 2024-03-01 10:10:00 | scroll | S001 | 750 |
45+
| 4 | 201 | 2024-03-01 10:15:00 | scroll | S001 | 600 |
46+
| 5 | 201 | 2024-03-01 10:20:00 | scroll | S001 | 800 |
47+
| 6 | 201 | 2024-03-01 10:25:00 | scroll | S001 | 550 |
48+
| 7 | 201 | 2024-03-01 10:30:00 | scroll | S001 | 900 |
49+
| 8 | 201 | 2024-03-01 10:35:00 | app_close | S001 | NULL |
50+
| 9 | 202 | 2024-03-01 11:00:00 | app_open | S002 | NULL |
51+
| 10 | 202 | 2024-03-01 11:02:00 | click | S002 | NULL |
52+
| 11 | 202 | 2024-03-01 11:05:00 | scroll | S002 | 400 |
53+
| 12 | 202 | 2024-03-01 11:08:00 | click | S002 | NULL |
54+
| 13 | 202 | 2024-03-01 11:10:00 | scroll | S002 | 350 |
55+
| 14 | 202 | 2024-03-01 11:15:00 | purchase | S002 | 50 |
56+
| 15 | 202 | 2024-03-01 11:20:00 | app_close | S002 | NULL |
57+
| 16 | 203 | 2024-03-01 12:00:00 | app_open | S003 | NULL |
58+
| 17 | 203 | 2024-03-01 12:10:00 | scroll | S003 | 1000 |
59+
| 18 | 203 | 2024-03-01 12:20:00 | scroll | S003 | 1200 |
60+
| 19 | 203 | 2024-03-01 12:25:00 | click | S003 | NULL |
61+
| 20 | 203 | 2024-03-01 12:30:00 | scroll | S003 | 800 |
62+
| 21 | 203 | 2024-03-01 12:40:00 | scroll | S003 | 900 |
63+
| 22 | 203 | 2024-03-01 12:50:00 | scroll | S003 | 1100 |
64+
| 23 | 203 | 2024-03-01 13:00:00 | app_close | S003 | NULL |
65+
| 24 | 204 | 2024-03-01 14:00:00 | app_open | S004 | NULL |
66+
| 25 | 204 | 2024-03-01 14:05:00 | scroll | S004 | 600 |
67+
| 26 | 204 | 2024-03-01 14:08:00 | scroll | S004 | 700 |
68+
| 27 | 204 | 2024-03-01 14:10:00 | click | S004 | NULL |
69+
| 28 | 204 | 2024-03-01 14:12:00 | app_close | S004 | NULL |
70+
+----------+---------+---------------------+------------+------------+-------------+
71+
72+
**Output:**
73+
74+
+------------+---------+--------------------------+--------------+
75+
| session_id | user_id | session_duration_minutes | scroll_count |
76+
+------------+---------+--------------------------+--------------+
77+
| S001 | 201 | 35 | 6 |
78+
+------------+---------+--------------------------+--------------+
79+
80+
**Explanation:**
81+
82+
* **Session S001 (User 201)**:
83+
* Duration: 10:00:00 to 10:35:00 = 35 minutes (more than 30)
84+
* Scroll events: 6 (at least 5)
85+
* Click events: 0
86+
* Click-to-scroll ratio: 0/6 = 0.00 (less than 0.20)
87+
* Purchases: 0 (no purchases)
88+
* S001 is a zombie session (meets all criteria)
89+
* **Session S002 (User 202)**:
90+
* Duration: 11:00:00 to 11:20:00 = 20 minutes (less than 30)
91+
* Has a purchase event
92+
* S002 is not a zombie session
93+
* **Session S003 (User 203)**:
94+
* Duration: 12:00:00 to 13:00:00 = 60 minutes (more than 30)
95+
* Scroll events: 5 (at least 5)
96+
* Click events: 1
97+
* Click-to-scroll ratio: 1/5 = 0.20 (not less than 0.20)
98+
* Purchases: 0 (no purchases)
99+
* S003 is not a zombie session (click-to-scroll ratio equals 0.20, needs to be less)
100+
* **Session S004 (User 204)**:
101+
* Duration: 14:00:00 to 14:12:00 = 12 minutes (less than 30)
102+
* Scroll events: 2 (less than 5)
103+
* S004 is not a zombie session
104+
105+
The result table is ordered by scroll\_count in descending order, then by session\_id in ascending order.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Write your MySQL query statement below
2+
# #Hard #Database #2025_09_07_Time_278_ms_(100.00%)_Space_0.0_MB_(100.00%)
3+
SELECT
4+
session_id,
5+
user_id,
6+
TIMESTAMPDIFF(MINUTE, MIN(event_timestamp), MAX(event_timestamp)) AS session_duration_minutes,
7+
SUM(CASE WHEN event_type = 'scroll' THEN 1 ELSE 0 END) AS scroll_count
8+
FROM
9+
app_events
10+
GROUP BY
11+
session_id,
12+
user_id
13+
HAVING
14+
TIMESTAMPDIFF(MINUTE, MIN(event_timestamp), MAX(event_timestamp)) > 30
15+
AND SUM(CASE WHEN event_type = 'scroll' THEN 1 ELSE 0 END) > 4
16+
AND (
17+
CAST(SUM(CASE WHEN event_type = 'click' THEN 1 ELSE 0 END) AS DOUBLE) /
18+
NULLIF(SUM(CASE WHEN event_type = 'scroll' THEN 1 ELSE 0 END), 0)
19+
) < 0.2
20+
AND SUM(CASE WHEN event_type = 'purchase' THEN 1 ELSE 0 END) = 0
21+
ORDER BY
22+
scroll_count DESC,
23+
session_id ASC;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package g3601_3700.s3673_find_zombie_sessions;
2+
3+
import static org.hamcrest.CoreMatchers.equalTo;
4+
import static org.hamcrest.MatcherAssert.assertThat;
5+
6+
import java.io.BufferedReader;
7+
import java.io.FileNotFoundException;
8+
import java.io.FileReader;
9+
import java.sql.Connection;
10+
import java.sql.ResultSet;
11+
import java.sql.SQLException;
12+
import java.sql.Statement;
13+
import java.util.stream.Collectors;
14+
import javax.sql.DataSource;
15+
import org.junit.jupiter.api.Test;
16+
import org.zapodot.junit.db.annotations.EmbeddedDatabase;
17+
import org.zapodot.junit.db.annotations.EmbeddedDatabaseTest;
18+
import org.zapodot.junit.db.common.CompatibilityMode;
19+
20+
@EmbeddedDatabaseTest(
21+
compatibilityMode = CompatibilityMode.MySQL,
22+
initialSqls =
23+
"CREATE TABLE app_events ("
24+
+ " event_id INT PRIMARY KEY,"
25+
+ " user_id INT NOT NULL,"
26+
+ " event_timestamp TIMESTAMP NOT NULL,"
27+
+ " event_type VARCHAR(50) NOT NULL,"
28+
+ " session_id VARCHAR(50) NOT NULL,"
29+
+ " event_value INT"
30+
+ ");"
31+
+ "INSERT INTO app_events (event_id, user_id, event_timestamp, "
32+
+ "event_type, session_id, event_value) VALUES"
33+
+ "(1, 201, '2024-03-01 10:00:00', 'app_open', 'S001', NULL),"
34+
+ "(2, 201, '2024-03-01 10:05:00', 'scroll', 'S001', 500),"
35+
+ "(3, 201, '2024-03-01 10:10:00', 'scroll', 'S001', 750),"
36+
+ "(4, 201, '2024-03-01 10:15:00', 'scroll', 'S001', 600),"
37+
+ "(5, 201, '2024-03-01 10:20:00', 'scroll', 'S001', 800),"
38+
+ "(6, 201, '2024-03-01 10:25:00', 'scroll', 'S001', 550),"
39+
+ "(7, 201, '2024-03-01 10:30:00', 'scroll', 'S001', 900),"
40+
+ "(8, 201, '2024-03-01 10:35:00', 'app_close', 'S001', NULL),"
41+
+ "(9, 202, '2024-03-01 11:00:00', 'app_open', 'S002', NULL),"
42+
+ "(10, 202, '2024-03-01 11:02:00', 'click', 'S002', NULL),"
43+
+ "(11, 202, '2024-03-01 11:05:00', 'scroll', 'S002', 400),"
44+
+ "(12, 202, '2024-03-01 11:08:00', 'click', 'S002', NULL),"
45+
+ "(13, 202, '2024-03-01 11:10:00', 'scroll', 'S002', 350),"
46+
+ "(14, 202, '2024-03-01 11:15:00', 'purchase', 'S002', 50),"
47+
+ "(15, 202, '2024-03-01 11:20:00', 'app_close','S002', NULL),"
48+
+ "(16, 203, '2024-03-01 12:00:00', 'app_open', 'S003', NULL),"
49+
+ "(17, 203, '2024-03-01 12:10:00', 'scroll', 'S003', 1000),"
50+
+ "(18, 203, '2024-03-01 12:20:00', 'scroll', 'S003', 1200),"
51+
+ "(19, 203, '2024-03-01 12:25:00', 'click', 'S003', NULL),"
52+
+ "(20, 203, '2024-03-01 12:30:00', 'scroll', 'S003', 800),"
53+
+ "(21, 203, '2024-03-01 12:40:00', 'scroll', 'S003', 900),"
54+
+ "(22, 203, '2024-03-01 12:50:00', 'scroll', 'S003', 1100),"
55+
+ "(23, 203, '2024-03-01 13:00:00', 'app_close','S003', NULL),"
56+
+ "(24, 204, '2024-03-01 14:00:00', 'app_open', 'S004', NULL),"
57+
+ "(25, 204, '2024-03-01 14:05:00', 'scroll', 'S004', 600),"
58+
+ "(26, 204, '2024-03-01 14:08:00', 'scroll', 'S004', 700),"
59+
+ "(27, 204, '2024-03-01 14:10:00', 'click', 'S004', NULL),"
60+
+ "(28, 204, '2024-03-01 14:12:00', 'app_close','S004', NULL);")
61+
class MysqlTest {
62+
@Test
63+
void testScript(@EmbeddedDatabase DataSource dataSource)
64+
throws SQLException, FileNotFoundException {
65+
try (final Connection connection = dataSource.getConnection()) {
66+
try (final Statement statement = connection.createStatement();
67+
final ResultSet resultSet =
68+
statement.executeQuery(
69+
new BufferedReader(
70+
new FileReader(
71+
"src/main/java/g3601_3700/"
72+
+ "s3673_find_zombie_sessions/"
73+
+ "script.sql"))
74+
.lines()
75+
.collect(Collectors.joining("\n"))
76+
.replaceAll("#.*?\\r?\\n", ""))) {
77+
assertThat(resultSet.next(), equalTo(true));
78+
assertThat(resultSet.getNString(1), equalTo("S001"));
79+
assertThat(resultSet.getNString(2), equalTo("201"));
80+
assertThat(resultSet.getNString(3), equalTo("35"));
81+
assertThat(resultSet.getNString(4), equalTo("6"));
82+
assertThat(resultSet.next(), equalTo(false));
83+
}
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)