Effective dating is one of the most important parts of reliable Oracle Fusion HCM SQL. A worker, assignment, job, grade, position, department, location, or person name can have multiple physical rows that represent the same logical object at different points in time.
The basic effective_start_date / effective_end_date filter is necessary, but it is not the whole story. Some objects support future-dated changes, some support multiple changes on the same day, and some can be corrected in place without creating a new history row. If those distinctions are ignored, a query can return duplicate assignments, inflate headcount, show the wrong job, or reconstruct history incorrectly.
Scope: The examples below focus on Oracle Fusion HCM date-effective objects. They address temporal correctness, not data security. BI Publisher physical SQL against base tables doesn't automatically reproduce HCM data security; use Oracle secured reporting objects where user-specific security is required.
Date-Effective vs Date-Enabled Objects
Oracle distinguishes date-effective objects from objects that are merely date-enabled. A date-effective logical object is made of one or more physical rows, each with its own effective start and end dates. Past and future versions can coexist. A date-enabled object may have start/end dates, but changing an attribute can overwrite the existing value instead of preserving a full temporal history.
| Concept | Meaning |
|---|---|
| Logical record | The business object as users think of it, such as one assignment or one job. |
| Physical record | One dated version of that logical object. |
| Update | Creates a new physical version from an effective date and adjusts the previous row's end date. |
| Correction | Changes the existing physical row. A correction doesn't create a separate history version for that correction. |
| Future-dated change | A physical row that already exists but doesn't become current until its effective start date. |
That last distinction matters when interpreting audit history. A new value in a date-effective object isn't always proof that a new row was created: Oracle supports both update and correction behavior.
What _F and _M Tell You — and What They Don't
Names ending in _F or _M are a strong clue that an HCM object is date-effective, but don't treat a suffix as a complete data-model specification. Verify the actual primary key and columns in Oracle metadata before deciding how to filter it.
Typical _F object
Usually one physical version per effective date range, with a key such as object ID + effective start/end dates. Examples include PER_JOBS_F and HR_ALL_ORGANIZATION_UNITS_F.
Multiple-changes-per-day object
PER_ALL_ASSIGNMENTS_M is date-tracked and supports multiple changes on the same day. Its key includes EFFECTIVE_LATEST_CHANGE and EFFECTIVE_SEQUENCE.
Common HCM date-effective objects
| Object | Use | Important temporal note |
|---|---|---|
PER_ALL_PEOPLE_F | Person record | Date-effective person row; PER_PERSONS is the non-date-tracked parent. |
PER_PERSON_NAMES_F | Person names | Filter both date range and the required NAME_TYPE. |
PER_ALL_ASSIGNMENTS_M | Assignments / terms | Supports multiple changes per day; handle EFFECTIVE_LATEST_CHANGE and EFFECTIVE_SEQUENCE. |
PER_JOBS_F / PER_JOBS_F_VL | Jobs | PER_JOBS_F stores the base attributes; _VL exposes the session-language job name. |
PER_GRADES_F | Grades | Date-effective reference object; status can matter in addition to dates. |
HR_ALL_POSITIONS_F | Positions | Current Fusion position base table; avoid the incorrect PER_POSITIONS_F shorthand. |
HR_ALL_ORGANIZATION_UNITS_F | Organizations | Date-effective organization definition. |
HR_LOCATIONS_ALL_F | Location view | Date-effective location details exposed through a view over the Fusion location model. |
The 31-DEC-4712 Sentinel Date
Oracle HCM commonly uses DATE '4712-12-31' as an “end of time” value. It means the physical row is open-ended: there is no later effective end date currently defined for that row.
Important: EFFECTIVE_END_DATE = DATE '4712-12-31' does not mean “active today.” A future-dated physical row can also be the last open-ended row. To retrieve the row effective today, use today's as-of date against the effective range.
-- Open-ended last physical row, not necessarily today's row
WHERE effective_end_date = DATE '4712-12-31'
-- Row effective today
WHERE TRUNC(SYSDATE)
BETWEEN effective_start_date AND effective_end_date
Six Effective-Date SQL Patterns That Matter
1. Current primary worker assignment
For PER_ALL_ASSIGNMENTS_M, the date range alone isn't enough. Earlier same-day sequence rows can share the same effective date, so normal current-state reporting should include EFFECTIVE_LATEST_CHANGE='Y'. The assignment-type predicate below also excludes employment/placement terms and other non-worker-assignment rows.
SELECT
p.person_number,
n.display_name,
a.assignment_id,
a.assignment_number,
a.assignment_status_type
FROM per_all_people_f p
JOIN per_person_names_f n
ON n.person_id = p.person_id
AND n.name_type = 'GLOBAL'
AND TRUNC(SYSDATE)
BETWEEN n.effective_start_date AND n.effective_end_date
JOIN per_all_assignments_m a
ON a.person_id = p.person_id
AND a.assignment_type IN ('E','C','N','P')
AND a.effective_latest_change = 'Y'
AND a.primary_flag = 'Y'
AND TRUNC(SYSDATE)
BETWEEN a.effective_start_date AND a.effective_end_date
WHERE TRUNC(SYSDATE)
BETWEEN p.effective_start_date AND p.effective_end_date;
Business rule vs deduplication: PRIMARY_FLAG='Y' means “primary assignment” and should be used only when that is actually the report requirement. It isn't a generic duplicate-removal technique.
2. Historical point-in-time snapshot
Use one as-of date consistently across every date-effective object. PER_JOBS_F doesn't contain the translated job name, so the example uses PER_JOBS_F_VL.
SELECT
p.person_number,
n.display_name,
a.assignment_number,
j.job_code,
j.name AS job_name
FROM per_all_people_f p
JOIN per_person_names_f n
ON n.person_id = p.person_id
AND n.name_type = 'GLOBAL'
AND TRUNC(:p_as_of_date)
BETWEEN n.effective_start_date AND n.effective_end_date
JOIN per_all_assignments_m a
ON a.person_id = p.person_id
AND a.assignment_type IN ('E','C','N','P')
AND a.effective_latest_change = 'Y'
AND a.primary_flag = 'Y'
AND TRUNC(:p_as_of_date)
BETWEEN a.effective_start_date AND a.effective_end_date
LEFT JOIN per_jobs_f_vl j
ON j.job_id = a.job_id
AND TRUNC(:p_as_of_date)
BETWEEN j.effective_start_date AND j.effective_end_date
WHERE TRUNC(:p_as_of_date)
BETWEEN p.effective_start_date AND p.effective_end_date;
3. Final assignment state for each effective date
If the report needs one assignment state per day, keep only the last same-day change.
SELECT
a.person_id,
a.assignment_id,
a.assignment_number,
a.effective_start_date AS change_date,
a.effective_sequence,
a.job_id,
a.organization_id,
a.location_id
FROM per_all_assignments_m a
WHERE a.assignment_type IN ('E','C','N','P')
AND a.effective_latest_change = 'Y'
AND a.effective_start_date
BETWEEN TRUNC(:p_from_date) AND TRUNC(:p_to_date)
ORDER BY a.assignment_id,
a.effective_start_date,
a.effective_sequence;
4. Every same-day assignment change
For an audit-style timeline, don't filter out EFFECTIVE_LATEST_CHANGE='N'. Instead, expose the sequence. Oracle uses EFFECTIVE_SEQUENCE to order multiple updates made on the same effective date; the lowest number is the earliest change.
SELECT
a.assignment_id,
a.effective_start_date,
a.effective_end_date,
a.effective_sequence,
a.effective_latest_change,
a.job_id,
a.organization_id,
a.location_id,
a.assignment_status_type
FROM per_all_assignments_m a
WHERE a.assignment_id = :p_assignment_id
ORDER BY a.effective_start_date,
a.effective_sequence;
On a multiple-changes-per-day object, an earlier row can have EFFECTIVE_LATEST_CHANGE='N' and the same effective start/end date. That is why a date-range predicate by itself can return more than one assignment row for the same day.
5. Join historical date ranges by overlap
For a single snapshot, apply the same as-of date to both tables. For a timeline that must preserve all periods where two objects were simultaneously valid, join their effective ranges by overlap.
SELECT
a.assignment_id,
a.job_id,
j.job_code,
GREATEST(a.effective_start_date,
j.effective_start_date) AS valid_from,
LEAST(a.effective_end_date,
j.effective_end_date) AS valid_to
FROM per_all_assignments_m a
JOIN per_jobs_f j
ON j.job_id = a.job_id
AND a.effective_start_date <= j.effective_end_date
AND a.effective_end_date >= j.effective_start_date
WHERE a.assignment_id = :p_assignment_id
AND a.effective_latest_change = 'Y'
ORDER BY valid_from;
This pattern is useful when reconstructing historical assignment/job or assignment/position timelines. It is different from an as-of-date report.
6. Open-ended rows
Use the 4712 predicate only when the business question is specifically “what is the last open-ended physical row?” If the question is “what is effective today?”, use the as-of-date pattern instead.
SELECT
job_id,
job_code,
effective_start_date,
effective_end_date,
active_status
FROM per_jobs_f
WHERE effective_end_date = DATE '4712-12-31';
Dates Aren't the Only Filter
A row can be effective on a date and still not be the row your report needs. Temporal filters answer “which version existed?” Other attributes answer “which business record qualifies?”
| Filter | Why it matters |
|---|---|
EFFECTIVE_LATEST_CHANGE='Y' | For MCPD objects such as assignments, selects the last change on an effective date. |
ASSIGNMENT_TYPE | Separates actual worker assignments from employment/placement terms and other assignment record types. |
PRIMARY_FLAG='Y' | Selects the primary assignment only when the report requires it. |
NAME_TYPE='GLOBAL' | Selects the global person name. Use a local name type instead if that is the report requirement. |
| Status columns | Jobs, grades, positions, and other objects can be date-effective but inactive. Effective dates don't override business status. |
Common Mistakes
SYSDATE side. Wrapping effective-date columns in functions can make predicates harder to optimize.Quick Reference
| Use case | Core pattern |
|---|---|
| Current row | TRUNC(SYSDATE) BETWEEN start AND end |
| Historical snapshot | TRUNC(:p_date) BETWEEN start AND end |
| Assignment snapshot | Date range + EFFECTIVE_LATEST_CHANGE='Y' |
| All same-day assignment changes | Keep all rows; order by EFFECTIVE_START_DATE, EFFECTIVE_SEQUENCE |
| Daily final assignment history | EFFECTIVE_LATEST_CHANGE='Y' + order by effective date |
| Historical range join | a.start <= b.end AND a.end >= b.start |
| Open-ended last row | EFFECTIVE_END_DATE = DATE '4712-12-31' |
Recommended Workflow
- Identify the required grain: person, work relationship, assignment, job, position, or another logical object.
- Check the actual Oracle object metadata instead of inferring behavior only from the table suffix.
- Decide whether the report needs a current snapshot, historical as-of snapshot, daily final state, or every same-day change.
- Apply the same as-of date to every date-effective object in a snapshot query.
- For
PER_ALL_ASSIGNMENTS_M, decide explicitly whetherEFFECTIVE_LATEST_CHANGEandEFFECTIVE_SEQUENCEare required. - Add business filters such as assignment type, primary assignment, name type, and active status only when they match the report requirement.
- Validate row counts one join at a time before adding aggregation.
Key Takeaways
Reliable Oracle Fusion effective-date SQL requires more than adding one BETWEEN condition. You need to understand whether an object is truly date-effective, whether corrections or updates created the history, whether future rows exist, and whether the object supports multiple changes per day.
For worker assignment reporting, EFFECTIVE_LATEST_CHANGE and EFFECTIVE_SEQUENCE are especially important. For 4712-dated rows, remember that “open-ended” and “current” are different concepts.
Build Effective-Date SQL Faster with FusionLens SQL
Inspect effective start/end dates, keys, sequence columns, translation views, and related Oracle Fusion objects before writing the join.
Write and test current, as-of, historical, and multiple-changes-per-day SQL against your Oracle Fusion reporting connection.
Keep working versions of effective-date queries and compare the changes that fixed duplicate rows or incorrect snapshots.
Related
See the effective-dated tables section of the complete Oracle Fusion SQL Guide for additional production query patterns.