Database Schema - Laboratory Master Data
โครงสร้างตารางฐานข้อมูลสำหรับระบบ Master Data ห้องปฏิบัติการ
📊 ภาพรวม Tables
erDiagram
lab_categories ||--o{ lab_items : "categorizes"
specimen_types ||--o{ lab_items : "requires"
container_types ||--o{ lab_items : "uses"
lab_items ||--o{ lab_panel_items : "includes"
lab_panels ||--o{ lab_panel_items : "contains"
lab_items ||--o{ lab_normal_ranges : "has"
lab_items ||--o{ lab_critical_values : "has"
lab_items ||--o{ lab_item_coverage : "covered_by"
eligibility_schemes ||--o{ lab_item_coverage : "provides"
1. lab_categories (หมวดหมู่รายการตรวจ)
จัดกลุ่มรายการตรวจตามประเภท เช่น โลหิตวิทยา, เคมีคลินิก, จุลชีววิทยา
Schema
CREATE TABLE lab_categories (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสหมวดหมู่ (HEMA, CHEM, MICRO)',
name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อภาษาไทย',
name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อภาษาอังกฤษ',
color VARCHAR(20) DEFAULT NULL COMMENT 'สีแสดงผล (Hex Color Code)',
display_order INT UNSIGNED DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน (0=ไม่ใช้งาน, 1=ใช้งาน)',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL COMMENT 'ผู้สร้างข้อมูล (User ID)',
updated_by VARCHAR(50) DEFAULT NULL COMMENT 'ผู้แก้ไขข้อมูลล่าสุด',
INDEX idx_code (code),
INDEX idx_active (is_active),
INDEX idx_display_order (display_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='หมวดหมู่รายการตรวจ Lab';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| code | VARCHAR(20) | NO | รหัสหมวดหมู่ (HEMA, CHEM, MICRO) - UNIQUE |
| name_th | VARCHAR(255) | NO | ชื่อภาษาไทย |
| name_en | VARCHAR(255) | NO | ชื่อภาษาอังกฤษ |
| color | VARCHAR(20) | YES | สีแสดงผล (Hex #RRGGBB) |
| display_order | INT UNSIGNED | NO | ลำดับการแสดงผล (0=แรกสุด) |
| is_active | TINYINT(1) | NO | สถานะการใช้งาน (1=ใช้งาน, 0=ไม่ใช้งาน) |
| created_at | DATETIME | NO | วันเวลาที่สร้าง |
| updated_at | DATETIME | NO | วันเวลาที่แก้ไขล่าสุด |
| created_by | VARCHAR(50) | YES | ผู้สร้างข้อมูล |
| updated_by | VARCHAR(50) | YES | ผู้แก้ไขข้อมูล |
Business Rules
codeต้อง UNIQUE และเป็น uppercasedisplay_orderใช้สำหรับจัดเรียงใน UI (เรียงจากน้อยไปมาก)colorเก็บเป็น Hex color code (#0d9488) สำหรับแสดงใน UI- ไม่ควรลบข้อมูลจริง ให้ใช้
is_active = 0แทน
2. specimen_types (ประเภทสิ่งส่งตรวจ)
ประเภทของสิ่งส่งตรวจที่รับตรวจ เช่น เลือด, ปัสสาวะ, อุจจาระ
Schema
CREATE TABLE specimen_types (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสประเภทสิ่งส่งตรวจ (BLOOD, URINE)',
name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อภาษาไทย',
name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อภาษาอังกฤษ',
description TEXT DEFAULT NULL COMMENT 'คำอธิบาย/วิธีเก็บตัวอย่าง',
display_order INT UNSIGNED DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL,
updated_by VARCHAR(50) DEFAULT NULL,
INDEX idx_code (code),
INDEX idx_active (is_active),
INDEX idx_display_order (display_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ประเภทสิ่งส่งตรวจ';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| code | VARCHAR(20) | NO | รหัสประเภท (BLOOD, URINE, STOOL) - UNIQUE |
| name_th | VARCHAR(255) | NO | ชื่อภาษาไทย (เลือด, ปัสสาวะ) |
| name_en | VARCHAR(255) | NO | ชื่อภาษาอังกฤษ (Blood, Urine) |
| description | TEXT | YES | คำอธิบาย/วิธีเก็บตัวอย่าง |
| display_order | INT UNSIGNED | NO | ลำดับการแสดงผล |
| is_active | TINYINT(1) | NO | สถานะการใช้งาน |
| created_at | DATETIME | NO | วันเวลาที่สร้าง |
| updated_at | DATETIME | NO | วันเวลาที่แก้ไขล่าสุด |
| created_by | VARCHAR(50) | YES | ผู้สร้างข้อมูล |
| updated_by | VARCHAR(50) | YES | ผู้แก้ไขข้อมูล |
Business Rules
codeต้อง UNIQUE และเป็น uppercasedescriptionใช้บันทึกวิธีการเก็บตัวอย่าง/ข้อควรระวัง
3. container_types (ประเภทหลอด/ภาชนะ)
ประเภทหลอดหรือภาชนะที่ใช้เก็บสิ่งส่งตรวจ เช่น EDTA, Plain, Fluoride
Schema
CREATE TABLE container_types (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสประเภทหลอด (EDTA, PLAIN)',
name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อภาษาไทย',
name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อภาษาอังกฤษ',
color VARCHAR(20) DEFAULT NULL COMMENT 'สีจุกหลอด (Hex Color)',
description TEXT DEFAULT NULL COMMENT 'คำอธิบาย/สารกันเลือดแข็ง',
display_order INT UNSIGNED DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL,
updated_by VARCHAR(50) DEFAULT NULL,
INDEX idx_code (code),
INDEX idx_active (is_active),
INDEX idx_display_order (display_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ประเภทหลอด/ภาชนะเก็บตัวอย่าง';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| code | VARCHAR(20) | NO | รหัสประเภทหลอด (EDTA, PLAIN, FLUORIDE) - UNIQUE |
| name_th | VARCHAR(255) | NO | ชื่อภาษาไทย (จุกม่วง EDTA) |
| name_en | VARCHAR(255) | NO | ชื่อภาษาอังกฤษ (EDTA Tube) |
| color | VARCHAR(20) | YES | สีจุกหลอด (Hex #6B46C1) |
| description | TEXT | YES | คำอธิบาย/สารกันเลือดแข็ง |
| display_order | INT UNSIGNED | NO | ลำดับการแสดงผล |
| is_active | TINYINT(1) | NO | สถานะการใช้งาน |
| created_at | DATETIME | NO | วันเวลาที่สร้าง |
| updated_at | DATETIME | NO | วันเวลาที่แก้ไขล่าสุด |
| created_by | VARCHAR(50) | YES | ผู้สร้างข้อมูล |
| updated_by | VARCHAR(50) | YES | ผู้แก้ไขข้อมูล |
Business Rules
codeต้อง UNIQUE และเป็น uppercasecolorเก็บสีจุกหลอดจริง (Purple=#6B46C1, Red=#DC2626)descriptionบันทึกชนิดสารกันเลือดแข็ง (Anticoagulant)
4. lab_items (รายการตรวจ Lab)
รายการตรวจ Lab แต่ละรายการ รองรับทั้ง In-house และ Out Lab
Schema
CREATE TABLE lab_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
lab_code VARCHAR(50) NOT NULL UNIQUE COMMENT 'รหัสรายการตรวจ (CBC, FBS)',
tmlt_code VARCHAR(20) DEFAULT NULL COMMENT 'รหัส TMLT (Thai Medical Lab Test Code)',
loinc_code VARCHAR(20) DEFAULT NULL COMMENT 'รหัส LOINC (International Standard)',
lab_name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อรายการตรวจภาษาไทย',
lab_name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อรายการตรวจภาษาอังกฤษ',
-- จัดหมวดหมู่
category_id BIGINT UNSIGNED DEFAULT NULL COMMENT 'หมวดหมู่ (FK: lab_categories.id)',
specimen_type_id BIGINT UNSIGNED DEFAULT NULL COMMENT 'ประเภทสิ่งส่งตรวจ (FK: specimen_types.id)',
container_type_id BIGINT UNSIGNED DEFAULT NULL COMMENT 'ประเภทหลอด (FK: container_types.id)',
-- ข้อมูลทั่วไป
specimen_volume DECIMAL(10,2) DEFAULT NULL COMMENT 'ปริมาณสิ่งส่งตรวจที่ต้องการ (ml)',
unit VARCHAR(50) DEFAULT NULL COMMENT 'หน่วยของผลตรวจ (mg/dL, mmol/L)',
default_value VARCHAR(100) DEFAULT NULL COMMENT 'ค่าพื้นฐาน (ค่ามาตรฐาน)',
method TEXT DEFAULT NULL COMMENT 'วิธีการตรวจ',
turn_around_time INT UNSIGNED DEFAULT NULL COMMENT 'ระยะเวลาออกผล (นาที)',
-- ราคา
price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'ราคาขาย (บาท)',
service_category_code VARCHAR(50) DEFAULT NULL COMMENT 'หมวดหมู่ค่าบริการ (เชื่อมโยงระบบการเงิน)',
cost DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'ต้นทุน (บาท)',
-- Out Lab Support
is_out_lab TINYINT(1) DEFAULT 0 COMMENT 'เป็น Out Lab หรือไม่ (0=In-house, 1=Out Lab)',
out_lab_name VARCHAR(255) DEFAULT NULL COMMENT 'ชื่อห้อง Lab ภายนอก',
out_lab_code VARCHAR(50) DEFAULT NULL COMMENT 'รหัสรายการของ Out Lab',
out_lab_cost DECIMAL(10,2) DEFAULT NULL COMMENT 'ค่าใช้จ่ายจริงที่จ่ายให้ Out Lab',
-- สถานะ
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
display_order INT UNSIGNED DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
-- Audit
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL,
updated_by VARCHAR(50) DEFAULT NULL,
-- Indexes
INDEX idx_lab_code (lab_code),
INDEX idx_category (category_id),
INDEX idx_specimen_type (specimen_type_id),
INDEX idx_container_type (container_type_id),
INDEX idx_is_out_lab (is_out_lab),
INDEX idx_active (is_active),
INDEX idx_display_order (display_order),
-- Foreign Keys
CONSTRAINT fk_lab_item_category
FOREIGN KEY (category_id) REFERENCES lab_categories(id)
ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_lab_item_specimen
FOREIGN KEY (specimen_type_id) REFERENCES specimen_types(id)
ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_lab_item_container
FOREIGN KEY (container_type_id) REFERENCES container_types(id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='รายการตรวจ Lab';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| lab_code | VARCHAR(50) | NO | รหัสรายการตรวจ - UNIQUE |
| tmlt_code | VARCHAR(20) | YES | รหัส TMLT (ไทย) |
| loinc_code | VARCHAR(20) | YES | รหัส LOINC (สากล) |
| lab_name_th | VARCHAR(255) | NO | ชื่อรายการตรวจภาษาไทย |
| lab_name_en | VARCHAR(255) | NO | ชื่อรายการตรวจภาษาอังกฤษ |
| category_id | BIGINT UNSIGNED | YES | FK → lab_categories |
| specimen_type_id | BIGINT UNSIGNED | YES | FK → specimen_types |
| container_type_id | BIGINT UNSIGNED | YES | FK → container_types |
| specimen_volume | DECIMAL(10,2) | YES | ปริมาณสิ่งส่งตรวจ (ml) |
| unit | VARCHAR(50) | YES | หน่วยของผลตรวจ (mg/dL, mmol/L) |
| default_value | VARCHAR(100) | YES | ค่าพื้นฐาน (ค่ามาตรฐาน) |
| method | TEXT | YES | วิธีการตรวจ |
| turn_around_time | INT UNSIGNED | YES | ระยะเวลาออกผล (นาที) |
| price | DECIMAL(10,2) | NO | ราคาขาย (บาท) |
| service_category_code | VARCHAR(50) | YES | หมวดหมู่ค่าบริการ (เชื่อมโยงระบบการเงิน) |
| cost | DECIMAL(10,2) | NO | ต้นทุน (บาท) |
| unit | VARCHAR(50) | YES | หน่วยของผลตรวจ |
| method | TEXT | YES | วิธีการตรวจ |
| turn_around_time | INT UNSIGNED | YES | ระยะเวลาออกผล (นาที) |
| price | DECIMAL(10,2) | NO | ราคาขาย (บาท) |
| cost | DECIMAL(10,2) | NO | ต้นทุน (บาท) |
| is_out_lab | TINYINT(1) | NO | เป็น Out Lab หรือไม่ (0/1) |
| out_lab_name | VARCHAR(255) | YES | ชื่อห้อง Lab ภายนอก |
| out_lab_code | VARCHAR(50) | YES | รหัสรายการของ Out Lab |
| out_lab_cost | DECIMAL(10,2) | YES | ค่าใช้จ่ายจ่ายให้ Out Lab |
| is_active | TINYINT(1) | NO | สถานะการใช้งาน |
| display_order | INT UNSIGNED | NO | ลำดับการแสดงผล |
Business Rules
lab_codeต้อง UNIQUE และเป็น uppercase- ถ้า
is_out_lab = 1ต้องระบุout_lab_nameและout_lab_cost price≥cost(ป้องกันขายขาดทุน)out_lab_costคือราคาที่จ่ายให้ Out Lab (ต้นทุนจริง)turn_around_timeเป็นนาที (480 = 8 ชั่วโมง)
5. lab_panels (กลุ่มรายการตรวจ / Profiles)
กลุ่มรายการตรวจที่มักสั่งร่วมกัน (Panel/Profile) เช่น CBC + ESR, Lipid Profile
Schema
CREATE TABLE lab_panels (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
panel_code VARCHAR(50) NOT NULL UNIQUE COMMENT 'รหัส Panel (LFT, RFT)',
panel_name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อ Panel ภาษาไทย',
panel_name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อ Panel ภาษาอังกฤษ',
description TEXT DEFAULT NULL COMMENT 'คำอธิบาย/ข้อบ่งชี้',
-- ราคา
price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'ราคาขาย Panel (บาท)',
cost DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'ต้นทุนรวม (คำนวณจาก items)',
-- สถานะ
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
display_order INT UNSIGNED DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
-- Audit
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL,
updated_by VARCHAR(50) DEFAULT NULL,
-- Indexes
INDEX idx_panel_code (panel_code),
INDEX idx_active (is_active),
INDEX idx_display_order (display_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='กลุ่มรายการตรวจ (Lab Panels)';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| panel_code | VARCHAR(50) | NO | รหัส Panel - UNIQUE |
| panel_name_th | VARCHAR(255) | NO | ชื่อ Panel ภาษาไทย |
| panel_name_en | VARCHAR(255) | NO | ชื่อ Panel ภาษาอังกฤษ |
| description | TEXT | YES | คำอธิบาย/ข้อบ่งชี้ |
| price | DECIMAL(10,2) | NO | ราคาขาย Panel |
| cost | DECIMAL(10,2) | NO | ต้นทุนรวม |
| is_active | TINYINT(1) | NO | สถานะการใช้งาน |
| display_order | INT UNSIGNED | NO | ลำดับการแสดงผล |
Business Rules
panel_codeต้อง UNIQUE และเป็น uppercasepriceควรต่ำกว่าผลรวมราคา items แยก (เพื่อจูงใจให้สั่ง Panel)costคำนวณจากผลรวม cost ของ items ใน Panel- Panel อาจมีทั้ง In-house และ Out Lab items ปนกัน
6. lab_panel_items (รายการตรวจใน Panel)
Junction Table เชื่อมระหว่าง lab_panels และ lab_items (Many-to-Many)
Schema
CREATE TABLE lab_panel_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
panel_id BIGINT UNSIGNED NOT NULL COMMENT 'FK: lab_panels.id',
lab_item_id BIGINT UNSIGNED NOT NULL COMMENT 'FK: lab_items.id',
display_order INT UNSIGNED DEFAULT 0 COMMENT 'ลำดับการแสดงผลใน Panel',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Indexes
INDEX idx_panel (panel_id),
INDEX idx_lab_item (lab_item_id),
UNIQUE KEY uk_panel_item (panel_id, lab_item_id),
-- Foreign Keys
CONSTRAINT fk_panel_item_panel
FOREIGN KEY (panel_id) REFERENCES lab_panels(id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_panel_item_lab
FOREIGN KEY (lab_item_id) REFERENCES lab_items(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='รายการตรวจใน Panel (Junction Table)';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| panel_id | BIGINT UNSIGNED | NO | FK → lab_panels |
| lab_item_id | BIGINT UNSIGNED | NO | FK → lab_items |
| display_order | INT UNSIGNED | NO | ลำดับการแสดงผลใน Panel |
| created_at | DATETIME | NO | วันเวลาที่สร้าง |
Business Rules
(panel_id, lab_item_id)ต้อง UNIQUE (ห้ามมี item ซ้ำใน panel เดียวกัน)ON DELETE CASCADE: ลบ Panel → ลบ items ใน Paneldisplay_orderใช้จัดเรียงรายการใน Panel UI
7. lab_normal_ranges (ค่าปกติตามอายุ/เพศ)
เก็บค่าปกติของแต่ละรายการตรวจ แยกตามอายุ/เพศ
Schema
CREATE TABLE lab_normal_ranges (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
lab_item_id BIGINT UNSIGNED NOT NULL COMMENT 'FK: lab_items.id',
-- ช่วงอายุ (เก็บเป็นวัน)
age_min_days INT UNSIGNED DEFAULT NULL COMMENT 'อายุต่ำสุด (วัน) NULL=ไม่จำกัด',
age_max_days INT UNSIGNED DEFAULT NULL COMMENT 'อายุสูงสุด (วัน) NULL=ไม่จำกัด',
-- เพศ
gender ENUM('M', 'F', 'ALL') DEFAULT 'ALL' COMMENT 'เพศ (M=ชาย, F=หญิง, ALL=ทั้งหมด)',
-- ประเภทค่าปกติ
range_type ENUM('NUMERIC', 'TEXT', 'POSSIBLE_VALUES') NOT NULL DEFAULT 'NUMERIC'
COMMENT 'ประเภท (NUMERIC=ตัวเลข, TEXT=ข้อความ, POSSIBLE_VALUES=เลือกค่า)',
-- ค่าปกติ (ตัวเลข)
min_value DECIMAL(15,4) DEFAULT NULL COMMENT 'ค่าต่ำสุด (สำหรับ NUMERIC)',
max_value DECIMAL(15,4) DEFAULT NULL COMMENT 'ค่าสูงสุด (สำหรับ NUMERIC)',
-- ค่าปกติ (ข้อความ)
text_value TEXT DEFAULT NULL COMMENT 'ค่าปกติแบบข้อความ (สำหรับ TEXT)',
possible_values TEXT DEFAULT NULL COMMENT 'ค่าที่เป็นไปได้ (JSON array สำหรับ POSSIBLE_VALUES)',
-- Audit
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL,
updated_by VARCHAR(50) DEFAULT NULL,
-- Indexes
INDEX idx_lab_item (lab_item_id),
INDEX idx_age_range (age_min_days, age_max_days),
INDEX idx_gender (gender),
-- Foreign Keys
CONSTRAINT fk_normal_range_lab_item
FOREIGN KEY (lab_item_id) REFERENCES lab_items(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ค่าปกติตามอายุ/เพศ';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| lab_item_id | BIGINT UNSIGNED | NO | FK → lab_items |
| age_min_days | INT UNSIGNED | YES | อายุต่ำสุด (วัน) NULL=ไม่จำกัด |
| age_max_days | INT UNSIGNED | YES | อายุสูงสุด (วัน) NULL=ไม่จำกัด |
| gender | ENUM | NO | เพศ (M/F/ALL) |
| range_type | ENUM | NO | ประเภท (NUMERIC/TEXT/POSSIBLE_VALUES) |
| min_value | DECIMAL(15,4) | YES | ค่าต่ำสุด (NUMERIC) |
| max_value | DECIMAL(15,4) | YES | ค่าสูงสุด (NUMERIC) |
| text_value | TEXT | YES | ค่าปกติข้อความ (TEXT) |
| possible_values | TEXT | YES | ค่าที่เป็นไปได้ JSON (POSSIBLE_VALUES) |
Business Rules
- อายุเก็บเป็นวัน (days) เพื่อความแม่นยำ (1 ปี = 365 วัน)
- NULL ใน age_min_days = ไม่จำกัดอายุขั้นต่ำ
- NULL ใน age_max_days = ไม่จำกัดอายุสูงสุด
range_type = NUMERIC: ใช้ min_value, max_valuerange_type = TEXT: ใช้ text_value (เช่น "Negative")range_type = POSSIBLE_VALUES: ใช้ possible_values (JSON array)
ตัวอย่าง Age Ranges
| Age Description | age_min_days | age_max_days |
|---|---|---|
| ทารก 0-1 ปี | 0 | 365 |
| เด็ก 1-12 ปี | 366 | 4380 |
| วัยรุ่น 13-18 ปี | 4745 | 6570 |
| ผู้ใหญ่ ≥18 ปี | 6571 | NULL |
| ทุกอายุ | NULL | NULL |
8. lab_critical_values (ค่าวิกฤต)
เก็บค่าวิกฤต (Critical/Panic Values) ที่ต้องแจ้งแพทย์ทันที
Schema
CREATE TABLE lab_critical_values (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
lab_item_id BIGINT UNSIGNED NOT NULL COMMENT 'FK: lab_items.id',
-- ค่าวิกฤต (Critical)
critical_low DECIMAL(15,4) DEFAULT NULL COMMENT 'ค่าต่ำวิกฤต (Critical Low)',
critical_high DECIMAL(15,4) DEFAULT NULL COMMENT 'ค่าสูงวิกฤต (Critical High)',
-- ค่าวิกฤตฉุกเฉิน (Panic)
panic_low DECIMAL(15,4) DEFAULT NULL COMMENT 'ค่าต่ำฉุกเฉิน (Panic Low)',
panic_high DECIMAL(15,4) DEFAULT NULL COMMENT 'ค่าสูงฉุกเฉิน (Panic High)',
-- การแจ้งเตือน
alert_message TEXT DEFAULT NULL COMMENT 'ข้อความแจ้งเตือนเมื่อพบค่าวิกฤต',
action_required TEXT DEFAULT NULL COMMENT 'การปฏิบัติที่ต้องทำ',
notify_immediately TINYINT(1) DEFAULT 1 COMMENT 'แจ้งแพทย์ทันที (0=ไม่ต้อง, 1=ต้องแจ้ง)',
-- Audit
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL,
updated_by VARCHAR(50) DEFAULT NULL,
-- Indexes
INDEX idx_lab_item (lab_item_id),
UNIQUE KEY uk_lab_item (lab_item_id),
-- Foreign Keys
CONSTRAINT fk_critical_value_lab_item
FOREIGN KEY (lab_item_id) REFERENCES lab_items(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ค่าวิกฤต (Critical/Panic Values)';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| lab_item_id | BIGINT UNSIGNED | NO | FK → lab_items (UNIQUE) |
| critical_low | DECIMAL(15,4) | YES | ค่าต่ำวิกฤต |
| critical_high | DECIMAL(15,4) | YES | ค่าสูงวิกฤต |
| panic_low | DECIMAL(15,4) | YES | ค่าต่ำฉุกเฉิน |
| panic_high | DECIMAL(15,4) | YES | ค่าสูงฉุกเฉิน |
| alert_message | TEXT | YES | ข้อความแจ้งเตือน |
| action_required | TEXT | YES | การปฏิบัติที่ต้องทำ |
| notify_immediately | TINYINT(1) | NO | แจ้งแพทย์ทันที |
Business Rules
lab_item_idต้อง UNIQUE (1 รายการตรวจ = 1 ชุดค่าวิกฤต)- Critical: ค่าที่ผิดปกติมาก ต้องติดตามเร่งด่วน
- Panic: ค่าที่อันตรายถึงชีวิต ต้องแจ้งแพทย์ทันที
- Logic:
panic_low < critical_low < normal < critical_high < panic_high notify_immediately = 1: ระบบต้องส่ง alert ไปหาแพทย์ทันที
ตัวอย่างค่าวิกฤต
| รายการ | Critical Low | Critical High | Panic Low | Panic High |
|---|---|---|---|---|
| Glucose | 50 | 400 | 40 | 500 |
| Potassium | 2.8 | 5.5 | 2.5 | 6.0 |
| Hemoglobin | 7.0 | 18.0 | 5.0 | 20.0 |
9. lab_item_coverage (ความครอบคลุมสิทธิ์)
เก็บความครอบคลุมรายการตรวจ Lab กับสิทธิการรักษา (ราคา, ค่าร่วมจ่าย, PA)
Schema
CREATE TABLE lab_item_coverage (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-- Lab Item Reference
lab_item_id VARCHAR(50) NOT NULL COMMENT 'รหัสรายการตรวจ Lab (FK: lab_items.lab_code)',
lab_item_name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อรายการตรวจภาษาไทย (Auto-fetch)',
lab_item_name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อรายการตรวจภาษาอังกฤษ (Auto-fetch)',
-- Eligibility Reference
eligibility_code VARCHAR(20) NOT NULL COMMENT 'รหัสสิทธิ (UC, SSO, CSMBS, PRIVATE, CASH, LGO)',
eligibility_name_th VARCHAR(255) NOT NULL COMMENT 'ชื่อสิทธิภาษาไทย (Auto-fetch)',
eligibility_name_en VARCHAR(255) NOT NULL COMMENT 'ชื่อสิทธิภาษาอังกฤษ (Auto-fetch)',
-- Coverage Details
coverage_status ENUM('covered', 'not_covered', 'prior_auth_required') DEFAULT 'covered'
COMMENT 'สถานะความคุ้มครอง',
price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'ราคารายการตรวจสำหรับสิทธินี้ (บาท)',
-- Copay Options
copay_amount DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'ค่าร่วมจ่ายคงที่ (บาท)',
copay_percent DECIMAL(5,2) NOT NULL DEFAULT 0.00 COMMENT 'ค่าร่วมจ่ายเป็นเปอร์เซ็นต์ (%)',
-- Prior Authorization
requires_prior_auth TINYINT(1) DEFAULT 0 COMMENT 'ต้องขออนุมัติก่อน (PA)',
prior_auth_criteria TEXT DEFAULT NULL COMMENT 'เกณฑ์การขออนุมัติ PA',
-- Limits
max_times_per_year INT UNSIGNED DEFAULT NULL COMMENT 'จำนวนครั้งสูงสุดต่อปี (NULL=ไม่จำกัด)',
notes TEXT DEFAULT NULL COMMENT 'หมายเหตุเพิ่มเติม',
-- Effective Period
effective_date DATE DEFAULT NULL COMMENT 'วันที่เริ่มใช้งาน',
expiry_date DATE DEFAULT NULL COMMENT 'วันที่หมดอายุ (NULL=ไม่หมดอายุ)',
-- Status
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
-- Audit
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by VARCHAR(50) DEFAULT NULL COMMENT 'ผู้สร้างข้อมูล',
updated_by VARCHAR(50) DEFAULT NULL COMMENT 'ผู้แก้ไขข้อมูล',
-- Indexes
UNIQUE KEY uk_lab_eligibility (lab_item_id, eligibility_code),
INDEX idx_lab_item (lab_item_id),
INDEX idx_eligibility (eligibility_code),
INDEX idx_coverage_status (coverage_status),
INDEX idx_prior_auth (requires_prior_auth),
INDEX idx_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='ความครอบคลุมรายการตรวจ Lab กับสิทธิการรักษา';
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
| id | BIGINT UNSIGNED | NO | Primary Key |
| lab_item_id | VARCHAR(50) | NO | รหัสรายการตรวจ Lab (FK to lab_items.lab_code) |
| lab_item_name_th | VARCHAR(255) | NO | ชื่อรายการตรวจภาษาไทย (Auto-populated) |
| lab_item_name_en | VARCHAR(255) | NO | ชื่อรายการตรวจภาษาอังกฤษ (Auto-populated) |
| eligibility_code | VARCHAR(20) | NO | รหัสสิทธิ (UC, SSO, CSMBS, PRIVATE, CASH, LGO) |
| eligibility_name_th | VARCHAR(255) | NO | ชื่อสิทธิภาษาไทย (Auto-populated) |
| eligibility_name_en | VARCHAR(255) | NO | ชื่อสิทธิภาษาอังกฤษ (Auto-populated) |
| coverage_status | ENUM | NO | สถานะความคุ้มครอง (covered/not_covered/prior_auth_required) |
| price | DECIMAL(10,2) | NO | ราคารายการตรวจสำหรับสิทธินี้ (บาท) |
| copay_amount | DECIMAL(10,2) | NO | ค่าร่วมจ่ายคงที่ (บาท) |
| copay_percent | DECIMAL(5,2) | NO | ค่าร่วมจ่ายเป็นเปอร์เซ็นต์ (0-100%) |
| requires_prior_auth | TINYINT(1) | NO | ต้องขออนุมัติก่อน (PA) |
| prior_auth_criteria | TEXT | YES | เกณฑ์การขออนุมัติ PA |
| max_times_per_year | INT UNSIGNED | YES | จำนวนครั้งสูงสุดต่อปี (NULL=ไม่จำกัด) |
| notes | TEXT | YES | หมายเหตุเพิ่มเติม |
| effective_date | DATE | YES | วันที่เริ่มใช้งาน |
| expiry_date | DATE | YES | วันที่หมดอายุ (NULL=ไม่หมดอายุ) |
| is_active | TINYINT(1) | NO | สถานะการใช้งาน |
Business Rules
- Unique Constraint:
(lab_item_id, eligibility_code)ต้อง UNIQUE - Coverage Status:
covered: คุ้มครอง ตัดสิทธิได้เลยnot_covered: ไม่คุ้มครอง ผู้ป่วยจ่ายเต็มprior_auth_required: ต้องขออนุมัติก่อน (PA)- Price Calculation: ราคาที่ผู้ป่วยจ่าย =
price × (copay_percent/100) + copay_amount - Prior Authorization: ถ้า
requires_prior_auth = 1→ แพทย์ต้องขออนุมัติก่อน - Annual Limits:
max_times_per_year= จำกัดครั้ง, NULL = ไม่จำกัด - Auto-Populated: ชื่อ Lab Item และชื่อสิทธิ ดึงมาจาก master data อัตโนมัติ
ตัวอย่างข้อมูล
UC (บัตรทอง) - คุ้มครองเต็ม
INSERT INTO lab_item_coverage (
lab_item_id, lab_item_name_th, eligibility_code, eligibility_name_th,
coverage_status, price, copay_amount, copay_percent
) VALUES
('L081051', 'นับเม็ดเลือดขาว WBC', 'UC', 'สิทธิ UC บัตรทอง', 'covered', 50.00, 0.00, 0.00),
('L082001', 'น้ำตาลในเลือด FBS', 'UC', 'สิทธิ UC บัตรทอง', 'covered', 60.00, 0.00, 0.00);
SSO (ประกันสังคม) - มีค่าร่วมจ่าย 30 บาท
INSERT INTO lab_item_coverage (
lab_item_id, lab_item_name_th, eligibility_code, eligibility_name_th,
coverage_status, price, copay_amount, copay_percent
) VALUES
('L081051', 'นับเม็ดเลือดขาว WBC', 'SSO', 'สิทธิประกันสังคม SSO', 'covered', 50.00, 30.00, 0.00),
('L082001', 'น้ำตาลในเลือด FBS', 'SSO', 'สิทธิประกันสังคม SSO', 'covered', 60.00, 30.00, 0.00);
CSMBS (ข้าราชการ) - ต้องขออนุมัติ PA
INSERT INTO lab_item_coverage (
lab_item_id, lab_item_name_th, eligibility_code, eligibility_name_th,
coverage_status, price, requires_prior_auth, prior_auth_criteria
) VALUES
('L082015', 'HbA1C', 'CSMBS', 'สิทธิข้าราชการ CSMBS', 'prior_auth_required', 300.00, 1,
'ต้องมี HbA1C > 7% หรือมีประวัติโรคเบาหวาน');
Integration with Other Tables
-- ดึงข้อมูล Lab Item + Coverage สำหรับสิทธิ UC
SELECT
li.lab_code,
li.lab_name_th,
lc.coverage_status,
lc.price,
lc.copay_amount,
lc.requires_prior_auth
FROM lab_items li
LEFT JOIN lab_item_coverage lc
ON li.lab_code = lc.lab_item_id
AND lc.eligibility_code = 'UC'
WHERE li.is_active = 1 AND lc.is_active = 1;
🔐 Security & Performance
Indexes Strategy
- Primary Keys: ทุก table มี AUTO_INCREMENT id
- Unique Keys: code fields ทั้งหมด (lab_code, panel_code, etc.)
- Foreign Keys: เพื่อ referential integrity
- Search Indexes: code, name_th, is_active
- Composite Indexes: (panel_id, lab_item_id) ใน junction table
Data Integrity
- Foreign Key Constraints: ป้องกัน orphaned records
- ON DELETE CASCADE: Junction tables (lab_panel_items)
- ON DELETE SET NULL: Optional references (category_id, specimen_type_id)
- CHECK Constraints: (เพิ่มได้ในอนาคตสำหรับ price >= cost)
Backup Strategy
- Daily Full Backup: ทุกวัน 00:00
- Hourly Incremental: ระหว่างวัน
- Retention: เก็บ 30 วัน
Next: ดู RELATIONSHIPS.md สำหรับ ERD และความสัมพันธ์ระหว่าง Tables