Mối quan hệ giữa Concepts (Maps to, Is a, RxNorm has ingredient...) và cây phân cấp Ancestor-Descendant. Bảng quan trọng nhất cho ETL mapping và phân tích hierarchical.
Giới thiệu
Nếu CONCEPT là "từ điển", thì CONCEPT_RELATIONSHIP là "bản đồ" kết nối các từ lại với nhau, và CONCEPT_ANCESTOR là "cây gia phả" thể hiện quan hệ tổ tiên-hậu duệ. Hai bảng này cực kỳ quan trọng: CONCEPT_RELATIONSHIP dùng cho ETL (mapping ICD-10 → SNOMED), CONCEPT_ANCESTOR dùng cho phân tích (tìm tất cả mã "tiểu đường" bao gồm type 1, type 2, gestational...).
-- Tìm Standard Concept từ ICD-10 code
SELECT
c1.concept_code AS source_code,
c1.concept_name AS source_name,
c1.vocabulary_id AS source_vocab,
cr.relationship_id,
c2.concept_id AS standard_concept_id,
c2.concept_name AS standard_name,
c2.vocabulary_id AS standard_vocab,
c2.domain_id
FROM concept c1
JOIN concept_relationship cr
ON c1.concept_id = cr.concept_id_1
AND cr.relationship_id = 'Maps to'
AND cr.invalid_reason IS NULL
JOIN concept c2
ON cr.concept_id_2 = c2.concept_id
AND c2.standard_concept = 'S'
AND c2.invalid_reason IS NULL
WHERE c1.concept_code = 'E11'
AND c1.vocabulary_id = 'ICD10CM';
1.4. "Is a" — Phân cấp SNOMED
Diabetes mellitus (concept_id = 201820)
↑ Is a
├── Type 1 diabetes mellitus (201254)
│ ↑ Is a
│ ├── Type 1 DM without complication (435216)
│ └── Type 1 DM with ketoacidosis (443727)
│
├── Type 2 diabetes mellitus (201826)
│ ↑ Is a
│ ├── Type 2 DM without complication (443732)
│ └── Type 2 DM with peripheral angiopathy (318712)
│
└── Gestational diabetes (4058243)
-- Tìm concept cha trực tiếp
SELECT
c_parent.concept_id,
c_parent.concept_name
FROM concept_relationship cr
JOIN concept c_parent ON cr.concept_id_2 = c_parent.concept_id
WHERE cr.concept_id_1 = 201826 -- Type 2 DM
AND cr.relationship_id = 'Is a'
AND cr.invalid_reason IS NULL;
-- Tìm concept con trực tiếp
SELECT
c_child.concept_id,
c_child.concept_name
FROM concept_relationship cr
JOIN concept c_child ON cr.concept_id_1 = c_child.concept_id
WHERE cr.concept_id_2 = 201826 -- Type 2 DM
AND cr.relationship_id = 'Is a'
AND cr.invalid_reason IS NULL;
2. Bảng RELATIONSHIP
Cột
Kiểu
Mô tả
relationship_id
VARCHAR(20)
PK
relationship_name
VARCHAR(255)
Tên quan hệ
is_hierarchical
VARCHAR(1)
1 = phân cấp
defines_ancestry
VARCHAR(1)
1 = tạo ancestor
reverse_relationship_id
VARCHAR(20)
Quan hệ ngược
relationship_concept_id
INTEGER
FK → concept
3. CONCEPT_ANCESTOR — Cây phân cấp đầy đủ
3.1. Cấu trúc bảng
Cột
Kiểu
Mô tả
ancestor_concept_id
INTEGER
FK → CONCEPT (tổ tiên)
descendant_concept_id
INTEGER
FK → CONCEPT (hậu duệ)
min_levels_of_separation
INTEGER
Khoảng cách tối thiểu
max_levels_of_separation
INTEGER
Khoảng cách tối đa
3.2. So sánh CONCEPT_RELATIONSHIP vs CONCEPT_ANCESTOR
CONCEPT_RELATIONSHIP
CONCEPT_ANCESTOR
Nội dung
Quan hệ trực tiếp
Tất cả tổ tiên-hậu duệ
Ví dụ
Type 2 DM → Is a → DM
Type 2 DM → mọi ancestor
Levels
Chỉ 1 bậc
Bao gồm n bậc
Dùng cho
ETL mapping
Phân tích hierarchical
Includes self
Không
✅ (min_level = 0)
3.3. Tại sao cần CONCEPT_ANCESTOR?
CONCEPT_RELATIONSHIP chỉ có quan hệ "1 bậc". Muốn tìm tất cả loại tiểu đường (type 1, type 2, gestational, neonatal...), phải duyệt cây nhiều lần. CONCEPT_ANCESTOR đã tính sẵn (pre-computed transitive closure).
-- Tìm TẤT CẢ concept thuộc nhóm "Diabetes mellitus"
-- Bao gồm bản thân + mọi hậu duệ
SELECT
ca.descendant_concept_id,
c.concept_name,
ca.min_levels_of_separation AS levels
FROM concept_ancestor ca
JOIN concept c ON ca.descendant_concept_id = c.concept_id
WHERE ca.ancestor_concept_id = 201820 -- Diabetes mellitus
AND c.standard_concept = 'S'
ORDER BY ca.min_levels_of_separation, c.concept_name;
-- Kết quả: ~300+ concepts bao gồm mọi loại & biến chứng
3.4. Ứng dụng phân tích
-- Đếm BN có BẤT KỲ loại tiểu đường nào
SELECT COUNT(DISTINCT co.person_id) AS dm_patients
FROM condition_occurrence co
WHERE co.condition_concept_id IN (
SELECT descendant_concept_id
FROM concept_ancestor
WHERE ancestor_concept_id = 201820 -- Diabetes mellitus
);
-- So sánh: KHÔNG dùng ancestor (chỉ bắt 1 loại)
SELECT COUNT(DISTINCT co.person_id) AS dm_type2_only
FROM condition_occurrence co
WHERE co.condition_concept_id = 201826; -- Chỉ Type 2 DM
-- → Bỏ sót Type 1, gestational, neonatal, with complications...!
4. SOURCE_TO_CONCEPT_MAP — Mapping tùy chỉnh
Dùng khi vocabulary chưa có mapping (VD: mã nội bộ BV Việt Nam).
Cột
Kiểu
Mô tả
source_code
VARCHAR(50)
Mã nguồn
source_concept_id
INTEGER
Concept nguồn (0 nếu chưa có)
source_vocabulary_id
VARCHAR(20)
ID vocabulary tùy chỉnh
source_code_description
VARCHAR(255)
Mô tả
target_concept_id
INTEGER
FK → Standard Concept
target_vocabulary_id
VARCHAR(20)
Vocabulary đích
valid_start_date
DATE
valid_end_date
DATE
invalid_reason
VARCHAR(1)
-- Tạo mapping cho mã ICD-10-VN nội bộ
INSERT INTO source_to_concept_map (
source_code, source_concept_id,
source_vocabulary_id, source_code_description,
target_concept_id, target_vocabulary_id,
valid_start_date, valid_end_date
) VALUES
('E11', 0, 'VN_ICD10',
'Đái tháo đường type 2',
201826, 'SNOMED',
'2024-01-01', '2099-12-31'),
('METFORMIN500', 0, 'VN_DRUG',
'Metformin 500mg viên nén',
1503328, 'RxNorm',
'2024-01-01', '2099-12-31');
5. CONCEPT_SYNONYM — Tên đồng nghĩa
Cột
Kiểu
Mô tả
concept_id
INTEGER
FK → CONCEPT
concept_synonym_name
VARCHAR(1000)
Tên đồng nghĩa
language_concept_id
INTEGER
Ngôn ngữ (4180186 = English)
-- Tìm concept qua tên đồng nghĩa
SELECT DISTINCT c.concept_id, c.concept_name
FROM concept_synonym cs
JOIN concept c ON cs.concept_id = c.concept_id
WHERE LOWER(cs.concept_synonym_name) LIKE '%heart attack%'
AND c.standard_concept = 'S';
-- Tìm được: Acute myocardial infarction