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

Bài 4: Bảng PERSON — Quản lý danh tính bệnh nhân

Cấu trúc bảng PERSON, các trường bắt buộc (person_id, gender_concept_id, year_of_birth), demographic data, liên kết với LOCATION và PROVIDER, ETL conventions cho dữ liệu Việt Nam.

🏗️ Kiến trúc — Bài 4 Bảng PERSON — Quản lý danh tính bệnh nhân OMOP CDM 5.4 cho Người mới — Hiểu từ A đến Z Phần 2: Person & Visit — Nền tảng dữ liệu xdev.asia

PERSON — trung tâm của OMOP CDM, kết nối tất cả bảng lâm sàng

Giới thiệu

PERSON là bảng trung tâm của toàn bộ OMOP CDM — mọi bảng clinical đều tham chiếu đến PERSON qua person_id. Đây là nơi lưu trữ thông tin nhân khẩu học (demographics) của bệnh nhân.

Mỗi dòng trong PERSON = một bệnh nhân duy nhất (unique person).


1. Cấu trúc bảng PERSON

1.1. Danh sách cột đầy đủ

CộtKiểuBắt buộcMô tả
person_idINTEGER✅ PKID duy nhất cho mỗi bệnh nhân
gender_concept_idINTEGER✅Giới tính (Standard Concept)
year_of_birthINTEGER✅Năm sinh
month_of_birthINTEGERTháng sinh
day_of_birthINTEGERNgày sinh
birth_datetimeDATETIMENgày giờ sinh đầy đủ
race_concept_idINTEGER✅Chủng tộc (Standard Concept)
ethnicity_concept_idINTEGER✅Dân tộc (Standard Concept)
location_idINTEGERFKĐịa chỉ (tham chiếu LOCATION)
provider_idINTEGERFKBác sĩ chính (tham chiếu PROVIDER)
care_site_idINTEGERFKCơ sở y tế (tham chiếu CARE_SITE)
person_source_valueVARCHAR(50)Mã bệnh nhân gốc từ HIS
gender_source_valueVARCHAR(50)Giới tính gốc (VD: "Nu", "F")
gender_source_concept_idINTEGERConcept ID giới tính gốc
race_source_valueVARCHAR(50)Chủng tộc gốc
race_source_concept_idINTEGERConcept ID chủng tộc gốc
ethnicity_source_valueVARCHAR(50)Dân tộc gốc
ethnicity_source_concept_idINTEGERConcept ID dân tộc gốc

1.2. Entity-Relationship

  ┌──────────────┐       ┌──────────────┐       ┌──────────────┐
  │   LOCATION   │←──────│    PERSON    │──────→│   PROVIDER   │
  │ location_id  │       │  person_id   │       │ provider_id  │
  │ address_1    │       │  gender_*    │       │ provider_name│
  │ city         │       │  birth_*     │       │ specialty_*  │
  │ state        │       │  race_*      │       └──────────────┘
  │ zip          │       │  ethnicity_* │              ↑
  │ country_*    │       │  location_id │              │
  └──────────────┘       │  provider_id │       ┌──────┴───────┐
                         │  care_site_id│──────→│  CARE_SITE   │
                         └──────┬───────┘       │ care_site_id │
                                │               │ care_site_name│
                    ┌───────────┼───────────┐   └──────────────┘
                    ↓           ↓           ↓
             VISIT_OCC.    CONDITION    DRUG_EXPOSURE
             OBSERVATION   MEASUREMENT  ... (tất cả clinical)

2. Các trường quan trọng chi tiết

2.1. person_id

  • Kiểu: INTEGER, Primary Key
  • Quy tắc: Duy nhất, không thay đổi, không có ý nghĩa lâm sàng
  • Không phải mã bệnh nhân gốc (mã BN gốc lưu ở person_source_value)
-- ĐÚNG: person_id là số tự tăng hoặc hash
person_id = 100001
person_source_value = 'BN-2024-00123'  -- Mã gốc từ HIS

