Chuyển đến nội dung chính

Lesson 7: CONDITION_OCCURRENCE — Diagnosis & Pathology

Record diagnosis, symptoms, pathological signs, condition_concept_id vs source_value, condition_status (admitting/primary/secondary), link to Visit and Provider, distinguish from OBSERVATION table.

🏗️ Architecture — Lesson 7 CONDITION_OCCURRENCE Diagnosis & Pathology OMOP CDM 5.4 for Beginners — Understand A to Z Part 3: Key clinical events xdev.asia

ICD-10 → SNOMED mapping process in CONDITION_OCCURRENCE

Introduction

CONDITION_OCCURRENCE records all medical diagnoses, symptoms, and signs that the doctor notes for the patient. This is often the most analyzed table in OMOP CDM — because medical research often starts with the question: "Who gets what?"


1. Table structure

ColumnTypeRequiredDescription
condition_occurrence_idINTEGER✅ PKUnique ID
person_idINTEGER✅ FKPatients
condition_concept_idINTEGER✅Standard Concept (SNOMED)
condition_start_dateDATE✅Diagnosis start date
condition_start_datetimeDATETIMEDate and time
condition_end_dateDATEDate of end of diagnosis
condition_end_datetimeDATETIMEEnd date and time
condition_type_concept_idINTEGER✅Data source
condition_status_concept_idINTEGERStatus (Primary, Admitting...)
stop_reasonVARCHAR(20)Reasons for stopping diagnosis
provider_idINTEGERFKDiagnosis Doctor
visit_occurrence_idINTEGERFKRelated Visit
visit_detail_idINTEGERFKVisit details (which department)
condition_source_valueVARCHAR(50)Original code (eg "E11")
condition_source_concept_idINTEGEROriginal concept
condition_status_source_valueVARCHAR(50)Original status

2. What is stored in CONDITION_OCCURRENCE?

2.1. SHOULD save

TypeExampleVocabulary
Disease diagnosisType 2 diabetes, PneumoniaSNOMED CT
SymptomsFever, Abdominal pain, CoughSNOMED CT
Clinical signsSwollen feet, JaundiceSNOMED CT
Differential diagnosisSuspected pulmonary tuberculosisSNOMED CT

2.2. DO NOT save (save in another table)

TypeDestination tableReason
"History of diabetes"OBSERVATIONDomain = Observation
"No allergies"OBSERVATIONAbsence → Observation
"BMI = 28"MEASUREMENTDomain = Measurement
Drug side effectsCONDITION + DRUG_EXPOSURECondition for ADR, Drug for drug causing

3. condition_status_concept_id — Diagnostic status

Concept IDStatusMeaning
32902Primary diagnosisPrimary Diagnosis
32908Secondary diagnosisSecondary Diagnosis
32903Admitting diagnosisDiagnosis at admission
32904Discharge diagnosisDiagnosis at discharge
32906Provisional diagnosisProvisional diagnosis
32907Confirmed diagnosisConfirmed diagnosis
-- Ví dụ: BN nhập viện
-- Chẩn đoán nhập viện: Nghi lao phổi (provisional)
INSERT INTO condition_occurrence VALUES (
    70001, 100001, 255848,       -- SNOMED: Pneumonia
    '2024-06-10', NULL,
    '2024-06-20', NULL,
    32817,                        -- EHR
    32903,                        -- Admitting diagnosis
    NULL, 5001, 50001, NULL,
    'J18.9', 0,                   -- ICD-10: Pneumonia, unspecified
    'admitting'
);

-- Chẩn đoán xuất viện: Viêm phổi do phế cầu (confirmed)
INSERT INTO condition_occurrence VALUES (
    70002, 100001, 257315,       -- SNOMED: Pneumococcal pneumonia
    '2024-06-10', NULL,
    '2024-06-20', NULL,
    32817,                        -- EHR
    32904,                        -- Discharge diagnosis
    NULL, 5001, 50001, NULL,
    'J13', 0,                     -- ICD-10
    'discharge'
);

4. ETL for Vietnam ICD-10 data

4.1. Mapping process

  HIS: ma_benh = 'E11.65'  (ICD-10-CM)
       ten_benh = 'ĐTĐ type 2 có biến chứng mạch máu ngoại vi'
       │
       │ Bước 1: Tìm source concept
       ↓
  SOURCE CONCEPT: concept_id = 45591837
       vocabulary_id = ICD10CM
       concept_code = 'E11.65'
       │
       │ Bước 2: Tìm Standard Concept (Maps to)
       ↓
  STANDARD CONCEPT: concept_id = 201826
       vocabulary_id = SNOMED
       concept_name = 'Type 2 diabetes mellitus'
       domain_id = 'Condition'
