Employee Hierarchy Management

L3
ModelContextProtocolPostgresChinook

Reorganize employee structure through CRUD operations including inserts, updates, deletes, and customer reassignments.

Created by Lingxiao Du
2025-08-12
Data MigrationSchema DesignTransactional Operations

Model Ranking

Click on the dots to view the trajectory of each task run
Model
Run Results
Pass@4
Pass^4
Avg Time
Avg Turns
Input Tokens
Output Tokens
Total Tokens
Claude
claude-sonnet-4
4
/4
189.5s
26.5
193,484
4,038
197,522
Claude
claude-sonnet-4-high
4
/4
133.4s
28.0
348,215
3,895
352,109
Claude
claude-sonnet-4-low
4
/4
113.9s
24.8
249,073
3,607
252,680
DeepSeek
deepseek-chat
4
/4
195.5s
20.3
124,806
2,255
127,061
Gemini
gemini-2-5-flash
4
/4
37.7s
16.0
55,164
3,678
58,842
OpenAI
gpt-4-1
4
/4
39.9s
12.5
44,744
1,563
46,307
OpenAI
gpt-4-1-mini
4
/4
50.8s
15.3
71,917
2,041
73,957
OpenAI
gpt-5-low
4
/4
144.8s
4.0
11,905
6,643
18,549
OpenAI
gpt-5-mini-medium
4
/4
51.0s
7.3
36,364
5,040
41,404
OpenAI
gpt-5-nano-medium
4
/4
83.0s
9.8
38,343
15,426
53,769
Grok
grok-4
4
/4
109.6s
19.0
105,694
3,407
109,101
Grok
grok-code-fast-1
4
/4
36.0s
23.8
203,938
2,530
206,468
MoonshotAI
kimi-k2-0711
4
/4
119.6s
28.3
184,148
2,061
186,209
MoonshotAI
kimi-k2-0905
4
/4
183.0s
28.3
220,179
2,069
222,248
OpenAI
o4-mini
4
/4
55.8s
3.0
7,558
4,301
11,859
Qwen
qwen-3-coder-plus
4
/4
71.7s
31.8
381,111
2,503
383,614
Qwen
qwen-3-max
4
/4
50.1s
21.5
147,017
1,282
148,299
Z.ai
glm-4-5
3
/4
81.8s
23.5
145,415
2,459
147,874
OpenAI
gpt-5-mini-low
3
/4
43.2s
6.8
21,834
4,008
25,842
OpenAI
gpt-5-nano-low
3
/4
110.6s
12.8
72,383
21,529
93,912
OpenAI
o3
3
/4
65.4s
8.3
30,576
4,203
34,778
Gemini
gemini-2-5-pro
2
/4
46.9s
6.8
19,932
3,017
22,949
OpenAI
gpt-5-high
2
/4
625.7s
11.5
68,585
23,166
91,751
OpenAI
gpt-5-medium
2
/4
182.6s
8.3
40,073
9,762
49,835
OpenAI
gpt-5-mini-high
2
/4
146.2s
17.8
163,194
16,039
179,232
OpenAI
gpt-5-nano-high
2
/4
180.5s
17.5
134,558
33,875
168,432
Claude
claude-opus-4-1
0
/1
--
322.4s
18.0
110,287
5,976
116,263
OpenAI
gpt-4-1-nano
0
/4
40.0s
16.5
83,329
2,409
85,737
OpenAI
gpt-oss-120b
0
/4
14.7s
6.0
20,424
948
21,372

Task State

Table "Album" { "AlbumId" int4 [pk, not null] "Title" varchar(160) [not null] "ArtistId" int4 [not null] Indexes { ArtistId [type: btree, name: "IFK_AlbumArtistId"] } } Table "Artist" { "ArtistId" int4 [pk, not null] "Name" varchar(120) } Table "Customer" { "CustomerId" int4 [pk, not null] "FirstName" varchar(40) [not null] "LastName" varchar(20) [not null] "Company" varchar(80) "Address" varchar(70) "City" varchar(40) "State" varchar(40) "Country" varchar(40) "PostalCode" varchar(10) "Phone" varchar(24) "Fax" varchar(24) "Email" varchar(60) [not null] "SupportRepId" int4 Indexes { SupportRepId [type: btree, name: "IFK_CustomerSupportRepId"] } } Table "Employee" { "EmployeeId" int4 [pk, not null] "LastName" varchar(20) [not null] "FirstName" varchar(20) [not null] "Title" varchar(30) "ReportsTo" int4 "BirthDate" timestamp "HireDate" timestamp "Address" varchar(70) "City" varchar(40) "State" varchar(40) "Country" varchar(40) "PostalCode" varchar(10) "Phone" varchar(24) "Fax" varchar(24) "Email" varchar(60) Indexes { ReportsTo [type: btree, name: "IFK_EmployeeReportsTo"] } } Table "Genre" { "GenreId" int4 [pk, not null] "Name" varchar(120) } Table "Invoice" { "InvoiceId" int4 [pk, not null] "CustomerId" int4 [not null] "InvoiceDate" timestamp [not null] "BillingAddress" varchar(70) "BillingCity" varchar(40) "BillingState" varchar(40) "BillingCountry" varchar(40) "BillingPostalCode" varchar(10) "Total" numeric(10,2) [not null] Indexes { CustomerId [type: btree, name: "IFK_InvoiceCustomerId"] } } Table "InvoiceLine" { "InvoiceLineId" int4 [pk, not null] "InvoiceId" int4 [not null] "TrackId" int4 [not null] "UnitPrice" numeric(10,2) [not null] "Quantity" int4 [not null] Indexes { InvoiceId [type: btree, name: "IFK_InvoiceLineInvoiceId"] TrackId [type: btree, name: "IFK_InvoiceLineTrackId"] } } Table "MediaType" { "MediaTypeId" int4 [pk, not null] "Name" varchar(120) } Table "Playlist" { "PlaylistId" int4 [pk, not null] "Name" varchar(120) } Table "PlaylistTrack" { "PlaylistId" int4 [not null] "TrackId" int4 [not null] Indexes { (PlaylistId, TrackId) [type: btree, name: "PK_PlaylistTrack"] TrackId [type: btree, name: "IFK_PlaylistTrackTrackId"] } } Table "Track" { "TrackId" int4 [pk, not null] "Name" varchar(200) [not null] "AlbumId" int4 "MediaTypeId" int4 [not null] "GenreId" int4 "Composer" varchar(220) "Milliseconds" int4 [not null] "Bytes" int4 "UnitPrice" numeric(10,2) [not null] Indexes { AlbumId [type: btree, name: "IFK_TrackAlbumId"] GenreId [type: btree, name: "IFK_TrackGenreId"] MediaTypeId [type: btree, name: "IFK_TrackMediaTypeId"] } } Ref "FK_AlbumArtistId":"Artist"."ArtistId" < "Album"."ArtistId" Ref "FK_CustomerSupportRepId":"Employee"."EmployeeId" < "Customer"."SupportRepId" Ref "FK_EmployeeReportsTo":"Employee"."EmployeeId" < "Employee"."ReportsTo" Ref "FK_InvoiceCustomerId":"Customer"."CustomerId" < "Invoice"."CustomerId" Ref "FK_InvoiceLineInvoiceId":"Invoice"."InvoiceId" < "InvoiceLine"."InvoiceId" Ref "FK_InvoiceLineTrackId":"Track"."TrackId" < "InvoiceLine"."TrackId" Ref "FK_PlaylistTrackPlaylistId":"Playlist"."PlaylistId" < "PlaylistTrack"."PlaylistId" Ref "FK_PlaylistTrackTrackId":"Track"."TrackId" < "PlaylistTrack"."TrackId" Ref "FK_TrackAlbumId":"Album"."AlbumId" < "Track"."AlbumId" Ref "FK_TrackGenreId":"Genre"."GenreId" < "Track"."GenreId" Ref "FK_TrackMediaTypeId":"MediaType"."MediaTypeId" < "Track"."MediaTypeId"

