Mine

รูปภาพของฉัน
หาดใหญ่, ภาคใต้, Thailand
ชอบเอาใจ แต่ก็เอาแต่ใจ

วันพฤหัสบดีที่ 17 มิถุนายน พ.ศ. 2553

ช่วงบน และช่วงล่าง ของความดันแยกจากกันได้มั้ย

สวัสดีค่ะ ...
เนื่องจากมีเสียงสมาชิก Hospital OS สอบถามมาหลายเสียง เรื่อง "การหาค่า บน และ ค่าล่าง ของความดัน" ทำอย่างไร เช่น 120/80 ต้องการทราบว่าค่าบน คือ 120 ส่วนค่าล่างคือ 80 จะทำได้อย่างไร เพราะความจริงแล้วเราไม่สามารถระบุได้ว่าค่าบนจะเป็น 3 หลักเสมอไป เพราะผู้ป่วยบาง case อาจจะมี 2 หลักก็เป็นได้ เช่น 82/59

ซึ่งตรงนี้คิดว่า คนที่ไม่ถามก็อาจจะอยากรู้ หรือ คนที่ได้บอกไปแล้ว ก็อาจจะได้มาทำความเข้าใจกันค่ะ

มาดูกันเลยค่ะ ...

ถ้าเรามองข้อมูลกันให้ดีๆ จะเห็นว่าเป็น Pattern เดียวกันค่ะ
120/80
82/59

จะเห็นว่าข้อมูลที่จัดเก็บนั้น จะคั่นค่าชั้นบน กับค่าชั้นล่าง ด้วย "/"
เราสามารถนำ "/" มาช่วยในการตัดข้อมูลแยกจากกันได้ค่ะ
แต่ว่า เราจะทราบได้อย่างไรว่าตำแหน่งของ "/" จะอยู่ที่ไหนกันแน่

ก่อนอื่นมาทบทวนกันก่อนค่ะ เรื่อง String ใน PostgreSQL
การนับ String หรือ สายอักษร เราจะเริ่มนับที่ 1 ค่ะ เช่น 120/80
1 -> นับเป็นตำแหน่งที่ 1
2 -> นับเป็นตำแหน่งที่ 2
0 -> นับเป็นตำแหน่งที่ 3
/ -> นับเป็นตำแหน่งที่ 4
8 -> นับเป็นตำแหน่งที่ 5
0 -> นับเป็นตำแหน่งที่ 6

ขอนำเสนอคำสั่ง position ซึ่งเป็นคำสั่งในการหาตำแหน่งของคำที่เรากำหนดค่ะ
รูปแบบคำสั่ง
position('[คำที่เราต้องการหาตำแหน่ง]' in [ชื่อ Filed ที่เราต้องการให้หาตำแหน่งของคำ])
จะแสดงผลลัพธ์เป็น
จะแสดงค่าตำแหน่งของคำที่ค้นหา
ถ้าพบ -> จะแสดงตำแหน่งโดยเริ่มนับจาก 1
ถ้าไม่พบ -> จะแสดงเลข 0
ตัวอย่าง จากข้อมูลความดัน
120/80
82/59
คำสั่งที่เขียน(ขออ้างอิงตารางของ HOspital OS)
select
visit_vital_sign_blood_presure --ข้อมูลที่เก็บในฐานข้อมูล
, position('/' in visit_vital_sign_blood_presure) --แสดงตำแหน่งของ "/" ที่หาพบในข้อมูล
from t_visit_vital_sign
ผลลัพธ์
120/80    4
82/59    3

เมื่อเราได้ตำแหน่งของ "/" ตามที่ต้องการแล้ว มาดูกันต่อว่าเราจะนำมาใช้งานได้อย่างไร

เราจำคำสั่ง substring ได้หรือเปล่าคะ ยังไงก็มาดูก็แล้วกัน
รูปแบบคำสั่ง1 
substring([ชื่อ Filed ที่เราต้องการตัด],[ตำแหน่งเริ่มต้นของการตัด],[จำนวนที่เราต้องการตัด])
จะแสดงผลลัพธ์เป็น
แสดงอักษรจากจุดที่เริ่มตัด นับไปเท่ากับจำนวนที่เรากำหนด
ตัวอย่าง จากข้อมูลความดัน
120/80
82/59
คำสั่งที่เขียน(ขออ้างอิงตารางของ HOspital OS)
select
visit_vital_sign_blood_presure --ข้อมูลที่เก็บในฐานข้อมูล
, substring(visit_vital_sign_blood_presure,1,3) --แสดงข้อมูลที่ต้องการตัด ตำแหน่งที่ 1 นับไป 3 ตัว
from t_visit_vital_sign
ผลลัพธ์
120/80    120
82/59    82/

