The tables FHIR does not give you¶
Some OMOP CDM tables have no FHIR source. You have to construct them, and the construction is where the most consequential assumptions in the entire pipeline get made.
OBSERVATION_PERIOD¶
The most important table in this chapter and the one with the least guidance.
Why it exists¶
OBSERVATION_PERIOD records the spans during which a person was under observation, meaning the spans during which, if something had happened, you would have seen it.
Without it, absence is uninterpretable. Consider a query for people with no myocardial infarction in a given year. Two people match: one who was under care throughout the year and genuinely had no event, and one who moved away in February and had a heart attack elsewhere in June. They are not the same, and only OBSERVATION_PERIOD distinguishes them.
Every incidence rate, every time-at-risk calculation, and every "did not have" criterion in every cohort definition depends on this table. It sets the denominator for essentially all population-scale research on your instance.
Why FHIR has none¶
FHIR describes what is, not the boundary of what is knowable. There is no resource meaning "this person was visible to us from here to here". The concept is foreign to an exchange standard, and reasonably so.
So you derive it. How you derive it changes every study result.
The derivation options¶
Option one: first to last event.
The observation period runs from the person's earliest clinical event to their latest.
Simple, defensible, universally implementable, and biased in a specific direction. By construction, every person has an event on the first and last day of their observation period, which makes the period boundaries look like periods of high activity. It also means a person is defined as unobserved before their first recorded event, even if they were an established patient with a quiet two years.
This is the most common approach in EHR-derived instances and it is a reasonable default. Its bias is well understood in the field.
Option two: continuous coverage.
Derive from Coverage resources, giving spans of insurance enrollment.
Much better where available, because enrollment genuinely does approximate observability in a claims system. Rarely available in EHR FHIR endpoints.
Option three: event density with gap rules.
Start at first event, end at last event, and split the period wherever a gap exceeds a threshold, on the theory that a person with no contact for three years was probably not observable during it.
More faithful and much more assumption-laden. The gap threshold is a free parameter that directly controls the result, and reasonable values range widely by care setting. A dermatology practice and a dialysis center have very different natural contact intervals.
Option four: administrative source.
If the source system can tell you enrollment, attribution, panel membership, or active patient status, use it. This is the best basis available when it exists, and it usually requires data outside the FHIR interface.
The guidance¶
Pick the most defensible option your data supports. Document the rule in CDM_SOURCE and in your ETL specification, with the parameter values stated numerically. Report the distribution of observation period lengths, because that distribution is the first thing a careful analyst will want and the shape of it reveals derivation artifacts quickly.
Be specific in your documentation about what your observation periods do and do not mean. "Derived as first to last clinical event; does not represent enrollment or continuous care" is a sentence that saves a downstream researcher from a wrong conclusion.
The one to be loudest about
If a study using your instance reports an incidence rate, that rate has your OBSERVATION_PERIOD derivation in its denominator. Nobody reading the paper will know what rule you used unless you told the study team, and they will not think to ask unless you told them to ask.
DEATH¶
FHIR scatters death information across several places and none of them is reliable alone.
| Source | Content |
|---|---|
Patient.deceasedBoolean |
The person is dead. No date |
Patient.deceasedDateTime |
Date of death |
Encounter.hospitalization.dischargeDisposition |
A disposition code indicating death, giving an in-hospital death date |
Observation or Condition with a death-related code |
Occasionally |
| External vital status linkage | Often the best source, and not FHIR |
DEATH has death_date, death_datetime, death_type_concept_id, cause_concept_id, cause_source_value, and cause_source_concept_id.
The practical hierarchy: use deceasedDateTime when present. Fall back to a discharge disposition indicating death, taking the encounter end as the date. Treat deceasedBoolean true with no date as a known death with an unknown date, which the OMOP CDM handles awkwardly since death_date is required. Options are to use the last known event date with a type concept marking the imprecision, or to leave the person out of DEATH and note the gap.
Cause of death is rarely available from an EHR FHIR endpoint. Empty is normal.
Completeness is the real issue. EHR data captures in-hospital death reasonably and out-of-hospital death poorly. Mortality studies on EHR-derived instances without external linkage systematically undercount, and the undercount is not random. State the limitation prominently.
The era tables¶
CONDITION_ERA, DRUG_ERA, and DOSE_ERA are computed from the loaded clinical tables, not from source.
An era collapses overlapping and near-contiguous records into continuous periods. Eleven DRUG_EXPOSURE rows for repeated metformin fills become one DRUG_ERA spanning the treatment course, using a persistence window that tolerates gaps.
You do not load these from FHIR. Generate them after loading, using the standard OHDSI logic so that your eras mean the same thing as everyone else's. Reimplementing era logic with local rules produces a table that looks standard and behaves differently, which is worse than not having it.
FACT_RELATIONSHIP¶
Explicit links between rows in other tables. It exists because the OMOP CDM's flat structure loses relationships that were present in the source.
Uses in a FHIR to OMOP pipeline:
- Linking a
DiagnosticReport's component measurements to each other - Linking an allergy observation to its reaction rows
- Linking a procedure to the condition that indicated it, where the source carried
reasonReference - Linking components of a panel
In v5.4, the _event_id and _event_field_concept_id column pairs on several tables provide a lighter-weight alternative for some of these cases.
FACT_RELATIONSHIP is inconsistently populated across instances and inconsistently consumed by tools. Populate it where a relationship carries real meaning, and do not expect analyses to use it automatically.
COHORT and COHORT_DEFINITION¶
Not part of ETL. Populated by ATLAS and analytical tooling when studies are run. Create the tables, leave them empty.
CDM_SOURCE and METADATA¶
Small, quick, and the first thing a careful collaborator reads.
CDM_SOURCE should carry the source name and abbreviation, the holder, a description, the source documentation reference, the ETL reference, the source release date, the OMOP CDM release date, the OMOP CDM version, and the vocabulary version.
Populating this table well is one of the highest-value-per-minute activities in the entire project. An instance with a well-filled CDM_SOURCE communicates that someone was paying attention. An empty one raises questions about everything else.
Use the description field. Write two or three sentences saying what this data is, what population it covers, what is known to be incomplete, and how observation period was derived. That paragraph will be read more often than your ETL specification.
METADATA holds additional structured metadata, including a good place to record ETL run details and version.
A summary of the inventions¶
Every one of these is a place where your pipeline creates information that the source did not contain. Each deserves a line in your documentation.
| Invention | The assumption |
|---|---|
| Observation period boundaries | When this person was observable |
| Drug exposure end dates | How long an exposure lasted |
| Visit grouping from flat encounters | Which encounters were one episode |
| Imputed date components | What the missing precision was |
| Local code mappings | What a local code corresponds to |
| Death date from disposition | That the encounter end is the death time |
| Event-to-visit attachment by time | That temporal coincidence implies clinical association |
Seven inventions. None produces an error. All change results. A pipeline whose documentation names all seven, states the rule for each, and reports the affected row counts is a pipeline that a researcher can use responsibly.
Next¶
- Getting the data, where the operational chapters begin