Instruction

Manage employee hierarchy and customer assignments through systematic CRUD operations.

Your Mission:

Chinook needs to reorganize their employee structure and reassign customer relationships. Complete a series of precise database modifications to update the employee hierarchy.

Tasks to Complete:

1. INSERT: Add New Employees

Insert exactly 2 new employees into the Employee table:

  • EmployeeId: 9, FirstName: 'Sarah', LastName: 'Johnson', Title: 'Sales Support Agent', ReportsTo: 2, BirthDate: '1985-03-15', HireDate: '2009-01-10', Address: '123 Oak Street', City: 'Calgary', State: 'AB', Country: 'Canada', PostalCode: 'T2P 5G3', Phone: '+1 (403) 555-0123', Fax: '+1 (403) 555-0124', Email: 'sarah.johnson@chinookcorp.com'
  • EmployeeId: 10, FirstName: 'Mike', LastName: 'Chen', Title: 'Sales Support Agent', ReportsTo: 2, BirthDate: '1982-08-22', HireDate: '2009-01-10', Address: '456 Pine Ave', City: 'Calgary', State: 'AB', Country: 'Canada', PostalCode: 'T2P 5G4', Phone: '+1 (403) 555-0125', Fax: '+1 (403) 555-0126', Email: 'mike.chen@chinookcorp.com'

2. UPDATE: Modify Existing Employee Information

  • Change Andrew Adams (EmployeeId = 1) title from 'General Manager' to 'CEO'
  • Update Nancy Edwards (EmployeeId = 2) phone number to '+1 (403) 555-9999'
  • Change all employees with Title = 'IT Staff' to have Title = 'IT Specialist'

3. UPDATE: Reassign Some Customers to New Employees

  • Update customers with CustomerId 1, 2, 3 to have SupportRepId = 9 (Sarah Johnson)
  • Update customers with CustomerId 4, 5, 6 to have SupportRepId = 10 (Mike Chen)

4. UPDATE: Reorganize Reporting Structure

  • Change Sarah Johnson (EmployeeId = 9) to report to Andrew Adams (EmployeeId = 1) instead of Nancy Edwards
  • Change Mike Chen (EmployeeId = 10) to also report to Andrew Adams (EmployeeId = 1)

5. INSERT: Create Employee Performance Table

Create a new table called employee_performance:

  • employee_id (integer, foreign key to Employee)
  • customers_assigned (integer)
  • performance_score (decimal)

Insert records for employees 9 and 10 by calculating their actual customer assignments:

  • Sarah Johnson: calculate actual number of customers assigned to her, performance score 4.5
  • Mike Chen: calculate actual number of customers assigned to him, performance score 4.2

6. DELETE: Remove IT Department Employee

  • Delete Robert King (EmployeeId = 7) from the Employee table
  • Before deletion, handle all relationships:
    • Find who Robert reports to and reassign any employees who report to Robert to report to Robert's manager instead
    • Find all customers assigned to Robert as their support rep and reassign them to Robert's manager

7. UPDATE: Promote Remaining IT Staff

  • Promote Laura Callahan (EmployeeId = 8) from 'IT Specialist' to 'Senior IT Specialist'
  • Update her salary information by adding a new column salary to Employee table (decimal type)
  • Set Laura's salary to 75000.00 and all other employees to 50000.00

8. Final Verification Query

Execute this exact query to verify all changes:

SQL
SELECT 
    COUNT(*) as total_employees,
    COUNT(CASE WHEN "Title" = 'CEO' THEN 1 END) as ceo_count,
    COUNT(CASE WHEN "Title" = 'IT Specialist' THEN 1 END) as it_specialist_count,
    COUNT(CASE WHEN "ReportsTo" = 1 THEN 1 END) as reports_to_ceo
FROM "Employee";

Expected result: total_employees = 9, ceo_count = 1, it_specialist_count = 0, reports_to_ceo = 4

Business Rules:

  • Use exact EmployeeId values as specified
  • Maintain referential integrity between Employee and Customer tables
  • All phone numbers must include country code format
  • Email addresses must follow the pattern firstname.lastname@chinookcorp.com

Expected Outcome:

The database should have exactly 10 employees total, with the new hierarchy structure in place and customer assignments updated accordingly.



Verify

*.py
Python
"""
Verification script for PostgreSQL Task 3: Employee Hierarchy Management
"""

import os
import sys
import psycopg2
from decimal import Decimal

def rows_match(actual_row, expected_row):
    """
    Compare two rows with appropriate tolerance.
    For Decimal types: allows 0.01 tolerance
    For other types: requires exact match
    """
    if len(actual_row) != len(expected_row):
        return False
    
    for actual, expected in zip(actual_row, expected_row):
        if isinstance(actual, Decimal) and isinstance(expected, Decimal):
            if abs(float(actual) - float(expected)) > 0.01:
                return False
        elif actual != expected:
            return False
    
    return True

def get_connection_params() -> dict:
    """Get database connection parameters."""
    return {
        "host": os.getenv("POSTGRES_HOST", "localhost"),
        "port": int(os.getenv("POSTGRES_PORT", 5432)),
        "database": os.getenv("POSTGRES_DATABASE"),
        "user": os.getenv("POSTGRES_USERNAME"),
        "password": os.getenv("POSTGRES_PASSWORD")
    }

def verify_employee_count_and_titles(conn) -> bool:
    """Verify the final employee count and title changes."""
    with conn.cursor() as cur:
        # Check the final verification query results
        cur.execute("""
            SELECT 
                COUNT(*) as total_employees,
                COUNT(CASE WHEN "Title" = 'CEO' THEN 1 END) as ceo_count,
                COUNT(CASE WHEN "Title" = 'IT Specialist' THEN 1 END) as it_specialist_count,
                COUNT(CASE WHEN "ReportsTo" = 1 THEN 1 END) as reports_to_ceo
            FROM "Employee"
        """)
        result = cur.fetchone()
        
        total_employees, ceo_count, it_specialist_count, reports_to_ceo = result
        
        # Expected: total_employees = 9, ceo_count = 1, it_specialist_count = 1, reports_to_ceo = 4
        if total_employees != 9:
            print(f"❌ Expected 9 total employees, got {total_employees}")
            return False
            
        if ceo_count != 1:
            print(f"❌ Expected 1 CEO, got {ceo_count}")
            return False
            
        if it_specialist_count != 0:
            print(f"❌ Expected 0 IT Specialists, got {it_specialist_count}")
            return False
            
        if reports_to_ceo != 4:
            print(f"❌ Expected 4 employees reporting to CEO, got {reports_to_ceo}")
            return False
        
        print("✅ Employee count and title verification passed")
        return True