-- SQL ETL
SELECT
    ROW_NUMBER() OVER() AS condition_occurrence_id,
    pm.person_id,
    COALESCE(cr.concept_id_2, 0) AS condition_concept_id,
    cd.ngay_chandoan AS condition_start_date,
    NULL AS condition_end_date,
    32817 AS condition_type_concept_id,
    CASE cd.loai_chandoan
        WHEN 'CHINH' THEN 32902   -- Primary
        WHEN 'PHU'   THEN 32908   -- Secondary
        ELSE 0
    END AS condition_status_concept_id,
    cd.ma_icd10 AS condition_source_value,
    COALESCE(c_source.concept_id, 0) AS condition_source_concept_id
FROM chandoan_his cd
JOIN person_mapping pm ON cd.ma_bn = pm.source_id
LEFT JOIN concept c_source
    ON cd.ma_icd10 = c_source.concept_code
    AND c_source.vocabulary_id = 'ICD10CM'
LEFT JOIN concept_relationship cr
    ON c_source.concept_id = cr.concept_id_1
    AND cr.relationship_id = 'Maps to'
LEFT JOIN concept c_std
    ON cr.concept_id_2 = c_std.concept_id
    AND c_std.standard_concept = 'S';

4.2. Vietnam-specific data processing

ProblemSolution
ICD-10-VN is different from ICD-10-CMMapping via SOURCE_TO_CONCEPT_MAP
BV internal codeUsagi mapping tool
Missing end datecondition_end_date = NULL (valid)
1 ICD map many SNOMEDChoose the most suitable concept

5. Distinguish between CONDITION and OBSERVATION

CriteriaCONDITION_OCCURRENCEOBSERVATION
ContentCurrent illness/under treatmentPrehistory, lifestyle, records
Example"Type 2 diabetes""Family history of diabetes"
DomainConditionsObservation
Standard VocabSNOMED CTSNOMED CT
When?Active diseaseRecord information

Rule: Always check Standard Concept's domain_id on Athena. If domain = "Observation", save to OBSERVATION even though the source is ICD-10.


6. Popular SQL analysis

-- Top 10 chẩn đoán phổ biến nhất
SELECT
    c.concept_name AS condition_name,
    COUNT(DISTINCT co.person_id) AS patient_count,
    COUNT(*) AS record_count
FROM condition_occurrence co
JOIN concept c ON co.condition_concept_id = c.concept_id
WHERE co.condition_concept_id != 0
GROUP BY c.concept_name
ORDER BY patient_count DESC
LIMIT 10;

-- Tỉ lệ mắc bệnh theo giới tính
SELECT
    g.concept_name AS gender,
    c.concept_name AS condition_name,
    COUNT(DISTINCT co.person_id) AS patients
FROM condition_occurrence co
JOIN person p ON co.person_id = p.person_id
JOIN concept g ON p.gender_concept_id = g.concept_id
JOIN concept c ON co.condition_concept_id = c.concept_id
WHERE co.condition_concept_id = 201826  -- Type 2 DM
GROUP BY g.concept_name, c.concept_name;

-- Comorbidity: BN tiểu đường có tăng huyết áp?
SELECT
    COUNT(DISTINCT co_dm.person_id) AS dm_patients,
    COUNT(DISTINCT co_ht.person_id) AS dm_with_hypertension,
    ROUND(
        COUNT(DISTINCT co_ht.person_id) * 100.0 /
        NULLIF(COUNT(DISTINCT co_dm.person_id), 0), 1
    ) AS comorbidity_pct
FROM condition_occurrence co_dm
LEFT JOIN condition_occurrence co_ht
    ON co_dm.person_id = co_ht.person_id
    AND co_ht.condition_concept_id IN (
        SELECT descendant_concept_id
        FROM concept_ancestor
        WHERE ancestor_concept_id = 320128  -- Essential hypertension
    )
WHERE co_dm.condition_concept_id IN (
    SELECT descendant_concept_id
    FROM concept_ancestor
    WHERE ancestor_concept_id = 201826  -- Type 2 DM
);

Summary

  1. CONDITION_OCCURRENCE = diagnosis, symptoms, signs of pathology
  2. condition_concept_id uses Standard Concept (SNOMED CT)
  3. condition_status: Primary, Secondary, Admitting, Discharge
  4. Tree of three columns: concept_id / source_value / source_concept_id
  5. Distinguish CONDITION (current illness) vs OBSERVATION (history, record)
  6. ETL VN: ICD-10-VN → Source Concept → Maps to → Standard SNOMED

Next article: DRUG_EXPOSURE — how OMOP CDM records drugs, prescriptions, and vaccines.


References