-- SAI: Không dùng mã gốc làm person_id
-- person_id = 'BN-2024-00123'  ← SAI (phải là INTEGER)

2.2. gender_concept_id

Concept IDConcept NameMô tả
8507MaleNam
8532FemaleNữ
8551UNKNOWNKhông rõ
8521OTHERKhác
-- Ví dụ ETL cho dữ liệu Việt Nam
CASE
    WHEN gioi_tinh IN ('Nam', 'M', '1') THEN 8507    -- Male
    WHEN gioi_tinh IN ('Nữ', 'Nu', 'F', '2') THEN 8532  -- Female
    ELSE 8551  -- UNKNOWN
END AS gender_concept_id,
gioi_tinh AS gender_source_value

2.3. year_of_birth, month_of_birth, day_of_birth

  • year_of_birth: Bắt buộc — nếu không có, không nạp bệnh nhân
  • month_of_birth, day_of_birth: Tùy chọn — đặt NULL nếu không có
  • birth_datetime: Tùy chọn — hữu ích cho nhi khoa (tính tuổi chính xác)
-- Ví dụ: BN sinh ngày 15/03/1980
year_of_birth  = 1980
month_of_birth = 3
day_of_birth   = 15
birth_datetime = '1980-03-15 00:00:00'

2.4. race_concept_id và ethnicity_concept_id

Đây là 2 trường theo chuẩn US Census. Cho dữ liệu Việt Nam:

TrườngKhuyến nghị cho VN
race_concept_id8515 (Asian)
race_source_value"Kinh", "Tày", "Mường"...
ethnicity_concept_id0 (No matching concept)
ethnicity_source_valueGhi dân tộc gốc nếu có

Lưu ý: race và ethnicity trong OMOP theo chuẩn Mỹ (OMB). Khi ETL dữ liệu VN, ta vẫn phải đặt giá trị (dùng 0 nếu không map được) nhưng giữ thông tin gốc ở *_source_value.


3. Ví dụ thực tế

3.1. Bệnh nhân Việt Nam

INSERT INTO person VALUES (
    100001,                    -- person_id
    8532,                      -- gender_concept_id (Female)
    1980,                      -- year_of_birth
    3,                         -- month_of_birth
    15,                        -- day_of_birth
    '1980-03-15 00:00:00',     -- birth_datetime
    8515,                      -- race_concept_id (Asian)
    0,                         -- ethnicity_concept_id (N/A)
    1001,                      -- location_id (→ LOCATION table)
    5001,                      -- provider_id (→ PROVIDER table)
    2001,                      -- care_site_id (→ CARE_SITE table)
    'BN-2024-00123',           -- person_source_value
    'Nữ',                      -- gender_source_value
    0,                         -- gender_source_concept_id
    'Kinh',                    -- race_source_value
    0,                         -- race_source_concept_id
    NULL,                      -- ethnicity_source_value
    0                          -- ethnicity_source_concept_id
);

3.2. SQL truy vấn cơ bản

-- Đếm bệnh nhân theo giới tính
SELECT
    c.concept_name AS gender,
    COUNT(*) AS patient_count
FROM person p
JOIN concept c ON p.gender_concept_id = c.concept_id
GROUP BY c.concept_name;

-- Phân bố tuổi
SELECT
    EXTRACT(YEAR FROM CURRENT_DATE) - year_of_birth AS age,
    COUNT(*) AS count
FROM person
GROUP BY 1
ORDER BY 1;

-- Tìm bệnh nhân có dữ liệu gốc
SELECT
    person_id,
    person_source_value AS ma_bn_goc,
    gender_source_value AS gioi_tinh_goc,
    race_source_value AS dan_toc
FROM person
WHERE person_source_value IS NOT NULL
LIMIT 10;

4. ETL Conventions

4.1. Quy tắc quan trọng

