หัวข้อนี้มาจากพี่ชายเราคนนึงอยากคิวรี่ข้อมูล “ผู้ป่วยรายใหม่ของกลุ่มโรคใดๆ ในช่วงระยะเวลา 3 ปี” ก็เลยเขียนบทความนี้ขึ้นมา – disclaimer ก่อนนะครับ ก็คือเราเคยได้มีโอกาสคิวรี่ข้อมูลผู้ป่วยจาก 43 แฟ้มอยู่บ้าง ทำให้คุ้นเคยกับชุดข้อมูลนี้อยู่บ้าง แต่จริงๆ แล้ว ผู้อ่านสามารถนำไปประยุกต์ได้อยู่น้า ไม่ต่างกันมาก
มาเริ่มกันเลย เราจะใช้ชุดข้อมูลจาก Kaggle แทนนะครับ (ตอนนี้เราเข้าไม่สามารถเข้าถึงข้อมูลผู้ป่วยแล้วนะ แล้วก็ยังเป็นข้อมูลอ่อนไหวด้วย ⚖️) เป็นข้อมูล Satria Data 2022 Dataset
เอาไว้ train model ซักอย่าง แต่นั่นไม่ใช้ประเด็น เราต้องการข้อมูลการวินิจฉัยผู้ป่วยด้วยกลุ่มโรคตามมาตรฐาน ICD10 และมีวันที่ที่แพทย์วินิจฉัย ก็น่าจะเพียงพอแล้ว
ทั้งนี้ ขึ้นอยู่กับตัวผู้อ่านนะครับ ว่าจะหา “ครั้งแรก” แยกตามกลุ่มอะไร?
แล้วเราตั้งโจทย์ไว้ว่า “จำนวนผู้ป่วยรายใหม่โรค เบาหวาน แยกตามรหัสกลุ่มโรคในช่วงเวลา 3 ปี” และนี่คือตัวอย่างข้อมูลที่เรามี

โดยมีรายละเอียดคอลัมน์คือ
HN
– หมายเลขประจำตัวผู้ป่วยID
– เป็น PK ของตารางนี้DATEDIAG
– วันที่แพทย์วินิจฉัยโรคDIAGTYPE
– ประเภทโรคที่วินิจัย; PRINCIPLE DX (โรคหลัก), CO-MORBIDITY (โรคร่วม), COMPLICATION (โรคแทรกซ้อน)ICD10GRP
– กลุ่มโรควินิจฉัยICD10
– รหัสโรควินิจฉัยICD10NAME
– ชื่อโรคที่วินิจฉัย
เราต้องลองดึงข้อมูลออกมาดูรูปแบบกันก่อน

จากตารางเราจะเห็นว่า
- HN 10244 มีการวินิจฉัยโรค E11 ทั้งหมด 3 ครั้งในชุดข้อมูลนี้ ซึ่งครั้งแรกก็คือวันที่ 2020-02-27 จะหมายถึงเค้าป่วยครั้งแรกในปี 2020
- HN 23395 มีการวินิจฉัยโรค E11 ทั้งหมด 3 ครั้ง ครั้งแรกก็คือวันที่ 2019-07-22 ซึ่งหมายถึงเค้าป่วยครั้งแรกในปี 2019
- ส่วน 2 บรรทัดแรกมีการวินิจแค่ครั้งเดียว หมายถึงนั่นเป็นวินิจฉัยครั้งแรกของโรค H65 กับ A01
และก็มาถึงการระบุ “บรรทัดแรก” กัน เราจะใช้ฟังก์ชั่น row_number() ใน select clause เพื่อดูว่าแต่ละแถวนั้นอยู่ลำดับที่เท่าไหร่ ตามกลุ่ม (partitionที่เราต้องการ)
row_number() over (partition by col_name(s)
order by col_name1 asc|desc, col_name2 asc|desc) as row_num
มาดูคิวรี่และผลลัพธ์กัน
select
d.datediag,
year(d.datediag) as year_,
d.icd10grp,
d.hn,
row_number() over (partition by d.icd10grp, d.hn order by d.datediag asc) as row_num
from diagnosis d
where d.hn in (23395, 10244) -- ขอกรองมาเฉพาะ 2 คนนี้ก่อนนะครับ ข้อมูลเยอะไม่ไหว
order by d.hn asc, d.datediag asc
row_number() คำสั่งให้แสดงหมายเลขลำดับของแถว โดย..
partition by d.icd10grp, d.hn
-> แบ่งกลุ่มตามกลุ่มโรควินิจฉัย และ HNorder by
d.datediag
asc
-> และจัดเรียงข้อมูลตาม วันที่แพทย์วินิจฉัย
จะได้ข้อมูลออกมาตามตารางนี้

