DiagnosticReport
→
procedure_occurrence
documented
When a DiagnosticReport's LOINC code resolves to an OMOP concept with domain_id = Procedure, the report produces one or more procedure_occurrence rows. This occurs primarily for imaging studies (radiology, nuclear medicine), pathology procedures, and certain clinical assessments whose LOINC codes are classified in the Procedure domain by the OMOP vocabulary. Each conclusionCode entry generates a separate row. This is independent of the Observation results referenced by DiagnosticReport.result[], which are mapped by the Observation mapper.
Conversion profile
omop-diagnosticreport-procedure-occurrence
A FHIR instance converts to procedure_occurrence iff it validates against this profile.
| Path | Card | Type | Binding / Fixed | Comment |
|---|---|---|---|---|
| DiagnosticReport.status | fhir/diagnostic-report-statusrequired | |||
| DiagnosticReport.code | 1..*MS | omop-procedure-codesrequired | ||
| DiagnosticReport.subject | 1..* | Reference | Required for procedure_occurrence.person_id. | |
| DiagnosticReport.effective[x] | 1..*MS | Required for procedure_occurrence.procedure_date / procedure_datetime. |
ViewDefinition (Stage 1 flattener)
omop-diagnosticreport-procedure-occurrence
13 columns · resource DiagnosticReport
| column name | FHIRPath | type |
|---|---|---|
| id | DiagnosticReport.id | id |
| code_loinc | DiagnosticReport.code.coding.where(system='http://loinc.org').first().code | code |
| code_snomed | DiagnosticReport.code.coding.where(system='http://snomed.info/sct').first().code | code |
| code_cpt | DiagnosticReport.code.coding.where(system='http://www.ama-assn.org/go/cpt').first().code | code |
| code_text | DiagnosticReport.code.text | string |
| subject_id | DiagnosticReport.subject | Reference(Patient) |
| procedure_date | DiagnosticReport.effective[x] | dateTime|Period |
| procedure_datetime | DiagnosticReport.effective[x] | dateTime|Period |
| procedure_end_date | DiagnosticReport.effectivePeriod.end | dateTime |
| procedure_end_datetime | DiagnosticReport.effectivePeriod.end | dateTime |
| modifier | DiagnosticReport.conclusionCode | Coding |
| performer_id | DiagnosticReport.performer[0] | Reference(Practitioner) |
| encounter_id | DiagnosticReport.encounter | Reference(Encounter) |
Condition: DiagnosticReport.code (LOINC) resolves to OMOP concept with domain_id = Procedure
Fields (16)
-
procedure_occurrence_id← — integer · idPKrequiredSurrogate key. Hash/sequence of DiagnosticReport.id + conclusionCode index. Must be unique across all procedure_occurrence sources. -
person_id←DiagnosticReport.subjectinteger · Reference(Patient)FK→PERSONrequiredResolve Patient/{id} reference to integer person_id. Skip row if unresolvable. -
procedure_concept_id←DiagnosticReport.codeinteger · CodeableConceptFK→CONCEPTrequiredLOINC code looked up in OMOP vocabulary. Must have domain_id = Procedure. Use first LOINC coding found. 0 if concept not found. ETL-German uses loincCodingConcept.getConceptId() (line 274). -
procedure_date←DiagnosticReport.effective[x]date · dateTime|PeriodrequiredDate component of effectiveDateTime, or effectivePeriod.start. Skip row if absent (ETL-German behavior). -
procedure_datetime←DiagnosticReport.effective[x]datetime · dateTime|PeriodFull timestamp from effectiveDateTime or effectivePeriod.start. -
procedure_end_date←DiagnosticReport.effectivePeriod.enddate · dateTimeEnd date from effectivePeriod.end. ETL-German does not set this field (only uses startDateTime). Leave null for effectiveDateTime. -
procedure_end_datetime←DiagnosticReport.effectivePeriod.enddatetime · dateTimeFull timestamp from effectivePeriod.end. ETL-German does not set this field. -
procedure_type_concept_id←DiagnosticReport.categoryinteger · CodeableConceptFK→CONCEPTrequiredmap:diagnostic_report_categoryETL-German maps category via SOURCE_VOCABULARY_ID_DIAGNOSTIC_REPORT_CATEGORY custom concept map (line 273). Common default: 32817 (EHR).2 sources ▾
-
Custom source_to_concept_map keyed on 'Diag.Rep Category' (line 190); category required — resource skipped if absent (lines 125-131)
-
Conceptual: category maps to procedure type concept
- fhir2omop-cookbook(guidance) refs/fhir2omop-cookbook.md:528-575
-
-
modifier_concept_id←DiagnosticReport.conclusionCodeinteger · CodingFK→CONCEPTETL-German extracts interpretation codes from composite SNOMED expressions in conclusionCode (e.g. the value after = in 118247008:{363713009=373068000}) and resolves them to OMOP concepts (lines 286-297). Set only when conclusionCode contains a :{ composite expression. 0 if absent or unmapped.2 sources ▾
-
Interpretation code from composite SNOMED expression resolved to OMOP concept (lines 286-297); only ETL-German implements this
-
Not specified — no other implementation addresses modifier_concept_id for DiagnosticReport
- fhir2omop-cookbook(guidance) refs/fhir2omop-cookbook.md:528-575
-
-
quantity← — integerDiagnosticReport has no quantity field. Leave null. -
provider_id←DiagnosticReport.performer[0]integer · Reference(Practitioner)FK→PROVIDERFirst performer reference resolved to provider_id. Also consider resultsInterpreter[0]. ETL-German does not map this field for DiagnosticReport procedure_occurrence rows (gap in implementation). -
visit_occurrence_id←DiagnosticReport.encounterinteger · Reference(Encounter)FK→VISIT_OCCURRENCEResolve Encounter/{id} to visit_occurrence_id. ETL-German sets this (line 272). -
visit_detail_id← — integerFK→VISIT_DETAILLeave null unless visit details are modeled. -
procedure_source_value←DiagnosticReport.conclusionCode.coding[0].codevarchar(50) · codeVerbatim SNOMED code from conclusionCode. ETL-German stores snomedCoding.getCode() (line 277).1 source ▾
-
SNOMED conclusionCode code string stored here (line 277); commented-out alternative would use loincCodingConcept.getConceptCode() (line 278)
-
-
procedure_source_concept_id←DiagnosticReport.conclusionCodeinteger · CodeableConceptFK→CONCEPTSNOMED conclusionCode resolved to OMOP concept ID. ETL-German stores snomedConcept.getConceptId() (line 276).1 source ▾
-
SNOMED conclusionCode concept stored here (line 276); commented-out alternative would use loincCodingConcept.getConceptId() (line 275)
-
-
modifier_source_value← — varchar(50)Verbatim interpretation code from composite SNOMED expression. ETL-German stores interpretationConcept.getConceptCode() (line 296). Only set when composite SNOMED expression is present.
Vocabularies
report_code_loinc
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| 24725-4 | CT Head W contrast IV | 3027018 | CT Head W contrast IV |
| 24566-1 | XR Chest 2 Views | 3003961 | XR Chest 2 Views |
| 24532-3 | MRI Brain WO contrast | 3048098 | MRI Brain WO contrast |
| 38269-7 | US Abdomen | 3042955 | US Abdomen |
| 24627-1 | MR Heart | 3044437 | MR Heart |
| 24610-7 | XR Spine Lumbar AP+Lateral | 3018893 | XR Spine Lumbar AP+Lateral |
diagnostic_report_category
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| RAD | Radiology | 32817 | EHR |
| PAT | Pathology | 32817 | EHR |
| LAB | Laboratory | 32856 | Lab result |
| MB | Microbiology | 32817 | EHR |
| (absent) | No category | 32817 | EHR |
Edge Cases
No effectiveDateTime or effectivePeriod
ETL-German skips the resource entirely. procedure_date is required in OMOP. Alternative: fall back to issued timestamp.
Status is registered, preliminary, cancelled, entered-in-error, or unknown
Reject. Accept only final, amended, corrected, appended.
No conclusionCode
ETL-German skips the resource. Without a conclusion, there is no SNOMED finding to store in procedure_source_concept_id. Only the referenced Observations produce rows.
Multiple conclusionCode entries
Each code produces a separate procedure_occurrence row. The procedure_concept_id (report LOINC) is the same across all rows; only procedure_source_concept_id and procedure_source_value differ.
Composite SNOMED in conclusionCode (e.g. 118247008:{363713009=373068000})
ETL-German splits composite expressions: base code before : maps to procedure_source_concept_id; attributes after :{ are parsed, and the interpretation code (value after =) is resolved to modifier_concept_id.
SNOMED codes joined with + (conjunction)
ETL-German splits on + and creates one row per component code. Each component is processed independently.
No category
ETL-German skips the resource. Alternative: default to procedure_type_concept_id = 32817 (EHR).
LOINC code resolves to Measurement or Observation domain
Route to measurement or observation table instead.
effectivePeriod with both start and end
ETL-German only uses startDateTime for procedure date/datetime. procedure_end_date and procedure_end_datetime are not populated. A complete implementation should use effectivePeriod.end for the end date fields.
Report with result[] but no code or conclusionCode
No report-level row produced. The Observations in result[] are still mapped independently.
subject references Group (not Patient)
Not supported. OMOP requires a single person_id. Skip the resource.
Incremental updates (same DiagnosticReport reprocessed)
ETL-German deletes existing OMOP rows from procedure_occurrence, measurement, and observation tables by fhirLogicalId or fhirIdentifier before re-inserting.
provider_id not populated by ETL-German
The ETL-German procedure builder does not set provider_id. A complete implementation should resolve performer[0] or resultsInterpreter[0] to a provider.
Reference Implementations
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/DiagnosticReportMapper.java:239-301 — Primary reference. createDiagnosticReportProcedureOcc() with domain routing, LOINC lookup, SNOMED conclusionCode, composite SNOMED splitting, interpretation to modifier_concept_id.
- fhir2omop-cookbook(guidance) refs/fhir2omop-cookbook.md:160-162 — Mentions Procedure domain routing conceptually. No field-level mapping for DiagnosticReport-to-procedure_occurrence.
- NACHC-fhir-to-omop(java) refs/refs/NACHC-fhir-to-omop/src/main/java/org/nachc/tools/fhirtoomop/fhir/parser/r4/diagnosticreport/DiagnosticReportParser.java:1-120 — Parser only -- extracts code, status, effectivePeriod. No OMOP procedure_occurrence output.