Masar Holding HR
Masar Holding (fictional) · 10 tables · 5,684 rows · version 1
Masar Holding is a fictional Saudi group with head-office functions, a logistics operation, sales teams in three cities and a customer service centre. The dataset holds its departments (a hierarchy), locations, jobs and salary bands, every employee who has worked there since 2015 (including leavers and rehires) with their manager, the full salary history, annual performance reviews for 2023–2025, leave requests for 2024–2025 and incentive payments. Use it for headcount and turnover at a date, self-joins and recursive org charts, salary-band compliance, window functions over salary history, and workforce analytics.
The documentation is open to everyone. Querying this dataset in the playground is included with Formula Quest membership; lessons that use it follow their own access.
Relationships
Sample queries
SELECT d.department_name, COUNT(e.employee_id) AS headcount
FROM departments AS d
LEFT JOIN employees AS e
ON e.department_id = d.department_id
AND e.hire_date <= DATE '2025-12-31'
AND (e.termination_date IS NULL OR e.termination_date >= DATE '2025-12-31')
GROUP BY d.department_name
ORDER BY headcount DESC;SELECT DISTINCT ON (s.employee_id)
e.employee_id, e.first_name, e.last_name, s.effective_date, s.base_salary,
s.base_salary + s.housing_allowance + s.transport_allowance AS total_monthly
FROM salary_history AS s
JOIN employees AS e ON e.employee_id = s.employee_id
WHERE e.termination_date IS NULL
ORDER BY s.employee_id, s.effective_date DESC;SELECT m.employee_id, m.first_name || ' ' || m.last_name AS manager, COUNT(r.employee_id) AS direct_reports
FROM employees AS m
JOIN employees AS r ON r.manager_id = m.employee_id AND r.termination_date IS NULL
WHERE m.termination_date IS NULL
GROUP BY m.employee_id, manager
ORDER BY direct_reports DESC;WITH RECURSIVE chart AS (
SELECT employee_id, manager_id, first_name || ' ' || last_name AS name, 1 AS level
FROM employees WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.manager_id, e.first_name || ' ' || e.last_name, c.level + 1
FROM employees e JOIN chart c ON e.manager_id = c.employee_id
WHERE e.termination_date IS NULL
)
SELECT level, COUNT(*) AS people FROM chart GROUP BY level ORDER BY level;SELECT EXTRACT(YEAR FROM termination_date) AS year, termination_reason, COUNT(*) AS leavers
FROM employees
WHERE termination_date IS NOT NULL
GROUP BY 1, 2
ORDER BY 1, 3 DESC;Data dictionary
locations
6 rows · primary key (location_id)Offices and sites where employees are based.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| location_id | integer | no | PK | Unique number for each location. |
| location_name | text | no | unique | Name of the office or site. |
| city | text | yes | City. NULL for the Remote location. | |
| region | text | yes | Region of Saudi Arabia. NULL for the Remote location. | |
| is_head_office | boolean | no | TRUE for the head office. |
departments
16 rows · primary key (department_id)Departments as a hierarchy: each department may belong to a parent department.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| department_id | integer | no | PK | Unique number for each department. |
| department_name | text | no | unique | Department name. |
| parent_department_id | integer | yes | departments.department_id | The department this one belongs to. NULL for the top (Executive Office). |
| cost_center_code | text | no | unique | Finance cost center the department's costs are charged to. |
| established_on | date | no | Date the department was created. |
jobs
37 rows · primary key (job_id)Job titles, their job family and pay grade.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| job_id | integer | no | PK | Unique number for each job. |
| job_title | text | no | unique | Job title. |
| job_family | text | no | Group of related jobs, e.g. Finance, Sales, Operations. | |
| grade | smallint | no | Pay grade, 1 (entry) to 10 (CEO). Links to salary_bands. |
salary_bands
30 rows · primary key (grade, effective_from)Monthly base-salary ranges per grade. Bands are revised from time to time; each version applies from effective_from until the next one.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| grade | smallint | no | PK | Pay grade. |
| effective_from | date | no | PK | Date this version of the band takes effect. |
| min_salary | numeric(12,2) | no | Minimum monthly base salary in SAR (full-time). | |
| mid_salary | numeric(12,2) | no | Mid-point monthly base salary in SAR. | |
| max_salary | numeric(12,2) | no | Maximum monthly base salary in SAR. |
employees
490 rows · primary key (employee_id)Everyone who has worked for Masar Holding since 2015, including leavers. A rehired person has a new row (new employee_id) with the same email.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| employee_id | integer | no | PK | Unique number for each employment record (assigned in order of hiring). |
| first_name | text | no | Given name. | |
| last_name | text | no | Family name. | |
| text | no | Work email. Not unique: a rehired person keeps the same address. | ||
| gender | text | no | 'F' or 'M'. | |
| nationality_group | text | no | 'Saudi' or 'Non-Saudi' (used for Saudization reporting). | |
| date_of_birth | date | no | Date of birth. | |
| hire_date | date | no | First working day. | |
| termination_date | date | yes | Last working day. NULL for current employees. | |
| termination_reason | text | yes | Why the employee left. NULL for current employees. | |
| employment_type | text | no | full_time, part_time (paid pro rata) or contractor (no allowances, reviews or bonuses). | |
| department_id | integer | no | departments.department_id | Current department (the last one, for leavers). Earlier moves are in department_transfers. |
| job_id | integer | no | jobs.job_id | Current job (the last one, for leavers). |
| location_id | integer | no | locations.location_id | Where the employee is based. |
| manager_id | integer | yes | employees.employee_id | Line manager (another employee). NULL only for the CEO. For leavers: the manager when they left. |
salary_history
1,742 rows · primary key (salary_id)Every change to an employee's monthly pay, from hiring onwards. The row with the latest effective_date is the current pay.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| salary_id | integer | no | PK | Unique number for each salary record. |
| employee_id | integer | no | employees.employee_id | Employee. |
| effective_date | date | no | Date the new pay takes effect. | |
| base_salary | numeric(12,2) | no | Monthly base salary in SAR. | |
| housing_allowance | numeric(12,2) | no | Monthly housing allowance in SAR (25% of base; 0 for contractors). | |
| transport_allowance | numeric(12,2) | no | Monthly transport allowance in SAR (10% of base, capped at 3,000; 0 for contractors). | |
| job_id | integer | no | jobs.job_id | Job held from this date (changes on promotion). |
| reason | text | no | Why pay changed: hire, promotion, annual_increase (each April; none in 2020) or adjustment. |
performance_reviews
770 rows · primary key (review_id)Year-end performance reviews (2023-2025) for employees and part-timers employed on 31 December. Contractors are not reviewed.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| review_id | integer | no | PK | Unique number for each review. |
| employee_id | integer | no | employees.employee_id | Employee reviewed. |
| review_year | integer | no | Year the review covers. | |
| rating | smallint | yes | 1 (unsatisfactory) to 5 (outstanding). NULL if the employee joined after 1 October or the review is still pending. | |
| reviewer_id | integer | yes | employees.employee_id | Manager who did the review. NULL for the CEO (reviewed by the board). |
| reviewed_on | date | yes | Date the review was completed. NULL when there is no rating. |
leave_requests
1,592 rows · primary key (leave_id)Leave requests for 2024 and 2025. Only approved requests are leave actually taken.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| leave_id | integer | no | PK | Unique number for each request. |
| employee_id | integer | no | employees.employee_id | Employee requesting leave. |
| leave_type | text | no | annual, sick, unpaid or maternity. | |
| start_date | date | no | First day of leave. | |
| end_date | date | no | Last day of leave. | |
| days | integer | no | Working days of leave (Sunday-Thursday) between start_date and end_date. | |
| status | text | no | approved, rejected or pending (awaiting the manager). | |
| requested_on | date | no | Date the request was submitted (sick leave is filed on the first day). |
incentive_payments
966 rows · primary key (payment_id)Bonuses, sales commissions and spot awards paid to employees (2024-2025 payments, plus 2023 spot awards and commissions).
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| payment_id | integer | no | PK | Unique number for each payment. |
| employee_id | integer | no | employees.employee_id | Employee paid. |
| plan | text | no | annual_bonus (paid in March for the previous year), sales_commission (quarterly, paid the month after the quarter) or spot_award. | |
| performance_year | integer | no | Year the payment rewards (can differ from the year it was paid). | |
| paid_on | date | no | Payment date. | |
| amount | numeric(12,2) | no | Amount paid in SAR. |
department_transfers
35 rows · primary key (transfer_id)Moves of employees between departments. employees.department_id holds the department after the latest move.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| transfer_id | integer | no | PK | Unique number for each transfer. |
| employee_id | integer | no | employees.employee_id | Employee who moved. |
| effective_date | date | no | First day in the new department. | |
| from_department_id | integer | no | departments.department_id | Department before the move. |
| to_department_id | integer | no | departments.department_id | Department after the move. |