Quy tắcChi tiết
1 person = 1 recordKhông trùng lặp, cần deduplicate
year_of_birth bắt buộcBỏ qua BN nếu không có năm sinh
gender_concept_id bắt buộcĐặt 8551 (UNKNOWN) nếu không rõ
person_id không mang ý nghĩaĐừng dùng mã BN gốc hoặc CMND/CCCD
Không lưu PII trực tiếpKhông có cột tên, CMND, sdt trong PERSON

4.2. De-identification (Khử danh)

OMOP CDM không có cột tên, số CMND/CCCD, số điện thoại. Đây là thiết kế có chủ đích:

  HIS gốc (có PII):                    OMOP CDM (de-identified):
  ┌─────────────────────────┐          ┌──────────────────────────┐
  │ ma_bn: BN-2024-00123    │    →     │ person_id: 100001        │
  │ ho_ten: Nguyễn Thị Lan  │    →     │ (không có cột tên!)      │
  │ cmnd: 079123456789      │    →     │ (không có cột CMND!)     │
  │ sdt: 0901234567         │    →     │ (không có cột SĐT!)     │
  │ ngay_sinh: 15/03/1980   │    →     │ year_of_birth: 1980      │
  │ gioi_tinh: Nữ           │    →     │ gender_concept_id: 8532  │
  └─────────────────────────┘          └──────────────────────────┘

Lưu ý: person_source_value có thể chứa mã BN gốc (để truy vết). Tùy tổ chức có thể hash hoặc mã hóa giá trị này.

4.3. Xử lý trùng lặp

Khi bệnh nhân có ≥2 mã ở nhiều hệ thống:

  HIS BV Chợ Rẫy: BN-CR-001   ┐
  HIS BV Bạch Mai: BN-BM-555   ├──→ person_id = 100001
  BHXH: DN-7900123456789        ┘    (1 person duy nhất)

ETL cần thực hiện Patient Matching (khớp bệnh nhân) trước khi nạp vào PERSON.


5. Mối quan hệ với các bảng khác

-- Tất cả dữ liệu lâm sàng của 1 bệnh nhân
SELECT 'Visits' AS data_type, COUNT(*) AS count
FROM visit_occurrence WHERE person_id = 100001
UNION ALL
SELECT 'Conditions', COUNT(*)
FROM condition_occurrence WHERE person_id = 100001
UNION ALL
SELECT 'Drugs', COUNT(*)
FROM drug_exposure WHERE person_id = 100001
UNION ALL
SELECT 'Measurements', COUNT(*)
FROM measurement WHERE person_id = 100001
UNION ALL
SELECT 'Observations', COUNT(*)
FROM observation WHERE person_id = 100001;

6. Các lỗi ETL thường gặp

LỗiHậu quảCách khắc phục
Trùng person_idGhi đè dữ liệuKiểm tra unique constraint
year_of_birth = NULLVi phạm NOT NULLBỏ qua hoặc impute
gender_concept_id saiPhân tích sai giới tínhMapping chính xác
Để PII vào source_valueVi phạm de-identificationHash hoặc loại bỏ
Không deduplicate1 BN thành nhiều personPatient matching trước ETL

Tổng kết

  1. PERSON là bảng trung tâm — mọi bảng clinical tham chiếu qua person_id
  2. Trường bắt buộc: person_id, gender_concept_id, year_of_birth, race_concept_id, ethnicity_concept_id
  3. Không chứa PII (tên, CMND, SĐT) — thiết kế de-identified
  4. Liên kết: LOCATION (địa chỉ), CARE_SITE (cơ sở), PROVIDER (bác sĩ chính)
  5. ETL VN: gender mapping, race = Asian (8515), ethnicity = 0

Bài tiếp theo: OBSERVATION_PERIOD — tại sao cần biết "khoảng thời gian theo dõi" và cách nó ảnh hưởng đến mọi phân tích.


Tài liệu tham khảo