def verify_specific_employees(conn) -> bool:
    """Verify specific employee records and modifications."""
    with conn.cursor() as cur:
        # Check all employee fields in one query
        cur.execute("""
            SELECT "EmployeeId", "LastName", "FirstName", "Title", "ReportsTo", "BirthDate", 
                   "HireDate", "Address", "City", "State", "Country", "PostalCode", 
                   "Phone", "Fax", "Email"
            FROM "Employee" 
            WHERE "EmployeeId" IN (1, 2, 9, 10)
            ORDER BY "EmployeeId"
        """)
        employees = cur.fetchall()
        
        from datetime import datetime
        
        expected = [
            # Andrew Adams (ID 1) - Title changes to 'CEO', phone stays original, ReportsTo stays None
            (1, 'Adams', 'Andrew', 'CEO', None, datetime(1962, 2, 18), datetime(2002, 8, 14),
             '11120 Jasper Ave NW', 'Edmonton', 'AB', 'Canada', 'T5K 2N1', '+1 (780) 428-9482', '+1 (780) 428-3457', 'andrew@chinookcorp.com'),
            # Nancy Edwards (ID 2) - Phone changes, title stays 'Sales Manager', ReportsTo stays 1
            (2, 'Edwards', 'Nancy', 'Sales Manager', 1, datetime(1958, 12, 8), datetime(2002, 5, 1),
             '825 8 Ave SW', 'Calgary', 'AB', 'Canada', 'T2P 2T3', '+1 (403) 555-9999', '+1 (403) 262-3322', 'nancy@chinookcorp.com'),
            # Sarah Johnson - all new data, final ReportsTo = 1 (changed in step 4)
            (9, 'Johnson', 'Sarah', 'Sales Support Agent', 1, datetime(1985, 3, 15), datetime(2009, 1, 10),
             '123 Oak Street', 'Calgary', 'AB', 'Canada', 'T2P 5G3', '+1 (403) 555-0123', '+1 (403) 555-0124', 'sarah.johnson@chinookcorp.com'),
            # Mike Chen - all new data, final ReportsTo = 1 (changed in step 4)
            (10, 'Chen', 'Mike', 'Sales Support Agent', 1, datetime(1982, 8, 22), datetime(2009, 1, 10),
             '456 Pine Ave', 'Calgary', 'AB', 'Canada', 'T2P 5G4', '+1 (403) 555-0125', '+1 (403) 555-0126', 'mike.chen@chinookcorp.com')
        ]
        
        if len(employees) != 4:
            print(f"❌ Expected 4 key employees, found {len(employees)}")
            return False
            
        # Full field comparison for all employees using rows_match
        for actual, expected_emp in zip(employees, expected):
            if not rows_match(actual, expected_emp):
                print(f"❌ Employee {actual[0]} row mismatch: expected {expected_emp}, got {actual}")
                return False
        
        print("✅ Specific employee verification passed - all fields match exactly")
        return True

def verify_customer_assignments(conn) -> bool:
    """Verify customer support representative assignments."""
    with conn.cursor() as cur:
        # Check customers 1, 2, 3 are assigned to Sarah (ID 9)
        cur.execute("""
            SELECT COUNT(*)
            FROM "Customer" 
            WHERE "CustomerId" IN (1, 2, 3) AND "SupportRepId" = 9
        """)
        sarah_customers = cur.fetchone()[0]
        
        if sarah_customers != 3:
            print(f"❌ Expected 3 customers assigned to Sarah Johnson, got {sarah_customers}")
            return False
        
        # Check customers 4, 5, 6 are assigned to Mike (ID 10)
        cur.execute("""
            SELECT COUNT(*)
            FROM "Customer" 
            WHERE "CustomerId" IN (4, 5, 6) AND "SupportRepId" = 10
        """)
        mike_customers = cur.fetchone()[0]
        
        if mike_customers != 3:
            print(f"❌ Expected 3 customers assigned to Mike Chen, got {mike_customers}")
            return False
        
        print("✅ Customer assignment verification passed")
        return True

def verify_performance_table(conn) -> bool:
    """Verify the employee_performance table exists and has correct data."""
    with conn.cursor() as cur:
        try:
            # Get all performance records
            cur.execute("""
                SELECT employee_id, customers_assigned, performance_score
                FROM employee_performance 
                ORDER BY employee_id
            """)
            actual_results = cur.fetchall()
            
            # Get actual customer counts for verification
            cur.execute("""
                SELECT "SupportRepId", COUNT(*) 
                FROM "Customer" 
                WHERE "SupportRepId" IN (9, 10)
                GROUP BY "SupportRepId"
                ORDER BY "SupportRepId"
            """)
            customer_counts = dict(cur.fetchall())
            
            expected = [
                (9, customer_counts.get(9, 0), Decimal('4.5')),  # Sarah Johnson
                (10, customer_counts.get(10, 0), Decimal('4.2'))  # Mike Chen
            ]
            
            if len(actual_results) != 2:
                print(f"❌ Expected 2 performance records, got {len(actual_results)}")
                return False
            
            for actual, expected_row in zip(actual_results, expected):
                if not rows_match(actual, expected_row):
                    print(f"❌ Performance record mismatch: expected {expected_row}, got {actual}")
                    return False
            
            print("✅ Employee performance table verification passed")
            return True
            
        except psycopg2.Error as e:
            print(f"❌ Employee performance table verification failed: {e}")
            return False

def verify_employee_deletion_and_promotion(conn) -> bool:
    """Verify Robert King deletion and Laura Callahan promotion."""
    with conn.cursor() as cur:
        try:
            # Verify Robert King (ID 7) is deleted
            cur.execute("""
                SELECT COUNT(*) FROM "Employee" WHERE "EmployeeId" = 7
            """)
            if cur.fetchone()[0] != 0:
                print("❌ Robert King (EmployeeId = 7) should be deleted")
                return False
            
            # Verify Laura Callahan (ID 8) promotion
            cur.execute("""
                SELECT "Title" FROM "Employee" WHERE "EmployeeId" = 8
            """)
            laura_title = cur.fetchone()
            if not laura_title or laura_title[0] != 'Senior IT Specialist':
                print(f"❌ Laura Callahan should have title 'Senior IT Specialist', got: {laura_title[0] if laura_title else None}")
                return False
            
            print("✅ Employee deletion and promotion verification passed")
            return True
            
        except psycopg2.Error as e:
            print(f"❌ Employee deletion/promotion verification failed: {e}")
            return False

def verify_salary_column(conn) -> bool:
    """Verify salary column exists and has correct values."""
    with conn.cursor() as cur:
        try:
            # Check if salary column exists and get all salary values
            cur.execute("""
                SELECT "EmployeeId", salary 
                FROM "Employee" 
                ORDER BY "EmployeeId"
            """)
            salary_data = cur.fetchall()
            
            # Verify Laura (ID 8) has 75000.00, others have 50000.00
            for emp_id, salary in salary_data:
                expected_salary = Decimal('75000.00') if emp_id == 8 else Decimal('50000.00')
                if salary != expected_salary:
                    print(f"❌ Employee {emp_id} salary should be {expected_salary}, got {salary}")
                    return False
            
            print("✅ Salary column verification passed")
            return True
            
        except psycopg2.Error as e:
            print(f"❌ Salary column verification failed: {e}")
            return False

def main():
    """Main verification function."""
    print("=" * 50)
    print("Verifying Task 3: Employee Hierarchy Management")
    print("=" * 50)

    # Get connection parameters
    conn_params = get_connection_params()

    if not conn_params["database"]:
        print("❌ No database specified")
        sys.exit(1)

    try:
        # Connect to database
        conn = psycopg2.connect(**conn_params)

        # Run verification checks with short-circuit evaluation
        success = (verify_employee_count_and_titles(conn) and
                  verify_specific_employees(conn) and
                  verify_customer_assignments(conn) and
                  verify_performance_table(conn) and
                  verify_employee_deletion_and_promotion(conn) and
                  verify_salary_column(conn))

        conn.close()

        if success:
            print("\n🎉 Task verification: PASS")
            print("All employee hierarchy management operations completed correctly!")
            sys.exit(0)
        else:
            print("\n❌ Task verification: FAIL")
            sys.exit(1)

    except psycopg2.Error as e:
        print(f"❌ Database error: {e}")
        sys.exit(1)
    except Exception as e:
        print(f"❌ Verification error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()