From 219b33cdaaef20b55e886649995b45bf8f374c18 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Wed, 12 Mar 2025 17:36:01 +0200 Subject: [PATCH 1/2] Added task 3482 --- .../readme.md | 96 +++++++++++++ .../script.sql | 43 ++++++ .../MysqlTest.java | 130 ++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/readme.md create mode 100644 src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/script.sql create mode 100644 src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java diff --git a/src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/readme.md b/src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/readme.md new file mode 100644 index 000000000..a8080ee4e --- /dev/null +++ b/src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/readme.md @@ -0,0 +1,96 @@ +3482\. Analyze Organization Hierarchy + +Hard + +Table: `Employees` + + +----------------+---------+ + | Column Name | Type | + +----------------+---------+ + | employee_id | int | + | employee_name | varchar | + | manager_id | int | + | salary | int | + | department | varchar | + +----------------+---------+ + employee_id is the unique key for this table. + Each row contains information about an employee, including their ID, name, their manager's ID, salary, and department. + manager_id is null for the top-level manager (CEO). + +Write a solution to analyze the organizational hierarchy and answer the following: + +1. **Hierarchy Levels:** For each employee, determine their level in the organization (CEO is level `1`, employees reporting directly to the CEO are level `2`, and so on). +2. **Team Size:** For each employee who is a manager, count the total number of employees under them (direct and indirect reports). +3. **Salary Budget:** For each manager, calculate the total salary budget they control (sum of salaries of all employees under them, including indirect reports, plus their own salary). + +Return _the result table ordered by _the result ordered by **level** in **ascending** order, then by **budget** in **descending** order, and finally by **employee\_name** in **ascending** order_._ + +_The result format is in the following example._ + +**Example:** + +**Input:** + +Employees table: + + +-------------+---------------+------------+--------+-------------+ + | employee_id | employee_name | manager_id | salary | department | + +-------------+---------------+------------+--------+-------------+ + | 1 | Alice | null | 12000 | Executive | + | 2 | Bob | 1 | 10000 | Sales | + | 3 | Charlie | 1 | 10000 | Engineering | + | 4 | David | 2 | 7500 | Sales | + | 5 | Eva | 2 | 7500 | Sales | + | 6 | Frank | 3 | 9000 | Engineering | + | 7 | Grace | 3 | 8500 | Engineering | + | 8 | Hank | 4 | 6000 | Sales | + | 9 | Ivy | 6 | 7000 | Engineering | + | 10 | Judy | 6 | 7000 | Engineering | + +-------------+---------------+------------+--------+-------------+ + +**Output:** + + +-------------+---------------+-------+-----------+--------+ + | employee_id | employee_name | level | team_size | budget | + +-------------+---------------+-------+-----------+--------+ + | 1 | Alice | 1 | 9 | 84500 | + | 3 | Charlie | 2 | 4 | 41500 | + | 2 | Bob | 2 | 3 | 31000 | + | 6 | Frank | 3 | 2 | 23000 | + | 4 | David | 3 | 1 | 13500 | + | 7 | Grace | 3 | 0 | 8500 | + | 5 | Eva | 3 | 0 | 7500 | + | 9 | Ivy | 4 | 0 | 7000 | + | 10 | Judy | 4 | 0 | 7000 | + | 8 | Hank | 4 | 0 | 6000 | + +-------------+---------------+-------+-----------+--------+ + +**Explanation:** + +* **Organization Structure:** + * Alice (ID: 1) is the CEO (level 1) with no manager + * Bob (ID: 2) and Charlie (ID: 3) report directly to Alice (level 2) + * David (ID: 4), Eva (ID: 5) report to Bob, while Frank (ID: 6) and Grace (ID: 7) report to Charlie (level 3) + * Hank (ID: 8) reports to David, and Ivy (ID: 9) and Judy (ID: 10) report to Frank (level 4) +* **Level Calculation:** + * The CEO (Alice) is at level 1 + * Each subsequent level of management adds 1 to the level +* **Team Size Calculation:** + * Alice has 9 employees under her (the entire company except herself) + * Bob has 3 employees (David, Eva, and Hank) + * Charlie has 4 employees (Frank, Grace, Ivy, and Judy) + * David has 1 employee (Hank) + * Frank has 2 employees (Ivy and Judy) + * Eva, Grace, Hank, Ivy, and Judy have no direct reports (team\_size = 0) +* **Budget Calculation:** + * Alice's budget: Her salary (12000) + all employees' salaries (72500) = 84500 + * Charlie's budget: His salary (10000) + Frank's budget (23000) + Grace's salary (8500) = 41500 + * Bob's budget: His salary (10000) + David's budget (13500) + Eva's salary (7500) = 31000 + * Frank's budget: His salary (9000) + Ivy's salary (7000) + Judy's salary (7000) = 23000 + * David's budget: His salary (7500) + Hank's salary (6000) = 13500 + * Employees with no direct reports have budgets equal to their own salary + +**Note:** + +* The result is ordered first by level in ascending order +* Within the same level, employees are ordered by budget in descending order then by name in ascending order \ No newline at end of file diff --git a/src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/script.sql b/src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/script.sql new file mode 100644 index 000000000..5f8cb0e92 --- /dev/null +++ b/src/main/java/g3401_3500/s3482_analyze_organization_hierarchy/script.sql @@ -0,0 +1,43 @@ +# Write your MySQL query statement below +# #Hard #2025_03_11_Time_712_ms_(100.00%)_Space_0.0_MB_(100.00%) +with recursive org_hierarchy(orig_employee_id, orig_employee_name, employee_id, employee_name, manager_id, salary, org_level) as +( + select employee_id as orig_employee_id, + employee_name as orig_employee_name, + employee_id, + employee_name, + manager_id, + salary, + 1 as org_level + from Employees + UNION ALL + select P.orig_employee_id, + P.orig_employee_name, + CH.employee_id, + CH.employee_name, + CH.manager_id, + CH.salary, + P.org_level + 1 + from org_hierarchy P, Employees CH + where ch.manager_id = P.employee_id +), +CEO_hierarchy as ( + select org_hierarchy.employee_id as SUB_employee_id, + org_hierarchy.employee_name, + org_hierarchy.org_level as sub_level + from org_hierarchy, Employees + where org_hierarchy.orig_employee_id = Employees.employee_id + and Employees.manager_id is null +) +select +org_hierarchy.ORIG_EMPLOYEE_ID as employee_id, +org_hierarchy.ORIG_EMPLOYEE_name as employee_name, +CEO_hierarchy.sub_level as "level", +count(*) - 1 as team_size, +sum(org_hierarchy.salary) as budget +from org_hierarchy, CEO_hierarchy +where org_hierarchy.ORIG_EMPLOYEE_ID = CEO_hierarchy.SUB_employee_id +group by org_hierarchy.ORIG_EMPLOYEE_ID, +org_hierarchy.ORIG_EMPLOYEE_name, +CEO_hierarchy.sub_level +order by 3 asc, 5 desc, 2 diff --git a/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java b/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java new file mode 100644 index 000000000..61589f08b --- /dev/null +++ b/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java @@ -0,0 +1,130 @@ +package g3401_3500.s3482_analyze_organization_hierarchy; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.stream.Collectors; +import javax.sql.DataSource; +import org.junit.jupiter.api.Test; +import org.zapodot.junit.db.annotations.EmbeddedDatabase; +import org.zapodot.junit.db.annotations.EmbeddedDatabaseTest; +import org.zapodot.junit.db.common.CompatibilityMode; + +@EmbeddedDatabaseTest( + compatibilityMode = CompatibilityMode.MySQL, + initialSqls = + " CREATE TABLE Employees (" + + " employee_id INT," + + " employee_name VARCHAR(50)," + + " manager_id INT," + + " salary INT," + + " department VARCHAR(100)" + + ");" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(1, 'Alice', NULL, 12000, 'Executive');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(2, 'Bob', 1, 10000, 'Sales');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(3, 'Charlie', 1, 10000, 'Engineering');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(4, 'David', 2, 7500, 'Sales');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(5, 'Eva', 2, 7500, 'Sales');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(6, 'Frank', 3, 9000, 'Engineering');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(7, 'Grace', 3, 8500, 'Engineering');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(8, 'Hank', 4, 6000, 'Sales');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(9, 'Ivy', 6, 7000, 'Engineering');" + + "insert into Employees (employee_id, employee_name, manager_id, salary, department) values " + + "(10, 'Judy', 6, 7000, 'Engineering');") +class MysqlTest { + @Test + void testScript(@EmbeddedDatabase DataSource dataSource) + throws SQLException, FileNotFoundException { + try (final Connection connection = dataSource.getConnection()) { + try (final Statement statement = connection.createStatement(); + final ResultSet resultSet = + statement.executeQuery( + new BufferedReader( + new FileReader( + "src/main/java/g3401_3500/" + + "s3482_analyze_organization_hierarchy/" + + "script.sql")) + .lines() + .collect(Collectors.joining("\n")) + .replaceAll("#.*?\\r?\\n", ""))) { + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("1")); + assertThat(resultSet.getNString(2), equalTo("Alice")); + assertThat(resultSet.getNString(3), equalTo("1")); + assertThat(resultSet.getNString(4), equalTo("9")); + assertThat(resultSet.getNString(5), equalTo("84500")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("3")); + assertThat(resultSet.getNString(2), equalTo("Charlie")); + assertThat(resultSet.getNString(3), equalTo("2")); + assertThat(resultSet.getNString(4), equalTo("4")); + assertThat(resultSet.getNString(5), equalTo("41500")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("2")); + assertThat(resultSet.getNString(2), equalTo("Bob")); + assertThat(resultSet.getNString(3), equalTo("2")); + assertThat(resultSet.getNString(4), equalTo("3")); + assertThat(resultSet.getNString(5), equalTo("31000")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("6")); + assertThat(resultSet.getNString(2), equalTo("Frank")); + assertThat(resultSet.getNString(3), equalTo("3")); + assertThat(resultSet.getNString(4), equalTo("2")); + assertThat(resultSet.getNString(5), equalTo("23000")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("4")); + assertThat(resultSet.getNString(2), equalTo("David")); + assertThat(resultSet.getNString(3), equalTo("3")); + assertThat(resultSet.getNString(4), equalTo("1")); + assertThat(resultSet.getNString(5), equalTo("13500")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("7")); + assertThat(resultSet.getNString(2), equalTo("Grace")); + assertThat(resultSet.getNString(3), equalTo("3")); + assertThat(resultSet.getNString(4), equalTo("0")); + assertThat(resultSet.getNString(5), equalTo("8500")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("5")); + assertThat(resultSet.getNString(2), equalTo("Eva")); + assertThat(resultSet.getNString(3), equalTo("3")); + assertThat(resultSet.getNString(4), equalTo("0")); + assertThat(resultSet.getNString(5), equalTo("7500")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("9")); + assertThat(resultSet.getNString(2), equalTo("Ivy")); + assertThat(resultSet.getNString(3), equalTo("4")); + assertThat(resultSet.getNString(4), equalTo("0")); + assertThat(resultSet.getNString(5), equalTo("7000")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("10")); + assertThat(resultSet.getNString(2), equalTo("Judy")); + assertThat(resultSet.getNString(3), equalTo("4")); + assertThat(resultSet.getNString(4), equalTo("0")); + assertThat(resultSet.getNString(5), equalTo("7000")); + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo("8")); + assertThat(resultSet.getNString(2), equalTo("Hank")); + assertThat(resultSet.getNString(3), equalTo("4")); + assertThat(resultSet.getNString(4), equalTo("0")); + assertThat(resultSet.getNString(5), equalTo("6000")); + assertThat(resultSet.next(), equalTo(false)); + } + } + } +} From b36ae2890593755c801b8c4dfe9caaaf4e97e056 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Wed, 12 Mar 2025 17:45:50 +0200 Subject: [PATCH 2/2] Improved test --- .../MysqlTest.java | 79 +++++-------------- 1 file changed, 19 insertions(+), 60 deletions(-) diff --git a/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java b/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java index 61589f08b..f462d35d3 100644 --- a/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java +++ b/src/test/java/g3401_3500/s3482_analyze_organization_hierarchy/MysqlTest.java @@ -63,68 +63,27 @@ void testScript(@EmbeddedDatabase DataSource dataSource) .lines() .collect(Collectors.joining("\n")) .replaceAll("#.*?\\r?\\n", ""))) { - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("1")); - assertThat(resultSet.getNString(2), equalTo("Alice")); - assertThat(resultSet.getNString(3), equalTo("1")); - assertThat(resultSet.getNString(4), equalTo("9")); - assertThat(resultSet.getNString(5), equalTo("84500")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("3")); - assertThat(resultSet.getNString(2), equalTo("Charlie")); - assertThat(resultSet.getNString(3), equalTo("2")); - assertThat(resultSet.getNString(4), equalTo("4")); - assertThat(resultSet.getNString(5), equalTo("41500")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("2")); - assertThat(resultSet.getNString(2), equalTo("Bob")); - assertThat(resultSet.getNString(3), equalTo("2")); - assertThat(resultSet.getNString(4), equalTo("3")); - assertThat(resultSet.getNString(5), equalTo("31000")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("6")); - assertThat(resultSet.getNString(2), equalTo("Frank")); - assertThat(resultSet.getNString(3), equalTo("3")); - assertThat(resultSet.getNString(4), equalTo("2")); - assertThat(resultSet.getNString(5), equalTo("23000")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("4")); - assertThat(resultSet.getNString(2), equalTo("David")); - assertThat(resultSet.getNString(3), equalTo("3")); - assertThat(resultSet.getNString(4), equalTo("1")); - assertThat(resultSet.getNString(5), equalTo("13500")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("7")); - assertThat(resultSet.getNString(2), equalTo("Grace")); - assertThat(resultSet.getNString(3), equalTo("3")); - assertThat(resultSet.getNString(4), equalTo("0")); - assertThat(resultSet.getNString(5), equalTo("8500")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("5")); - assertThat(resultSet.getNString(2), equalTo("Eva")); - assertThat(resultSet.getNString(3), equalTo("3")); - assertThat(resultSet.getNString(4), equalTo("0")); - assertThat(resultSet.getNString(5), equalTo("7500")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("9")); - assertThat(resultSet.getNString(2), equalTo("Ivy")); - assertThat(resultSet.getNString(3), equalTo("4")); - assertThat(resultSet.getNString(4), equalTo("0")); - assertThat(resultSet.getNString(5), equalTo("7000")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("10")); - assertThat(resultSet.getNString(2), equalTo("Judy")); - assertThat(resultSet.getNString(3), equalTo("4")); - assertThat(resultSet.getNString(4), equalTo("0")); - assertThat(resultSet.getNString(5), equalTo("7000")); - assertThat(resultSet.next(), equalTo(true)); - assertThat(resultSet.getNString(1), equalTo("8")); - assertThat(resultSet.getNString(2), equalTo("Hank")); - assertThat(resultSet.getNString(3), equalTo("4")); - assertThat(resultSet.getNString(4), equalTo("0")); - assertThat(resultSet.getNString(5), equalTo("6000")); + checkRow(resultSet, new String[] {"1", "Alice", "1", "9", "84500"}); + checkRow(resultSet, new String[] {"3", "Charlie", "2", "4", "41500"}); + checkRow(resultSet, new String[] {"2", "Bob", "2", "3", "31000"}); + checkRow(resultSet, new String[] {"6", "Frank", "3", "2", "23000"}); + checkRow(resultSet, new String[] {"4", "David", "3", "1", "13500"}); + checkRow(resultSet, new String[] {"7", "Grace", "3", "0", "8500"}); + checkRow(resultSet, new String[] {"5", "Eva", "3", "0", "7500"}); + checkRow(resultSet, new String[] {"9", "Ivy", "4", "0", "7000"}); + checkRow(resultSet, new String[] {"10", "Judy", "4", "0", "7000"}); + checkRow(resultSet, new String[] {"8", "Hank", "4", "0", "6000"}); assertThat(resultSet.next(), equalTo(false)); } } } + + private static void checkRow(ResultSet resultSet, String[] values) throws SQLException { + assertThat(resultSet.next(), equalTo(true)); + assertThat(resultSet.getNString(1), equalTo(values[0])); + assertThat(resultSet.getNString(2), equalTo(values[1])); + assertThat(resultSet.getNString(3), equalTo(values[2])); + assertThat(resultSet.getNString(4), equalTo(values[3])); + assertThat(resultSet.getNString(5), equalTo(values[4])); + } }