รูปแบบคำสั่ง2
substring([ชื่อ Filed ที่เราต้องการตัด],[ตำแหน่งเริ่มต้นของการตัด])
จะแสดงผลลัพธ์เป็น
แสดงอักษรจากจุดที่เริ่มตัดไปจนสิ้นสุดอักขระของ String นั้น
ตัวอย่าง จากข้อมูลความดัน
120/80
82/59
คำสั่งที่เขียน(ขออ้างอิงตารางของ HOspital OS)
select
visit_vital_sign_blood_presure --ข้อมูลที่เก็บในฐานข้อมูล
, substring(visit_vital_sign_blood_presure,5) --แสดงข้อมูลที่ต้องการตัด ตำแหน่งที่ 5 เป็นต้นไป
from t_visit_vital_sign
ผลลัพธ์
120/80    80
82/59    9

เราเรียนรู้คำสั่งในการตัด String แล้วแต่เราก็ยังไม่สามารถนำมาใช้โดยตรงได้ค่ะ เพราะจากลักษณะของข้อมูลแล้วมีความเป็นไปได้ตามข้อมูลตัวอย่างข้างต้น เมื่อเรากับหนดค่าที่ตัดลงไปแบบ Fixed เราก็จะได้ผลลัพธ์ที่ไม่ถูกต้องค่ะ เราต้องนำความรู้มาผสมผสานให้เกิดสิ่งที่เราต้องการให้ได้ นั่นคือ การนำ position เข้ามาเป็นส่วนหนึ่งของการตัด String ถ้าเราสังเกตุตัวอย่าง จะเห็นว่า

ลองสันนิฐานดูว่า
จากตัวอย่างข้อมูลความดัน 120/80   
เราต้องการตัด string 3 หลักแรก คือ substring(visit_vital_sign_blood_presure,1,3)
ค่า position ของ "/" คือ 4  
เป็นไปได้หรือไม่ว่า จำนวนที่เราต้องการ คือ position-1 นั่นคือ 4-1 = 3

จากตัวอย่างข้อมูลความดัน 82/59   
เราต้องการตัด string 2 หลักแรก คือ substring(visit_vital_sign_blood_presure,1,2)
ค่า position ของ "/" คือ 3  
เป็นไปได้หรือไม่ว่า จำนวนที่เราต้องการ คือ position-1 นั่นคือ 3-1 = 2

ดังนั้น จากข้อสันนิฐาน เราก็นำมาพิสูจน์กันค่ะ ลองเขียนคำสั่งที่นำมาผสมผสานกันดูนะคะ
จะได้เป็น
select visit_vital_sign_blood_presure --ค่าในฐานข้อมูล
, position('/' in visit_vital_sign_blood_presure) --ตำแหน่งของ "/"
, substring(visit_vital_sign_blood_presure,1,(position('/' in visit_vital_sign_blood_presure)) -1) --ค่าความดันช่วงบน
from t_visit_vital_sign
where visit_vital_sign_blood_presure <> '' --ป้องกันค่าว่าง เพราะจะทำให้เกิด Error ได้ค่ะ
จะได้ผลลัพธ์เป็น
120/80    120
82/59    82

แล้วลองดูผลลัพธ์ที่เครื่องคุณนะคะ ว่าได้ผลที่ถูกต้องหรือเปล่า

ค่ะ อั้นนั้นมันเป็นเรื่องของเบื้องบน เราลองมาดูเบื้องล่างกันบ้างนะคะ
ลองสันนิฐานดูว่า
จากตัวอย่างข้อมูลความดัน 120/80   
เราต้องการตัด string หลังจาก "/" ทั้งหมด คือ substring(visit_vital_sign_blood_presure,5)
ค่า position ของ "/" คือ 4  
เป็นไปได้หรือไม่ว่า จุดเริ่มต้นที่เราต้องการ คือ position+1 นั่นคือ 4+1 = 5

จากตัวอย่างข้อมูลความดัน 82/59   
เราต้องการตัด string หลังจาก "/" ทั้งหมด คือ substring(visit_vital_sign_blood_presure,4)
ค่า position ของ "/" คือ 3  
เป็นไปได้หรือไม่ว่า จุดเริ่มต้นที่เราต้องการ คือ position+1 นั่นคือ 3+1 = 4

