Skip to main content
Learning data answers two questions: what training exists, and who has done it. Seven models cover both, and the split that decides your reporting is assigned versus achieved - report the first as the second and someone counts as trained when the data only says they were told to be.

The models

Coverage thins toward the top of that list. Where a system does not separate content from courses, content is sparse or absent, and many LMS platforms have no concept of skills at all, so that model comes back empty for those integrations.
Course, content, category, skill and user all carry a status of ACTIVE, PENDING or INACTIVE. Read without filtering and you get retired courses and deactivated learners, which inflates any compliance count built on top.

How they connect

An enrollment points straight at its completion, so finding outstanding training is a null check on a record you already hold, not a join you build. An enrollment with an empty completion is training assigned but not finished, and in a compliance context that gap is the report. Course and content reference each other both ways, so one video used across three courses is one record rather than three. Skills attach to courses and content the same way. A learner is not an employee. LMS user IDs and HRIS employee IDs do not correspond, so join on email_address and keep a bucket for learners with no employee record - contractors, leavers and outside participants routinely have one without the other.

How many per user

A completion references either a course or a content, so finishing one module counts as its own completion. Count completions without checking which field is set and you overstate how many full courses someone finished. Recurring compliance training produces one dated completion per cycle rather than overwriting the last, which is why the two models stay separate: a single record with a status field could only hold the most recent one.