Skip to content

Commit 2a1e080

Browse files
authored
Added task 3617
1 parent fa16a8f commit 2a1e080

File tree

3 files changed

+344
-0
lines changed
  • src
    • main/kotlin/g3601_3700/s3617_find_students_with_study_spiral_pattern
    • test/kotlin/g3601_3700/s3617_find_students_with_study_spiral_pattern

3 files changed

+344
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
3617\. Find Students with Study Spiral Pattern
2+
3+
Hard
4+
5+
Table: `students`
6+
7+
+--------------+---------+
8+
| Column Name | Type |
9+
+--------------+---------+
10+
| student_id | int |
11+
| student_name | varchar |
12+
| major | varchar |
13+
+--------------+---------+
14+
student_id is the unique identifier for this table.
15+
Each row contains information about a student and their academic major.
16+
17+
Table: `study_sessions`
18+
19+
+---------------+---------+
20+
| Column Name | Type |
21+
+---------------+---------+
22+
| session_id | int |
23+
| student_id | int |
24+
| subject | varchar |
25+
| session_date | date |
26+
| hours_studied | decimal |
27+
+---------------+---------+
28+
session_id is the unique identifier for this table.
29+
Each row represents a study session by a student for a specific subject.
30+
31+
Write a solution to find students who follow the **Study Spiral Pattern** - students who consistently study multiple subjects in a rotating cycle.
32+
33+
* A Study Spiral Pattern means a student studies at least `3` **different subjects** in a repeating sequence
34+
* The pattern must repeat for **at least** `2` **complete cycles** (minimum `6` study sessions)
35+
* Sessions must be **consecutive dates** with no gaps longer than `2` days between sessions
36+
* Calculate the **cycle length** (number of different subjects in the pattern)
37+
* Calculate the **total study hours** across all sessions in the pattern
38+
* Only include students with cycle length of **at least** `3` **subjects**
39+
40+
Return _the result table ordered by cycle length in **descending** order, then by total study hours in **descending** order_.
41+
42+
The result format is in the following example.
43+
44+
**Example:**
45+
46+
**Input:**
47+
48+
students table:
49+
50+
| student_id | student_name | major |
51+
|------------|--------------|-------------------|
52+
| 1 | Alice Chen | Computer Science |
53+
| 2 | Bob Johnson | Mathematics |
54+
| 3 | Carol Davis | Physics |
55+
| 4 | David Wilson | Chemistry |
56+
| 5 | Emma Brown | Biology |
57+
58+
study\_sessions table:
59+
60+
| session_id | student_id | subject | session_date | hours_studied |
61+
|------------|------------|------------|--------------|----------------|
62+
| 1 | 1 | Math | 2023-10-01 | 2.5 |
63+
| 2 | 1 | Physics | 2023-10-02 | 3.0 |
64+
| 3 | 1 | Chemistry | 2023-10-03 | 2.0 |
65+
| 4 | 1 | Math | 2023-10-04 | 2.5 |
66+
| 5 | 1 | Physics | 2023-10-05 | 3.0 |
67+
| 6 | 1 | Chemistry | 2023-10-06 | 2.0 |
68+
| 7 | 2 | Algebra | 2023-10-01 | 4.0 |
69+
| 8 | 2 | Calculus | 2023-10-02 | 3.5 |
70+
| 9 | 2 | Statistics | 2023-10-03 | 2.5 |
71+
| 10 | 2 | Geometry | 2023-10-04 | 3.0 |
72+
| 11 | 2 | Algebra | 2023-10-05 | 4.0 |
73+
| 12 | 2 | Calculus | 2023-10-06 | 3.5 |
74+
| 13 | 2 | Statistics | 2023-10-07 | 2.5 |
75+
| 14 | 2 | Geometry | 2023-10-08 | 3.0 |
76+
| 15 | 3 | Biology | 2023-10-01 | 2.0 |
77+
| 16 | 3 | Chemistry | 2023-10-02 | 2.5 |
78+
| 17 | 3 | Biology | 2023-10-03 | 2.0 |
79+
| 18 | 3 | Chemistry | 2023-10-04 | 2.5 |
80+
| 19 | 4 | Organic | 2023-10-01 | 3.0 |
81+
| 20 | 4 | Physical | 2023-10-05 | 2.5 |
82+
83+
**Output:**
84+
85+
| student_id | student_name | major | cycle_length | total_study_hours |
86+
|------------|--------------|-------------------|--------------|-------------------|
87+
| 2 | Bob Johnson | Mathematics | 4 | 26.0 |
88+
| 1 | Alice Chen | Computer Science | 3 | 15.0 |
89+
90+
**Explanation:**
91+
92+
* **Alice Chen (student\_id = 1):**
93+
* Study sequence: Math → Physics → Chemistry → Math → Physics → Chemistry
94+
* Pattern: 3 subjects (Math, Physics, Chemistry) repeating for 2 complete cycles
95+
* Consecutive dates: Oct 1-6 with no gaps > 2 days
96+
* Cycle length: 3 subjects
97+
* Total hours: 2.5 + 3.0 + 2.0 + 2.5 + 3.0 + 2.0 = 15.0 hours
98+
* **Bob Johnson (student\_id = 2):**
99+
* Study sequence: Algebra → Calculus → Statistics → Geometry → Algebra → Calculus → Statistics → Geometry
100+
* Pattern: 4 subjects (Algebra, Calculus, Statistics, Geometry) repeating for 2 complete cycles
101+
* Consecutive dates: Oct 1-8 with no gaps > 2 days
102+
* Cycle length: 4 subjects
103+
* Total hours: 4.0 + 3.5 + 2.5 + 3.0 + 4.0 + 3.5 + 2.5 + 3.0 = 26.0 hours
104+
* **Students not included:**
105+
* Carol Davis (student\_id = 3): Only 2 subjects (Biology, Chemistry) - doesn't meet minimum 3 subjects requirement
106+
* David Wilson (student\_id = 4): Only 2 study sessions with a 4-day gap - doesn't meet consecutive dates requirement
107+
* Emma Brown (student\_id = 5): No study sessions recorded
108+
109+
The result table is ordered by cycle\_length in descending order, then by total\_study\_hours in descending order.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Write your MySQL query statement below
2+
# #Hard #Database #2025_07_16_Time_553_ms_(100.00%)_Space_0.0_MB_(100.00%)
3+
-- WITH studentstudysummary AS (
4+
-- SELECT
5+
-- student_id,
6+
-- SUM(hours_studied) AS total_study_hours,
7+
-- COUNT(DISTINCT subject) AS cycle_length
8+
-- FROM
9+
-- study_sessions
10+
-- GROUP BY
11+
-- student_id
12+
-- HAVING
13+
-- COUNT(DISTINCT subject) >= 3
14+
-- ),
15+
-- rankedstudysessionswithgaps AS (
16+
-- SELECT
17+
-- ss.student_id,
18+
-- ss.subject,
19+
-- ss.session_date,
20+
-- DATEDIFF(
21+
-- LEAD(ss.session_date, 1, ss.session_date)
22+
-- OVER (PARTITION BY ss.student_id ORDER BY ss.session_date),
23+
-- ss.session_date
24+
-- ) AS gap_to_next_session,
25+
-- ROW_NUMBER() OVER (PARTITION BY ss.student_id ORDER BY ss.session_date) AS rn,
26+
-- sss.total_study_hours,
27+
-- sss.cycle_length
28+
-- FROM
29+
-- study_sessions ss
30+
-- INNER JOIN studentstudysummary sss
31+
-- ON ss.student_id = sss.student_id
32+
-- ),
33+
-- cyclicstudents AS (
34+
-- SELECT
35+
-- rss1.student_id,
36+
-- rss1.cycle_length,
37+
-- rss1.total_study_hours
38+
-- FROM
39+
-- rankedstudysessionswithgaps rss1
40+
-- INNER JOIN rankedstudysessionswithgaps rss2
41+
-- ON rss1.student_id = rss2.student_id
42+
-- AND rss2.rn = rss1.rn + rss1.cycle_length
43+
-- AND rss1.subject = rss2.subject
44+
-- WHERE
45+
-- rss1.gap_to_next_session < 3
46+
-- AND rss2.gap_to_next_session < 3
47+
-- GROUP BY
48+
-- rss1.student_id,
49+
-- rss1.cycle_length,
50+
-- rss1.total_study_hours
51+
-- HAVING
52+
-- COUNT(DISTINCT rss1.subject) >= 3
53+
-- )
54+
-- SELECT
55+
-- s.student_id,
56+
-- s.student_name,
57+
-- s.major,
58+
-- cs.cycle_length,
59+
-- cs.total_study_hours
60+
-- FROM
61+
-- cyclicstudents cs
62+
-- INNER JOIN students s
63+
-- ON cs.student_id = s.student_id
64+
-- ORDER BY
65+
-- cs.cycle_length DESC,
66+
-- cs.total_study_hours DESC;
67+
WITH studentstudysummary AS (
68+
SELECT
69+
student_id,
70+
SUM(hours_studied) AS total_study_hours,
71+
COUNT(DISTINCT subject) AS cycle_length
72+
FROM study_sessions
73+
GROUP BY student_id
74+
HAVING COUNT(DISTINCT subject) >= 3
75+
),
76+
rankedstudysessionswithgaps AS (
77+
SELECT
78+
ss.student_id,
79+
ss.subject,
80+
ss.session_date,
81+
DATEDIFF('DAY',
82+
ss.session_date,
83+
LEAD(ss.session_date, 1, ss.session_date) OVER (
84+
PARTITION BY ss.student_id ORDER BY ss.session_date
85+
)
86+
) AS gap_to_next_session,
87+
ROW_NUMBER() OVER (PARTITION BY ss.student_id ORDER BY ss.session_date) AS rn,
88+
sss.total_study_hours,
89+
sss.cycle_length
90+
FROM study_sessions ss
91+
INNER JOIN studentstudysummary sss
92+
ON ss.student_id = sss.student_id
93+
),
94+
cyclicstudents AS (
95+
SELECT
96+
rss1.student_id,
97+
rss1.cycle_length,
98+
rss1.total_study_hours
99+
FROM rankedstudysessionswithgaps rss1
100+
INNER JOIN rankedstudysessionswithgaps rss2
101+
ON rss1.student_id = rss2.student_id
102+
AND rss2.rn = rss1.rn + rss1.cycle_length
103+
AND rss1.subject = rss2.subject
104+
WHERE
105+
rss1.gap_to_next_session < 3
106+
AND rss2.gap_to_next_session < 3
107+
GROUP BY
108+
rss1.student_id,
109+
rss1.cycle_length,
110+
rss1.total_study_hours
111+
HAVING
112+
COUNT(DISTINCT rss1.subject) >= 3
113+
)
114+
SELECT
115+
s.student_id,
116+
s.student_name,
117+
s.major,
118+
cs.cycle_length,
119+
cs.total_study_hours
120+
FROM cyclicstudents cs
121+
INNER JOIN students s ON cs.student_id = s.student_id
122+
ORDER BY cs.cycle_length DESC, cs.total_study_hours DESC;
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package g3601_3700.s3617_find_students_with_study_spiral_pattern
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 students (" +
21+
" student_id INT PRIMARY KEY," +
22+
" student_name VARCHAR(50)," +
23+
" major VARCHAR(50)" +
24+
");" +
25+
"INSERT INTO students (student_id, student_name, major) VALUES" +
26+
"(1, 'Alice Chen', 'Computer Science')," +
27+
"(2, 'Bob Johnson', 'Mathematics')," +
28+
"(3, 'Carol Davis', 'Physics')," +
29+
"(4, 'David Wilson', 'Chemistry')," +
30+
"(5, 'Emma Brown', 'Biology');" +
31+
"CREATE TABLE study_sessions (" +
32+
" session_id INT PRIMARY KEY," +
33+
" student_id INT," +
34+
" subject VARCHAR(30)," +
35+
" session_date DATE," +
36+
" hours_studied DECIMAL(3,1)" +
37+
");" +
38+
"INSERT INTO study_sessions (session_id, student_id, " +
39+
"subject, session_date, hours_studied) VALUES" +
40+
"(1, 1, 'Math', '2023-10-01', 2.5)," +
41+
"(2, 1, 'Physics', '2023-10-02', 3.0)," +
42+
"(3, 1, 'Chemistry', '2023-10-03', 2.0)," +
43+
"(4, 1, 'Math', '2023-10-04', 2.5)," +
44+
"(5, 1, 'Physics', '2023-10-05', 3.0)," +
45+
"(6, 1, 'Chemistry', '2023-10-06', 2.0)," +
46+
"(7, 2, 'Algebra', '2023-10-01', 4.0)," +
47+
"(8, 2, 'Calculus', '2023-10-02', 3.5)," +
48+
"(9, 2, 'Statistics', '2023-10-03', 2.5)," +
49+
"(10, 2, 'Geometry', '2023-10-04', 3.0)," +
50+
"(11, 2, 'Algebra', '2023-10-05', 4.0)," +
51+
"(12, 2, 'Calculus', '2023-10-06', 3.5)," +
52+
"(13, 2, 'Statistics','2023-10-07', 2.5)," +
53+
"(14, 2, 'Geometry', '2023-10-08', 3.0)," +
54+
"(15, 3, 'Biology', '2023-10-01', 2.0)," +
55+
"(16, 3, 'Chemistry', '2023-10-02', 2.5)," +
56+
"(17, 3, 'Biology', '2023-10-03', 2.0)," +
57+
"(18, 3, 'Chemistry', '2023-10-04', 2.5)," +
58+
"(19, 4, 'Organic', '2023-10-01', 3.0)," +
59+
"(20, 4, 'Physical', '2023-10-05', 2.5);"
60+
),
61+
],
62+
)
63+
internal class MysqlTest {
64+
@Test
65+
@Throws(SQLException::class, FileNotFoundException::class)
66+
fun testScript(@EmbeddedDatabase dataSource: DataSource) {
67+
dataSource.connection.use { connection ->
68+
connection.createStatement().use { statement ->
69+
statement.executeQuery(
70+
BufferedReader(
71+
FileReader(
72+
(
73+
"src/main/kotlin/g3601_3700/" +
74+
"s3617_find_students_with_" +
75+
"study_spiral_pattern/" +
76+
"script.sql"
77+
),
78+
),
79+
)
80+
.lines()
81+
.collect(Collectors.joining("\n"))
82+
.replace("#.*?\\r?\\n".toRegex(), ""),
83+
).use { resultSet ->
84+
assertThat<Boolean>(resultSet.next(), equalTo<Boolean>(true))
85+
assertThat<String>(resultSet.getNString(1), equalTo<String>("2"))
86+
assertThat<String>(
87+
resultSet.getNString(2),
88+
equalTo<String>("Bob Johnson"),
89+
)
90+
assertThat<String>(
91+
resultSet.getNString(3),
92+
equalTo<String>("Mathematics"),
93+
)
94+
assertThat<String>(resultSet.getNString(4), equalTo<String>("4"))
95+
assertThat<String>(resultSet.getNString(5), equalTo<String>("26.0"))
96+
assertThat<Boolean>(resultSet.next(), equalTo<Boolean>(true))
97+
assertThat<String>(resultSet.getNString(1), equalTo<String>("1"))
98+
assertThat<String>(
99+
resultSet.getNString(2),
100+
equalTo<String>("Alice Chen"),
101+
)
102+
assertThat<String>(
103+
resultSet.getNString(3),
104+
equalTo<String>("Computer Science"),
105+
)
106+
assertThat<String>(resultSet.getNString(4), equalTo<String>("3"))
107+
assertThat<String>(resultSet.getNString(5), equalTo<String>("15.0"))
108+
assertThat<Boolean>(resultSet.next(), equalTo<Boolean>(false))
109+
}
110+
}
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)