ดังนั้น จากข้อสันนิฐาน เราก็นำมาพิสูจน์กันค่ะ ลองเขียนคำสั่งที่นำมาผสมผสานกันดูนะคะ
จะได้เป็น
select visit_vital_sign_blood_presure --ค่าในฐานข้อมูล
, position('/' in visit_vital_sign_blood_presure) --ตำแหน่งของ "/"
, substring(visit_vital_sign_blood_presure,(position('/' in visit_vital_sign_blood_presure)) +1) --ค่าความดันช่วงล่าง
from t_visit_vital_sign
where visit_vital_sign_blood_presure <> '' --ป้องกันค่าว่าง เพราะจะทำให้เกิด Error ได้ค่ะ
จะได้ผลลัพธ์เป็น
120/80    80
82/59    59

ไหนๆ ก็ทำแล้วก็ลองเอามารวมกันเลยค่ะ จะได้รันทีเดียวได้ ทั้งช่วงบนช่วงล่าง
ตามนี้
select visit_vital_sign_blood_presure
, substring(visit_vital_sign_blood_presure,1,(position('/' in visit_vital_sign_blood_presure)) -1) --ค่าความดันช่วงบน
, substring(visit_vital_sign_blood_presure,(position('/' in visit_vital_sign_blood_presure)) +1) --ค่าความดันช่วงล่าง
from t_visit_vital_sign where visit_vital_sign_blood_presure <> ''

ค่ะ ถึงตอนนี้ก็อยู่ที่ว่าจะนำไปใช้ทำอะไรแล้วค่ะ ไม่ว่าจะเป็น
- ผู้ป่วยที่มีความดัน เกิน 140 มีใครบ้าง อะไรประมาณนี้

อ่อ...แล้วก็ ไม่จำเป็นว่าคำสั่งต่างๆที่เราใช้จะต้องอยู่ใน select นะคะ เพราะถ้าเรานำไปเป็นเงื่อนไขก็ต้องนำไปอยู่ที่ where ... ได้เช่นเดียวกัน ที่ยกตัวอย่างขึ้นมาเพื่อให้แสดงผลออกมาให้เห็นนะคะ

เอาเป็นว่าวันนี้ก็พอก่อนนะคะ เดี๋ยวมีคำถามก็ฝากไว้ได้ค่ะ และหวังว่าจะเกิดกับโยชน์กับทุกคนที่สนใจค่ะ หรือมีอะไรชี้แนะก็ส่งมาได้เสมอค่ะ

วันเสาร์ที่ 12 มิถุนายน พ.ศ. 2553

เรามาเขียนรายงานจากฐานข้อมูล 18 แฟ้ม กันดีกว่า ตอนที่2

555 ในที่สุดก็เดือนละ 1 ครั้ง เฮ้ยยยยย... ขออภัยอย่างแรงค่ะ

งั้นเริ่มเลยนะ ความเดิม
"ทำความเข้าใจกันก่อนดีกว่าว่า 18 แฟ้ม คือข้อมูลอะไรบ้าง และ เราจะจัดการข้อมูลให้เป็นชุดเดียวกันได้อย่างไร มีรูปแบบข้อมูลเป็นอย่างไร ก็เชิงการวิเคราะห์อะค่ะ ไม่ยาก แต่ค่อนข้างละเอียดอ่อน"

จากที่เคยกล่าวไว้เรื่องการจัดการชุดข้อมูลเดียวกัน ตอนนี้เราลองหยิบเอกสาร 18 แฟ้ม จาก file Structure2553_1_0_7.pdf(อ้างอิง: http://www.nhso.go.th/op)

เมื่อเราได้เอกสารชุดเดียวกันแล้ว มาตรฐานข้อมูลที่เราจะกล่าวถึงก็จะเป็นข้อมูลชุดเดียวกันแล้วค่ะ งั้นพร้อมแล้วก็มาทำความเข้าใจกันเลยค่ะ เอาแบบคุยกันง่ายๆ ไม่ทางการนะคะ
1. 18 แฟ้ม คือข้อมูลอะไรบ้าง
ให้อ่านรายละเอียดของแฟ้มทั้งหมดดูว่าเข้าใจว่าอย่างไร เหมือนกับที่จะสรุปหรือไม่
ตามความหมายของแต่ละแฟ้มแยกกลุ่มข้อมูลได้ ดังนี้
- ข้อมูลพื้นฐานประชากร หรือข้อมูลทั่วไปของประชากร
PERSON, DEATH, CHRONIC, SURVEIL, WOMAN, HOME
- ข้อมูลหลักประกันสุขภาพ
PERSON, CARD
- ข้อมูลการเข้ารับบริการ
PERSON, SERVICE, DIAG,PROCED,APPOINT,DRUG
- ข้อมูลส่งเสริมป้องกัน
PERSON, SERVICE,EPI,NUTRI, FP, ANC, PP, MCH
2. การจัดการข้อมูล 18 แฟ้ม
2.1 เราได้ข้อมูลมาในรูปแบบใด
ในที่นี้ก็คงจะยึดมาตรฐานจากที่ทางส่วนกลางกำหนดไปเลยนะคะ เป็น Text File รูปแบบอ้างอิงจากเอกสาร Structure2553_1_0_7.pdf
2.2 เราจะจัดเก็บข้อมูลมูลไว้ที่ไหนดี
เมื่อเราทราบว่าข้อมูลที่เรามีในมือนั้นเป็น Text File แล้วเราจะเอาไว้ที่ไหนดี อันนี้แนะนำให้เก็บอยู่ในฐานข้อมูลค่ะ ซึ่งตรงนี้ขอยกตัวอย่างเป็น PostgreSQL แล้วกันค่ะ เป็น Open Source ที่ดีค่ะ สำหรับท่านอื่นๆ จะใช้ฐานข้อมูลอะไรก็ได้นะคะ
2.3 เราได้ข้อมูลมาบ่อยแค่ไหน ซ้ำซ้อนหรือไม่
อันนี้ก็คาดว่า 1 เดือนเราก็คง Query ข้อมูลมา 1 ครั้ง หรือแล้วแต่ว่าจะมีกรณีแก้ไขข้อมูลแล้วนำเข้ามาใหม่หรือไม่ อันนั้นก็ไม่ว่ากันค่ะ บ่อยแค่ไหนไม่ค่อยสำคัญมากนัก แต่ข้อมูลยังไงเราก็ไม่สามารถการันตีได้ว่าจะไม่ซ้ำซ้อนกัน ดังนั้น เราก็ต้องมีขั้นตอนที่จะตรวจสอบความซ้ำซ้อนของข้อมูลให้ได้ และจะจัดการกับข้อมูลเหล่านั้นอย่างไร ให้เหมาะสม
2.4 เราต้องจัดการกับข้อมูลใน CUP ด้วยหรือไม่
ยากเข้าไปอีกขั้น เพราะเราไม่สามารถควบคุมข้อมูลได้ แต่ก็สามารถทำได้ค่ะ ต้องทำความเข้าใจร่วมกันก่อนว่าข้อมูลทั้งหมดจะนำมาวิเคราะห์ร่วมกัน ดังนั้น Key ที่ใช้เป็นตัวบ่งชี้ถึงบุคคล หรือประชากรคนเดียวกันที่สำคัญ คือ เลขบัตรประชาชน แต่เราไม่ได้ วิเคราะห์ข้อมูลที่เป็นคนไทยอย่างเดียว ดังนั้น เราจำเป็นจะต้องมีข้อมูลอื่นร่วมด้วย ที่จริงแล้วเคยได้มีโอกาสเข้าร่วมประชุมค่ะ

ตรงนี้ทางหน่วยงานที่เกี่ยวข้องกับข้อมูลต่างด้าวก็พยาบามที่จะให้สร้างเลข 13 หลักของคนต่างด้าวขึ้นมา ถ้าเกิดขึ้นมาเหมือนกับที่ให้เลข 13 หลักของคนไทยก็น่าจะนำมาใช้ได้ค่ะ แต่ไม่แน่ใจว่าเลขที่ให้ Gen ขึ้นมานั้น หาก นาย ก ชาวพม่า ไปรับบริการ 2 หน่วยบริการจะได้เลขเดียวกันหรือไม่ (อันนี้ก็ค่อยหาทางออกอีกทีนะคะ 555 ด้วยอะไรหลายๆอย่างทำให้ไม่สะดวกค่ะ) สรุปคือว่า เอาคนไทยก่อนนะ เอาไว้ว่างๆจะหาทางให้ละกัน

งั้นเรามาสร้างโครงสร้างรองรับกับข้อมูลกันดีกว่าค่ะ
จากเอกสารที่เรานำมาอ้างอิง อย่างน้อยที่สุดนั้นเราจะต้องมีตารางข้อมูลเท่ากับจำนวนแฟ้มค่ะ แต่ส่วนที่ต้องเพิ่มขึ้นมาเพื่อให้อธิบายรหัสต่างๆของข้อมูล จะต้องดูว่าแต่ละแฟ้มมีรหัสอ้างอิงไปยังข้อมูลอะไรบ้าง ยกตัวอย่างเช่น เราหยิบแฟ้ม PERSON ขึ้นมา เราจะได้ตาราง ดังนี้
1. ตาราง person
    เพื่อเก็บข้อมูลประชากร
2. ตาราง address
    เพื่อเก็บข้อมูลรหัสของ ตำบล อำเภอ จังหวัด ตามมาตรฐานของกรมการปกครอง
3. ตาราง mstatus
    เก็บสถานภาพสมรส
4. ตาราง occupation
    เก็บรหัสอาชีพ
5. ตาราง race
    รหัสเชื้อชาติมาตรฐานตามกรมการปกครอง
6. ตาราง nation
    รหัสสัญชาติมาตรฐานตามกรมการปกครอง
7. ตาราง religion
    รหัศาสนาสมาตรฐาน สำนักนโยบายและยุทธศาสตร์
8. ตาราง education
    รหัสการศึกษามาตรฐาน สำนักนโยบายและยุทธศาสตร์
9. ตาราง fstatus
    สถานะในครอบครัว
10. ตาราง discharge_status
    สถานะสาเหตุการจำหน่าย
11. ตาราง blood_group
    หมู่เลือด
12. ตาราง labor
    รหัสความเป็นคนต่างด้าว
13. ตาราง typearea
     สถานะบุคคล

จะเห็นว่าเพียง 1 แฟ้มทำให้เรามีงานทำเพื่อสร้างตารางถึง 13 ตารางค่ะ แต่เราก็ต้องดูว่ารหัสนี้ใช้กับแฟ้มอื่นด้วยหรือเปล่าถ้าใช้ก็ไม่ต้องสร้างซ้ำซ้อนค่ะ

งั้นมาทำตามขั้นตอนค่ะ
1. สร้างฐานข้อมูล 1 ฐาน
ตัวอย่าง คำสั่ง
createdb -E unicode dataset_18files -U postgres
เท่านี้เราก็ได้ฐานข้อมูลเปล่ามา 1 ฐานชื่อ dataset_18files
สำหรับฐานข้อมูลอื่นๆ ก็สามารถสร้างตามสะดวกค่ะ หรือแม่แต่ PostgreSQL ก็ใช้ Tool สร้างก็ได้นะคะ หากไม่ถนัด Command
2. สร้างตารางที่เรา List เอาไว้
ตัวอย่าง คำสั่ง
CREATE TABLE blood_group (
    stdcode    varchar(255) NOT NULL,
    description    varchar(255) NULL,
    PRIMARY KEY(stdcode,description)
);
จะได้ตารางชื่อ blood_group
ประกอบด้วย 2 Field คือ stdcode,description
โดยมี Key หลักคือ stdcode
* โดยส่วนใหญ่แล้วถ้ากรณีรหัสมาตรฐานก็น่าจะมีอย่างน้อย 2 Field คือ รหัส และ รายละเอียดคำอธิบาย
3. นำข้อมูลรหัสมาตรฐาน เข้าไปยังตารางที่สร้างไว้
หากเป็นข้อมูลรหัสมาตรฐานจะคงที่ไม่มีการเปลี่ยนแปลง กรณีเปลี่ยนแปลง เช่น เมื่อมีการปรับปรุงรหัสข้อมูลใหม่ นั่นหมายถึงการเปลี่ยน Data Dictionary นั่นเอง เราควรจัดการให้เนียนกว่าการมาเปลี่ยนรหัสโดยตรงค่ะ เพราะจะกระทบกับข้อมูลเดิม (ค่อยว่ากันนะคะ ชักยุ่งเหยิง)
ตัวอย่าง คำสั่ง
INSERT INTO blood_group(stdcode, description)
    VALUES('1', 'A');
INSERT INTO blood_group(stdcode, description)
    VALUES('2', 'B');
INSERT INTO blood_group(stdcode, description)
    VALUES('3', 'AB');
INSERT INTO blood_group(stdcode, description)
    VALUES('4', 'O');

เอาไว้ก่อนนะ ไปทำกับข้าวก่อนค่ะ พอดีโกชอว์(สามี)กลับมาแล้วค่ะ
ลองสร้างตารางเล่นๆกันไปก่อนนะคะ หากใครทำเสร็จก่อนก็นำมาเผยแพ่เพื่อช่วยกันตรวจสอบได้ค่ะ

หากไม่แน่ใจ หรือมีคำถามก็แจ้งกันมาได้ค่ะ ... ช่วยกัน