Procedure
→
procedure_occurrence
documented
primary
One FHIR Procedure maps to one procedure_occurrence row. Domain routing may redirect codes with non-Procedure domain_id to drug_exposure, device_exposure, measurement, or observation. Only completed procedures should produce rows. performed[x] is polymorphic (dateTime or Period) and at least procedure_date is required -- skip the resource if no date is available.
Conversion profile
omop-procedure-procedure-occurrence
A FHIR instance converts to procedure_occurrence iff it validates against this profile.
| Path | Card | Type | Binding / Fixed | Comment |
|---|---|---|---|---|
| Procedure.status | fhir/event-statusrequired | Skip not-done, entered-in-error, stopped, preparation. | ||
| Procedure.code | 1..*MS | omop-procedure-codesrequired | ||
| Procedure.subject | 1..* | Reference | Required for procedure_occurrence.person_id. | |
| Procedure.performed[x] | 1..*MS | Required for procedure_occurrence.procedure_date. Accepts dateTime, Period, string, Age, Range. |
ViewDefinition (Stage 1 flattener)
omop-procedure-procedure-occurrence
16 columns · resource Procedure
| column name | FHIRPath | type |
|---|---|---|
| id | Procedure.id | id |
| code_cpt | Procedure.code.coding.where(system='http://www.ama-assn.org/go/cpt').first().code | code |
| code_hcpcs | Procedure.code.coding.where(system='https://www.cms.gov/Medicare/Coding/HCPCSReleaseCodeSets').first().code | code |
| code_snomed | Procedure.code.coding.where(system='http://snomed.info/sct').first().code | code |
| code_icd10pcs | Procedure.code.coding.where(system='http://www.cms.gov/Medicare/Coding/ICD10').first().code | code |
| code_icd9cm | Procedure.code.coding.where(system='http://hl7.org/fhir/sid/icd-9-cm').first().code | code |
| code_text | Procedure.code.text | string |
| subject_id | Procedure.subject | Reference(Patient) |
| procedure_date | Procedure.performedDateTime | dateTime |
| procedure_datetime | Procedure.performedDateTime | dateTime |
| procedure_end_date | Procedure.performedPeriod.end | dateTime |
| procedure_end_datetime | Procedure.performedPeriod.end | dateTime |
| modifier | Procedure.bodySite[0] | CodeableConcept |
| modifier_text | Procedure.bodySite[0].coding[0].code | code |
| performer_id | Procedure.performer[0].actor | Reference(Practitioner) |
| encounter_id | Procedure.encounter | Reference(Encounter) |
Condition: status is completed (recommended); code domain_id is Procedure
Fields (16)
-
procedure_occurrence_id←Procedure.idinteger · idPKrequiredSurrogate key. Generated via hash/sequence/lookup of Procedure.id. HL7 IG leaves as TODO. NACHC uses FhirToOmopIdGenerator.getId().4 sources ▾
-
TODO/commented placeholder — no concrete strategy
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Procedure.fml:11-16
-
Sequence via IdMapping lookup table
-
FhirToOmopIdGenerator.getId() — dedicated ID generation utility
-
int(Procedure.id) — verbatim FHIR id cast to integer
- fhir-x-omop(python) refs/refs/fhir-x-omop/fhir_x_omop/to_omop/procedure_occurrence.py
-
-
person_id←Procedure.subjectinteger · Reference(Patient)FK→PERSONrequiredResolve Patient reference to integer person_id. Skip resource if unresolved. -
procedure_concept_id←Procedure.codeinteger · CodeableConceptFK→CONCEPTrequiredmap:procedure_codeMap SNOMED/CPT/ICD-10-PCS/OPS code to OMOP standard concept via vocabulary lookup. Use concept_relationship (Maps to) for non-standard codes. 0 if unmapped. Check domain_id for routing.4 sources ▾
-
DB lookup via OmopConceptToUse — standard concept resolution from vocabulary tables
-
DB lookup via LookupCode; one row per coding
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:416-417
-
Full vocab lookup with OPS/SNOMED/DICOM priority + domain routing
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ProcedureMapper.java:628-701
-
Hardcoded to 0 — no vocabulary lookup performed
- fhir-x-omop(python) refs/refs/fhir-x-omop/fhir_x_omop/to_omop/procedure_occurrence.py
-
-
procedure_date←Procedure.performedDateTime | Procedure.performedPeriod.startdate · dateTimerequiredperformedDateTime date part, or performedPeriod.start date part. Required -- skip resource if absent. -
procedure_datetime←Procedure.performedDateTime | Procedure.performedPeriod.startdatetime · dateTimeFull ISO datetime. Same source as procedure_date but preserves time component. -
procedure_end_date←Procedure.performedPeriod.enddate · dateTimeEnd date for procedures with duration. For performedDateTime, ETL-German leaves null; NACHC sets end = start.3 sources ▾
-
Sets end_date = start when performedDateTime (no Period.end available)
- NACHC-fhir-to-omop(java) refs/refs/NACHC-fhir-to-omop/src/main/java/org/nachc/tools/fhirtoomop/omop/person/factory/builder/procedure/OmopProcedureBuilder.java:87-109 — ProcedureParser.java lines 87-109: Period only, end falls back to start
-
Leaves null for performedDateTime; only maps Period.end
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ProcedureMapper.java:165-172
-
Period only (always casts to Period, fails for performedDateTime)
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:445-446
-
-
procedure_end_datetime←Procedure.performedPeriod.enddatetime · dateTimeFull ISO datetime of procedure end. -
procedure_type_concept_id← constant integerFK→CONCEPTrequiredmap:procedure_type=3281732817 = 'EHR'. Provenance of the record. FhirToCdm and ETL-German use 32817; omoponfhir and NACHC use 44786630 (Primary Procedure).3 sources ▾
-
32817 (EHR) — recommended modern convention
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:426-426
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ProcedureMapper.java:703-734 — uses CONCEPT_EHR constant = 32817
-
44786630 (Primary Procedure) — legacy choice
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopProcedure.java:64-64
- NACHC-fhir-to-omop(java) refs/refs/NACHC-fhir-to-omop/src/main/java/org/nachc/tools/fhirtoomop/omop/person/factory/builder/procedure/OmopProcedureBuilder.java:97-97
-
Varies by code system URI — 32818/32820 depending on source
- fhir-x-omop(python) refs/refs/fhir-x-omop/fhir_x_omop/to_omop/procedure_occurrence.py:14-18
-
-
modifier_concept_id←Procedure.bodySite[0]integer · CodeableConceptFK→CONCEPTSNOMED body site mapped to OMOP concept. Take first bodySite[0] entry; remaining entries are lost. ETL-German also checks OPS site localization extension. 0 if unmapped or absent.3 sources ▾
-
SNOMED body site + OPS site localization extension — most complete body site handling
-
Not mapped — body site ignored
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopProcedure.java — No body site mapping in constructOmop()
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:407-451
-
Defaults to 0 — no lookup performed
-
-
modifier_source_value←Procedure.bodySite[0].coding[0].codevarchar(50) · codeRaw body site code string. NACHC defaults to 'Not Available' if null. -
provider_id←Procedure.performer[0].actorinteger · Reference(Practitioner)FK→PROVIDERFirst Practitioner-typed performer. Non-Practitioner performers (Organization, Device) are ignored. NACHC defaults to 1 when absent.2 sources ▾
-
Iterates performers, takes first Practitioner-typed actor; updates provider.specialty if function coded
-
Defaults to provider_id = 1 when no performer present
-
-
visit_occurrence_id←Procedure.encounterinteger · Reference(Encounter)FK→VISIT_OCCURRENCEResolve Encounter reference to integer visit_occurrence_id. Null if unresolved (optional field). -
visit_detail_id← — integerFK→VISIT_DETAILNot mapped. No direct FHIR equivalent. FhirToCdm sets it equal to visit_occurrence_id (non-standard). -
procedure_source_value←Procedure.code.coding[best].codevarchar(50) · codeRaw procedure code string. Best code by vocabulary priority (SNOMED > CPT > ICD-10-PCS). Truncate to 50 characters. -
procedure_source_concept_id←Procedure.codeinteger · CodeableConceptFK→CONCEPTSource vocabulary concept_id (non-standard). Lookup the source code in its native vocabulary. NACHC copies procedure_concept_id here if null. 0 if unmapped. -
quantity← — integerFHIR Procedure has no quantity field. NACHC defaults to 1. Most implementations leave null.2 sources ▾
-
Defaults to 1
-
Left null — no quantity mapping
-
Vocabularies
procedure_code
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| http://snomed.info/sct | SNOMED CT | - | SNOMED vocabulary_id |
| http://www.ama-assn.org/go/cpt | CPT-4 | - | CPT4 vocabulary_id |
| http://hl7.org/fhir/sid/icd-10-pcs | ICD-10-PCS | - | ICD10PCS vocabulary_id |
| http://hl7.org/fhir/sid/icd-9-cm | ICD-9-CM (Vol 3) | - | ICD9Proc vocabulary_id |
| https://www.cms.gov/Medicare/Coding/HCPCSReleaseCodeSets | HCPCS | - | HCPCS vocabulary_id |
| http://fhir.de/CodeSystem/bfarm/ops | OPS | - | OPS vocabulary_id |
procedure_type
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| EHR | EHR | 32817 | EHR |
| Primary Procedure | Primary Procedure (legacy) | 44786630 | Primary Procedure |
body_site
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| http://snomed.info/sct | SNOMED CT (Body Structure) | - | SNOMED body site concept |
status_filter
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| completed | Completed | - | Map |
| in-progress | In Progress | - | Skip or Map |
| not-done | Not Done | - | Skip |
| entered-in-error | Entered in Error | - | Skip |
| stopped | Stopped | - | Skip |
| preparation | Preparation | - | Skip |
Edge Cases
Multiple bodySite entries
Take first bodySite[0] for modifier_concept_id. ETL-German filters to SNOMED codings only. Remaining body sites are lost.
Multiple performer entries
Iterate and take first Practitioner-typed actor for provider_id. Non-Practitioner performers (Organization, Device) are ignored.
Multiple code.coding entries
Select best coding by vocabulary priority (SNOMED > CPT > ICD-10-PCS). ETL-German uses OPS > DICOM > SNOMED priority. FhirToCdm creates one row per coding. HL7 IG takes first coding only.
Code with non-Procedure domain
Route to appropriate OMOP table (drug_exposure, observation, measurement) based on standard concept's domain_id.
Missing performed[x] (no date)
Skip resource. procedure_date is required. ETL-German logs warning and returns null.
Missing subject reference
Skip resource. person_id is required. omoponfhir throws FHIRException. ETL-German logs and returns null.
Missing code
Skip resource. procedure_concept_id is required (0 is acceptable). ETL-German logs and skips.
status = entered-in-error
Skip resource. For incremental loads, delete any previously mapped record.
Extremely long procedure_source_value
OMOP field is varchar(50). Truncate code string to 50 characters. No implementation explicitly handles this.
usedCode (device codes) present
ETL-German creates device_exposure rows from Procedure.usedCode codings. Other implementations ignore this field.
focalDevice present
Could create device_exposure row. ETL-German handles usedCode (not focalDevice) for device exposure. No standard mapping for focalDevice.
reasonReference to Condition
Could populate fact_relationship to link procedure and condition. Not implemented in any reference.
performedDateTime (not Period)
Date part goes to procedure_date/procedure_datetime. procedure_end_date: ETL-German leaves null, NACHC sets end = start.
Procedure.category present
Could inform procedure_type_concept_id, but no implementation uses it. omoponfhir has commented-out code for this.
Reference Implementations
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Procedure.fml — 29 lines. Maps code and performed[x] only. procedure_occurrence_id and person_id are commented-out TODOs.
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopProcedure.java:1-515 — Bidirectional. constructOmop() at lines 369-513. Type concept 44786630. No status filtering, no body site, no domain routing.
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs — CreateProcedureOccurrence() lines 407-451. One row per coding. Type concept 32817. Partial domain routing.
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ProcedureMapper.java:1-1140 — Most complete: OPS/SNOMED/DICOM, full domain routing, body site + OPS localization, device_exposure from usedCode, status filtering, incremental updates.
- NACHC-fhir-to-omop(java) refs/refs/NACHC-fhir-to-omop/src/main/java/org/nachc/tools/fhirtoomop/omop/person/factory/builder/procedure/OmopProcedureBuilder.java:1-136 — DSTU3. Domain routing to Procedure/Measurement/Observation/Condition. Defaults: provider_id=1, quantity=1, modifier_concept_id=0.
- fhir-x-omop(python) refs/refs/fhir-x-omop/fhir_x_omop/to_omop/procedure_occurrence.py — 34 lines. Minimal mapper with all concept_ids hardcoded to 0. performedDateTime only.
- HealthcareLakeETL(python) refs/refs/HealthcareLakeETL/mappings/procedure_occurrence.py — 44 lines. PySpark column-level transformation. Period.start only. No concept mapping.