ข้อมูลที่ได้คือ การวินิจฉัยครั้งแรกของผู้ป่วยแต่ละคนแยกตามกลุ่มโรค ก็คือคอลัมน์ rum_num=1
นั่นเอง และเราก็ได้ดึงเฉพาะปีออกมาจากวันที่แพทย์วินิจฉัยเพิ่มด้วยที่คอลัมน์ year_
หมายความว่าในอนาคตเรามีกลุ่มอื่นให้ต้องคำนึงเพิ่มก็สามารถอัดเข้าไปใน partition by
เพิ่มได้ เช่น ต้องการประเภทการวินิจฉัยเพิ่มคิวรี่ก็จะเป็น partition by d.icd10grp, d.hn, d.diagtype
ขั้นต่อไปเราจะมานับจำนวนรวมกัน โดยสมมุติว่าโจทย์ของเราต้องการเฉพาะโรคเบาหวานเท่านั้น ก็จะมีเงื่อนไขที่ต้อง where เพิ่ม นั่นคือ ICD10GRP อยู่ระหว่าง E10-E14
select
dm.year_,
dm.icd10grp,
count(dm.hn) as cnt_pt -- นับจำนวนผู้ป่วย
from (
select
d.datediag,
year(d.datediag) as year_, -- ดึงเอาเฉพาะปี
d.icd10grp,
d.hn,
row_number() over (partition by d.icd10grp, d.hn order by d.datediag asc) as row_num
from diagnosis d
where d.icd10grp between 'E10' and 'E14' -- กรองเฉพาะโรคเบาหวาน
) dm
where dm.row_num = 1 -- เอามาเฉพาะบรรทัดที่เป็นครั้งแรก
group by dm.year_, dm.icd10grp
order by dm.year_ asc, dm.icd10grp asc;
ผลลัพธ์ที่ได้ ดังนี้

เย้! เราได้ผลลัพธ์ที่ต้องการแล้ว จากชุดข้อมูลการวินิจฉัยโรคที่เรามีในระยะเวลา 3 ปี มีจำนวน “จำนวนผู้ป่วยรายใหม่โรค เบาหวาน แยกตามรหัสกลุ่มโรค“ ได้ตามภาพเลยครับโผ้มมม 🚀😎
PS. DB บางเวอร์ชั่นไม่ซัพพอร์ตฟังก์ชันนี้น้า เช็คก่อนเด้อๆ —ของผู้เขียนใช้ MariaDB-10.4.32
และนี่ก็เป็นครั้งแรกที่เขียนบทความจากประสบการณ์ที่เคยได้ใช้มานะครับ ท่านผู้อ่านหากมีคำถามสงสัย ฝากไว้ในช่อง comment ได้เลยนะครับ ถ้าทำเป็นบทความสอนได้ จะมาเขียนเพิ่มครับ
เขียนดี ไม่ดียังไงติชมได้ครับ + แปลผิดแปลถูก + มี typo ขออภัยครับ 🙏 พยายามแล้วครับ
.
ขอบคุณครับ