CMD Guide
HomeDatabasesSQL Practice Problems

Employee Attendance Record

The problem

Two tables describe a company's attendance. Employees holds one row per person; Attendance holds one row per logged status on a date and may contain duplicates.

EmployeesTypeNote
employee_idintprimary key
employee_namevarchar
AttendanceTypeNote
employee_idintno PK; duplicates allowed
attendance_datedate
statusvarchar'Present' | 'Absent' | 'Late'

For each employee, return employee_id, employee_name, and three counts — days_present, days_absent, days_late — ordered by employee_id. Every employee must appear in the result even if they have no attendance rows at all.

Core idea: pivot rows into columns with conditional aggregation

The status values live down the rows — one row per Present/Absent/Late event. The output needs them across the columns — one count each, side by side. That row-to-column reshape is the whole problem. The tool for it is conditional aggregation: wrap a CASE inside an aggregate so each status is counted into its own column.

SUM(CASE WHEN a.status = 'Present' THEN 1 ELSE 0 END) AS days_present

For one employee's group of rows, the CASE emits 1 on the matching rows and 0 everywhere else; SUM then totals just the matches. Run three of these in parallel and you have all three counts in a single pass over the group. COUNT(CASE WHEN ... THEN 1 END) works identically — COUNT ignores NULL, so you drop the ELSE 0 and let non-matches fall through to NULL.

diagram
diagram

Why LEFT JOIN, not INNER JOIN

The requirement "every employee must appear" is the load-bearing constraint. An INNER JOIN silently drops any employee with zero attendance rows — a new hire, someone on leave — because there is no matching row to join to. A LEFT JOIN from Employees keeps every employee and fills the missing Attendance columns with NULL.

Those NULLs are then harmless to the counts: CASE WHEN a.status = 'Present' is neither true for a NULL status, so it lands in the ELSE 0 branch, and the employee correctly scores 0, 0, 0 instead of vanishing.

The full solution

SELECT e.employee_id,
       e.employee_name,
       SUM(CASE WHEN a.status = 'Present' THEN 1 ELSE 0 END) AS days_present,
       SUM(CASE WHEN a.status = 'Absent'  THEN 1 ELSE 0 END) AS days_absent,
       SUM(CASE WHEN a.status = 'Late'    THEN 1 ELSE 0 END) AS days_late
FROM Employees e
LEFT JOIN Attendance a ON e.employee_id = a.employee_id
GROUP BY e.employee_id, e.employee_name
ORDER BY e.employee_id;

Reading it as a pipeline: LEFT JOIN attaches each employee's attendance rows (or a single all-NULL row if they have none); GROUP BY collapses each employee into one group; the three SUM(CASE ...) expressions count statuses within that group; ORDER BY sorts the final rows. Against the sample data this yields Alice 1, 1, 0, Bob 1, 0, 1, Charlie 2, 0, 0.

Pitfalls

Generalize the pattern

This is the canonical conditional aggregation / row-to-column pivot shape, and it recurs constantly: orders by status (paid / pending / refunded), survey answers by choice, log events by level. The recipe is always the same three moves — (1) LEFT JOIN from the entity table you must fully preserve, (2) GROUP BY the entity, (3) one SUM(CASE WHEN category = X THEN 1 ELSE 0 END) per output column. Once you see "one count per category, side by side, every entity present," reach for this template.

Source

Adapted and expanded from the Knowledge Guide lesson Employee Attendance Record (Databases › SQL Practice Problems), file site/databases/sql-practice-problems/022-employee-attendance-record.html, with corrected coverage of PostgreSQL's primary-key functional-dependency handling in GROUP BY.

🤖 Don't fully get this? Learn it with Claude

Stuck on Employee Attendance Record? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Employee Attendance Record** (Databases) and want to truly understand it. Explain Employee Attendance Record from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Employee Attendance Record** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Employee Attendance Record** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Employee Attendance Record** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes