วันจันทร์, กันยายน 26, 2548

โจทย์ที่ไม่น่ายาก แต่คิดหาที่ทำแล้วเจ๋งๆ ยังไม่เจออ่ะ

สืบเนื่องจากอาทิตย์ก่อน อาจารย์ที่ปรึกษาจาก พ.ร.พ ได้มาเยี่ยมประเมินสภาพความพร้อม เพื่อขอรับการ Accredit แต่ละทีมก็ได้รับคำแนะนำที่เป็นประโยชน์หลายประการ ประเด็นหนึ่งซึ่งเกี่ยวข้องโดยตรงกับผม ซึ่งมีส่วนร่วมในส่วนของ IM และงานบริการในห้องยา เรื่องที่พูดถึงก็คือการลดความซ้ำซ้อนในการคัดลอกคำสั่งแพทย์ในตึกผู้ป่วยใน ปกติแล้วเวลาแพทย์เข้าไปติดตามอาการของผู้ป่วยเพื่อพิจารณาสั่งการรักษาประจำวัน หรือที่เรียกกันในวงการว่า Round Ward จะมีเอกสารที่สำคัญมากอยู่แผ่นนึงคือ Doctor Order (ขนาดประมาณ A4) แบ่งเป็นสองฟากซ้าย ขวา ฟากซ้ายเป็น Order For Oneday อีกฟากหนึ่งเป็น Order Continue (อาจจะพูดมากไปหน่อย เนื่องจาก Blog ของเราอยู่บนเครือข่ายอินเทอร์เน็ต อาจจะมีเพื่อนใหม่ ที่ไม่ได้อยู่ในวงการสาธารณสุข เข้ามาอ่าน จำเป็นต้องพูดให้ละเอียดนิดนึง) เจ้าเอกสารแผ่นนี้สำคัญมาก ชนิดที่ว่าหายไม่ได้ (ความจริงเอกสารเกี่ยวกับผู้ป่วยนี้ก็สำคัญทุกแผ่นนะ) ปกติแล้ว หลังจากแพทย์ Round Ward เสร็จก็จะทำการสั่งการรักษาลงใน Order Doctor หน้าที่ของผมคือ อ่านเจ้า Order Doctor นี้ทุกวัน ทุกรายที่เป็นผู้ป่วยใน เพื่อที่จะบันทึกข้อมูลเหล่านี้ลงใน Hospital OS ส่งรายการไปที่ห้องยาเพื่อจัดยาให้ผู้ที่มาใช้บริการ (เป็นศัพท์ใหม่ที่ควรจะใช้ แทนคำว่าผู้ป่วย หรือ ผู้มารับบริการ ฟังดูแล้วรู้สึกว่าเราเป็นผู้ให้บริการนะ หรูขึ้นไปอีก) พร้อมกับแนบเจ้า Order Doctor ไปด้วยเพื่อที่เภสัชกรจะได้ทำการตรวจสอบว่า รายการที่เบิกมาถูกต้องตามคำสั่งแพทย์จริงๆ หรือปล่าว ก่อนที่จะทำการส่งมอบยากลับมาที่ตึก หรือจ่ายให้ผู้มาใช้บริการกลับไปทานต่อที่บ้าน ทีนี้ปัญหาอยู่ที่ว่าเจ้า Order Doctor นี่ตามหลักการแล้วไม่ควรจะถูกเคลื่อนย้ายออกจากตึก เนื่องจากเหตุผลด้านความปลอดภัย สะดวกในการบันทึกกรณีที่มีเหตุฉุกเฉินต้องรายงานแพทย์ และเป็นการพิทักษ์สิทธิ์ของผู้ป่วยด้วย (การรักษาความลับของผู้ป่วย) โจทย์ที่ผมได้รับคือทำอย่างไรถึงจะไม่ต้องแนบเอกสารนี้ออกไปให้เภสัชกรตรวจสอบ แต่เภสัชกรก็ต้องสามารถที่จะเห็นลายมือแพทย์ได้โดยตรง

โอ จอร์ช มันยอดมากเลย คิดออกอยู่ สองวิธีที่น่าจะเข้าท่า คือ

เสนอความคิดเห็น ผ่านหัวหน้าฝ่ายไปคุยกับ ผู้อำนวยการแล้ว ได้รับโจทย์ให้มาคิดเพิ่มอีกว่า หาวิธีการทำตามแบบที่สองให้หน่อย รู้สีกว่ามันเข้าท่า ไม่ต้องเปลืองกระดาษ ลดความคลาดเคลื่อนในการอ่านลงไป (ข้อนี้หัวหน้าผม กับหัวหน้าตึก ร่วมมือกันไปล๊อบบี้) เกิดว่ากระดาษคาร์บอนเก่าก็จะทำให้สำเนาไม่ชัด ต้องมีการสอบถามกลับอีกเสียเวลา และไม่มีใคร(พยาบาลในตึก) ว่างมากถึงขนาดที่ต้องมานั่งจัดการเรื่องการสอดกระดาษเข้าๆ ออกๆ เตรียมให้คุณ ! แป่ว ไปหาวิธีจัดการให้ได้ เร็วที่สุด ไม่ต้องรอฟีเจอร์ใหม่ของ Hospital OS ทำไปก่อนก็ได้ หากโปรแกรมได้รับการพัฒนาแล้วค่อยว่ากันอีกที

เอ แล้วเราจะจัดการได้อย่างไรดีนะ ให้มันสะดวกทั้งเรา และทั้งเค้า ต้องมีระบบรักษาความปลอดภัยด้วยนะ เพราะนี่คือความลับของผู้ป่วย (ผู้ใช้บริการ แต่ผมมักติดปากเรียกเค้าว่าผู้ป่วยอยู่)


วันอาทิตย์, กันยายน 25, 2548

เวบรีพอร์ต Update 25 กันยายน 2548

เรื่องมีอยู่ว่า พึ่งไปเห็นว่ามีรายงานแสดงสถานะของผู้ป่วยในด้วยว่า ในช่วงเวลาหนึ่งๆ นั้นมี รับใหม่ จำหน่ายไปกี่คน แยกตามสิทธิบัตร ด้วยแต่บังเอิญไปทำให้มันไม่ Active ซะอย่างนั้น (น่าเบิด) ก็เลยเข้าไปดู เออเข้าท่าแฮะ แต่อ่าน SQL แล้วปวดหัวเป็นบ้า ก็เลยทำการโมดิฟายใหม่ เอาให้ (ตัวเอง) อ่านง่ายอีกหน่อยและเพิ่มความสามารถในการแสดงจำนวนวันนอนออกมา และยังสามารถลิงค์ไปดูรายละเอียดของตัวเลขแต่ละค่าที่แสดงออกมาด้วยล่ะ ซึ่งน่าจะทำให้มองภาพรวมได้ชัดเจนขึ้น ในอาทิตย์ที่ผ่านมานั้นเป็นสัปดาห์ในการทำงานที่ค่อนข้างจะเหนื่อย เนื่องจากเป็นอาทิตย์ที่มี คนประจำการห้องยาน้อยกว่าปกติ น้องๆ เค้าไปดุงานกัน ที่จริงแล้วผมก็อยู่ในลิสต์ที่จะได้ไปนะ แต่ขอตัวไม่ไป แล้วอาจารย์ที่ปรึกษามาเยี่ยมด้วย ทำให้ต้องรีบหาผักชีมาโรยกันใหญ่ ผลก็คือยังไม่สามารถขอ Accredit ได้ภายในสิ้นปีนี้ ซึ่งค่อนข้างจะทำให้ทีมงานบางท่าน เข่าอ่อนไปเนื่องจาก มั่นใจว่าน่าจะเข้าตากรรมการ หึหึ ก็ต้อง ICV (เข้ม) ต่อไปอีก วันพฤหัสบดี กับวันศุกร์ที่ผ่านมา อยู่กับหัวหน้าฝ่ายเพียงสองคน (สองคนจริงๆ นะ) คิดดูว่าโรงพยาบาลทั้งโรงพยาบาล มีคนอยู่ในห้องยาเพียงสองคน ข้าวกลางวันไม่ต้องพูดถึงครับ เป็นอะไรที่เหนื่อยมั่กมาก สาธุอย่าให้เจอเหตุการณ์แบบนี้อีกเลยนะ สาบานได้ว่าความเสี่ยงที่เกิดขึ้นน่ะมันมาก ปริมาณงานที่มาก ในขณะที่มีคนทำงานน้อย แล้วต้องทำเกือบทุกอย่าง เพื่อให้การประกันคุณภาพเท่าเดิม ดีที่ไม่มีอุบัติการณ์เกิดขึ้น ก็โชคดีของผู้มาใช้บริการไป

วันจันทร์, กันยายน 19, 2548

เวบรีพอร์ต อัพเดท 19 กันยายน 2548

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


วันเสาร์, กันยายน 17, 2548

เวบรีพอร์ต Update แล้ว (patch level 1)

พึ่งได้รับการ Feed Back จากยูสเซอร์อย่างเป็นเรื่องเป็นราว เมื่อวันศุกร์ที่ผ่านมานี้เองว่า รายงานแสดงสถานะของผู้ป่วยในทั้งหมด นั้นหน่ะยังไม่ถูกใจ ว่างั้น ก็ถามว่าเป็นอย่างไร ต้องการอะไรเพิ่มเติม ก็อายุแสดงไม่ครบอ่ะเด่ มีแต่ ปี ขาด เดือน กะวันไป เพิ่มให้หน่อยแล้วเธอ ก็จากปายยยย

อ๋อได้ จัดให้ จะไปยากอะไร ก็เพียงแต่เปลี่ยนฟังก์ชั่นที่ใช้ในการคำนวณอายุ จาก calage3 เป็น calage2 ซะก็สิ้นเรื่อง เจ้า calage2 นี้ก็ได้รับความอนุเคราะห์จากสุรชัย ต่อวงศ์อีกแล้วเขียนให้ ต้องขอขอบใจในความเอื้ออาทรอีกครั้ง เป็นฟังก์ชั่นที่รับค่าพารามิเตอร์มาสองค่าคือ t_visit.visit_begin_visit_time กับ t_patient.patient_birthday แล้วก็เอาไปคำนวณรีเทอร์นค่าออกมาเป็นเทกซ์ (ปี เดือน วัน) หน้าตาเป็นอย่างนี้ครับ

CREATE OR REPLACE FUNCTION calage2(date, date)
RETURNS text AS
'
DECLARE
mm INTEGER := 0;
dd INTEGER := 0;

y INTEGER := 0;
m INTEGER := 0;
d INTEGER := 0;

age TEXT := \'\';
BEGIN
dd := $1-$2;

IF ( dd>365 OR dd=365 )
THEN
y := dd/365;
ELSE
y := 0;
END IF;

mm := dd-y*365;

IF ( mm>30 OR mm=30 )
THEN
m := mm/30;
ELSE
m := 0;
END IF;

d := mm-m*30;

IF y > 0
THEN
age := y|| \' ปี \';
END IF;

IF m > 0
THEN
age := age||(m|| \' เดือน \');
END IF;

IF d > 0
THEN
age := age||(d|| \' วัน \');
END IF;

IF d = 0
THEN
age := age||(d|| \' วัน \');
END IF;


RETURN age;
END;

'
LANGUAGE 'plpgsql' VOLATILE;

ส่วนวิธีการอัพเดทคือ

เห็นว่าเป็นจุดที่ค่อนข้างสำคัญก็เลยรีบมาบอกกล่าวกันตั้งแต่เนิ่นๆ เพื่อความสะดวกในการเลือกดู เลือกใช้กันน่ะครับ

วันพุธ, กันยายน 14, 2548

เวบรีพอร์ต Update แล้ว

ระหว่างที่นั่งรอดูบอล ลิเวอร์พูล VS รีล เบติส อยู่ก็นึกๆ ว่าน่าจะทำอะไรไปด้วยดี เอาเป็น Web Report ฉบับ Update ไปเผยแพร่เพิ่มเติมดีกว่า เห็นมีเพื่อนสมาชิกบ่นๆ กันว่าไม่ค่อยจะอัพเดทเอาซะเล๊ย เอ่อ คือว่าทำแล้วบ้าง แต่ก็แก้ไปด้วย เนื่องจากทำแล้วไม่ค่อยได้ใช้เองเท่าไหร่ ทีนี้จะถูกหรือจะผิดก็ต้องรอผลการฟีดแบคกลับมาจากผู้ใช้ ซึ่งบางทีเค้าก็ยังไม่ได้ตรวจสอบ จริงจัง บ้าง หรือฟีดแบคกลับมาแล้วแต่ก็ยังทำได้ไม่ถูกใจผู้ใช้บ้าง ก็ค่อนข้างจะเนิ่นนานไป เอาล่ะ ก็มีอยู่หลายรายงานด้วยกันที่น่าจะถูกใจผู้ใช้อยู่ เช่น

วันอังคาร, กันยายน 13, 2548

เรื่องของ SQL ตอนที่ 4

ว่าจะมาเฉลยสิ่งที่เคยถามไว้ว่า ถ้าอยากจะทราบว่าในวันที่ 15 กรกฏาคม 2548 มีผู้ป่วยนอกมารับบริการแยกเพศ ชาย,หญิง,รวม จำแนกตามสิทธิบัตร โดยแสดงสิทธิบัตรออกมาจนครบ ตั้งแต่สุดสัปดาห์ที่ผ่านมาแล้ว แต่ก็มีเหตุให้ต้องเลื่อนเนื่องจากวันเสาร์ - อาทิตย์ที่ผ่านมามีภารกิจที่ต้องทำ (อย่างยิ่งยวด) โดยในวันเสาร์ที่โรงเรียนของลูกสาวมีการจัดแข่งขันกีฬาสี ก็ต้องพาเด็กๆ ไปร่วมงานตั้งแต่เช้า กว่าจะกลับมาถึงบ้านได้ก็บ่ายแก่ๆ อากาศร้อนอบอ้าวมากทั้งๆ ที่เป็นฤดูฝน (แล้วจัดทำไมล่ะ ก็แปลกดี ปกติแล้วกีฬาสีเนี่ยเค้าจัดกันตอนเทอมสองกันทั้งน้าน นี่ยังไม่ปิดเทอมแรกเลย ) เหนื่อยทั้งผู้ปกครองทั้งนักเรียน ทั้งครู กลับมาก็นอนพักกันทั้งบ้าน นอนพักกันจนเย็น เย็นมากจนขี้เกียจไปซะ วันอาทิตย์ก็ต้องไปประชุมเกี่ยวกับพฤติกรรมการบริการ ที่ทางทีมงานพัฒนาทรัพยากรมนุษย์เค้าจัดขึ้นอีก พอกลับมาก็ไฟดับยาวไปถึงตอนดึก ช่วงนี้ไฟดับบ่อยมากทั้งๆ ที่บ้านก็อยู่ใกล้สำนักงานไฟฟ้านะ (เกียวกันด้วยเร๊อะ) เลยเถิดมาถึงวันนี้จนได้

เอาล่ะ เฉลยเลยแล้วกัน ตอนแรกเราก็นับเฉพาะเพศชายก่อนโดย (สีแดงคือสิ่งที่เพิ่มเข้าไป) ตั้งชื่อไว้ก่อนว่า temp1

SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment,t_patient
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit.visit_hn = t_patient.patient_hn
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND t_patient.f_sex_id='1'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description

เมื่อได้เพศชายแล้วก็นับเพศหญิงต่อโดยใช้ SQL ชุดเดียวกันเพียงแต่เปลี่ยน t_patient.f_sex_id จาก 1 เป็น 2 ตั้งชื่อไว้ว่า temp2

SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment,t_patient
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit.visit_hn = t_patient.patient_hn
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND t_patient.f_sex_id='2'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description

แล้วก็นับทั้งหมด (รวมชายและหญิง) ตั้งชื่อเป็น temp3 ดังนี้

SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description

ทีนี้ก็นับสิทธิบัตรทั้งหมดออกมา ตั้งชื่อว่า temp4

SELECT
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
FROM
b_contract_plans

เริ่มการ JOIN โดยการใช้ temp4 เป็นตัวตั้ง แล้วเอา temp1,temp2,temp3 มา JOIN ตามที่ร่างไว้อย่างนี้

SELECT
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,temp1.total AS male
,temp2.total AS female
,temp3.total AS total_all

FROM
(b_contract_plans
LEFT JOIN
(
SQL ชุดที่หนึ่ง
) AS temp1 ON b_contract_plans.contract_plans_number=temp1.contract_plans_number
LEFT JOIN
(
SQL ชุดที่สอง
) AS temp2 ON b_contract_plans.contract_plans_number=temp2.contract_plans_number
LEFT JOIN
(
SQL ชุดที่สาม
) AS temp3 ON b_contract_plans.contract_plans_number=temp3.contract_plans_number
)
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,male
,female
,total_all


เมื่อแทนค่า temp1 , temp2 , temp3 ด้วยชุดคำสั่งแล้วก็จะได้เป็นดังนี้

SELECT
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,temp1.total AS male
,temp2.total AS female
,temp3.total AS total_all
FROM
(b_contract_plans LEFT JOIN
(
SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment,t_patient
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit.visit_hn = t_patient.patient_hn
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_patient.f_sex_id='1'
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
) AS temp1 ON b_contract_plans.contract_plans_number=temp1.contract_plans_number
LEFT JOIN
(
SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment,t_patient
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit.visit_hn = t_patient.patient_hn
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_patient.f_sex_id='2'
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
) AS temp2 ON b_contract_plans.contract_plans_number=temp2.contract_plans_number
LEFT JOIN
(
SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
) AS temp3 ON b_contract_plans.contract_plans_number=temp3.contract_plans_number
)
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,male
,female
,total_all
ORDER BY
b_contract_plans.contract_plans_number

ก็ได้ผลของการคิวรี่ดังนี้
A1     ชำระเงินเอง     1     3     4
A11 ผู้ประสบภัยจากรถ (หลักฐานครบ)
A12 ผู้ประสบภัยจากรถ (หลักฐานไม่ครบ) 3 3
A21 เบิกได้ (ข้าราชการ/ลูกจ้างประจำ) 8 8 16
A22 เบิกได้ (รัฐวิสาหกิจ,ส่วนท้องถิ่น)
A71 บัตรประกันสังคม (คู่สัญญา)
A72 บัตรประกันสังคม (คลอด ชำระเอง)
A73 บัตรประกันสังคม (ญาติสายตรง)
A74 บัตรประกันสังคม (เจ้าหน้าที่โรงพยาบาล) 1 1
A75 บัตรประกันสังคม (ทำฟัน ชำระเอง)
A76 บัตรประกันสังคม (ไม่ใช่คู่สัญญา ชำระเงินเอง) 1 1
AA บัตรทองมี ท (เด็ก 0-5 ปี) 3 3
AA1 บัตรทองมี ท (เด็ก 6-12 ปี) 1 2 3
AB บัตรทองมี ท (ผู้มีรายได้น้อย) 9 14 23
AC บัตรทองมี ท (นักเรียนมัธยมต้น) 2 2 4
AD บัตรทองมี ท (ผู้พิการ) 1 1
AE บัตรทองมี ท (ทหารผ่านศึก) 1 1
AF บัตรทองมี ท (สมณเพศ) 2 2
AG บัตรทองมี ท (ผู้สูงอายุ) 13 14 27
AH บัตรทองมี ท (บัตรชั่วคราว)
AH1 บัตรทองมี ท (พอสว)
AH2 บัตรทองมี ท (นอกเครือข่าย ชำระเงินเอง)
AH3 บัตรทองมี ท (นอกเครือข่ายฉุกเฉิน) 1 1
AH4 บัตรแรงงานต่างด้าว (ในเครือข่าย)
AH5 บัตรแรงงานต่างด้าว (นอกเครือข่าย)
AH6 บัตรทองมี ท (ในเครือข่าย ชำระเงินเอง)
AJ บัตรทองมี ท (ผู้นำชุมชน) 2 2 4
AK1 บัตรทองมี ท (อสม ในเขตอำเภอ) 2 2 4
AK2 บัตรทองมี ท (อสม นอกเขตอำเภอ)
AZ สังคมสงเคราะห์
UC1 บัตรทองเสียค่าธรรมเนียม 12 18 30
UC2 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่าย ชำระเงินเอง) 1 1
UC3 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่ายฉุกเฉิน)
UC4 บัตรทองเสียค่าธรรมเนียม (ในเครือข่าย ชำระเงินเอง)

รู้สึกว่ามันเยิ่นเย้อ มากไปหน่อย ลองดูอีกวิธีดีกว่า ตัด temp2, temp3 ออกไป temp4 คงเดิม แต่ temp1 มีการโมดิฟายเล็กน้อยโดยเอา temp1, temp2, temp3 มารวมกัน อ่า รวมได้ยังงัย เทคนิคนี้เรียกว่า เทคนิคการคิวรี่แบบ Pivot Table ดูกันเล้ย

SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,SUM(CASE when t_patient.f_sex_id = '1' THEN 1 ELSE 0 END) AS male
,SUM(CASE when t_patient.f_sex_id = '2' THEN 1 ELSE 0 END) AS female
,COUNT(t_visit.t_visit_id) AS total

FROM
b_contract_plans,t_visit,t_visit_payment,t_patient
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit.visit_hn = t_patient.patient_hn
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
ORDER BY
b_contract_plans.contract_plans_number

SUM(CASE when t_patient.f_sex_id = '1' THEN 1 ELSE 0 END) AS male

อธิบายนิดนึงครับ ว่าตั้งแต่ CASE ........ไปจนถึง END หมายความว่า..

เมื่อ t_patient.f_sex_id='1' ให้มีค่าเท่ากับ 1 ส่วนค่าอื่นๆ (t_patient.f_sex_id='2') ไม่สนใจให้เป็นศูนย์ ไปจนครบเงื่อนไขตามที่เรา WHERE ไว้ เมื่อครบแล้วก็ให้ SUM ได้เท่าไรเก็บไว้ใน male ส่วนค่า female นั้นก็ให้นับคล้ายๆ กันเพียงแต่บังคับให้นับเฉพาะ t_patient.f_sex_id='2' เท่านั้นให้เป็น 1 บรรทัดสุดท้ายคือ COUNT(t_visit.t_visit_id) ก็คือนับทั้ง t_patient.f_sex_id='1' และ t_patient.f_sex_id='2' เก็บไว้ในค่า total พอได้ temp1 เช่นนี้แล้วก็เอามา JOIN กับ temp4 เหมือนเดิม ได้ดังนี้

SELECT
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,temp1.male AS male
,temp1.female AS female
,temp1.total AS total_all

FROM
(b_contract_plans LEFT JOIN
(
SELECT
b_contract_plans.contract_plans_number AS contract_plans_number
,SUM(CASE when t_patient.f_sex_id = '1' THEN 1 ELSE 0 END) AS male
,SUM(CASE when t_patient.f_sex_id = '2' THEN 1 ELSE 0 END) AS female
,COUNT(t_visit.t_visit_id) AS total

FROM
b_contract_plans,t_visit,t_visit_payment,t_patient
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit.visit_hn = t_patient.patient_hn
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-15' and '2548-07-15')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
ORDER BY
b_contract_plans.contract_plans_number
) AS temp1 ON b_contract_plans.contract_plans_number=temp1.contract_plans_number
)
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,male
,female
,total_all
ORDER BY
b_contract_plans.contract_plans_number
พอลองรันดูก็ได้ผลดังนี้

A1 ชำระเงินเอง 1 3 4
A11 ผู้ประสบภัยจากรถ (หลักฐานครบ)
A12 ผู้ประสบภัยจากรถ (หลักฐานไม่ครบ) 3 3
A21 เบิกได้ (ข้าราชการ/ลูกจ้างประจำ) 8 8 16
A22 เบิกได้ (รัฐวิสาหกิจ,ส่วนท้องถิ่น)
A71 บัตรประกันสังคม (คู่สัญญา)
A72 บัตรประกันสังคม (คลอด ชำระเอง)
A73 บัตรประกันสังคม (ญาติสายตรง)
A74 บัตรประกันสังคม (เจ้าหน้าที่โรงพยาบาล) 1 1
A75 บัตรประกันสังคม (ทำฟัน ชำระเอง)
A76 บัตรประกันสังคม (ไม่ใช่คู่สัญญา ชำระเงินเอง) 1 1
AA บัตรทองมี ท (เด็ก 0-5 ปี) 3 3
AA1 บัตรทองมี ท (เด็ก 6-12 ปี) 1 2 3
AB บัตรทองมี ท (ผู้มีรายได้น้อย) 9 14 23
AC บัตรทองมี ท (นักเรียนมัธยมต้น) 2 2 4
AD บัตรทองมี ท (ผู้พิการ) 1 1
AE บัตรทองมี ท (ทหารผ่านศึก) 1 1
AF บัตรทองมี ท (สมณเพศ) 2 2
AG บัตรทองมี ท (ผู้สูงอายุ) 13 14 27
AH บัตรทองมี ท (บัตรชั่วคราว)
AH1 บัตรทองมี ท (พอสว)
AH2 บัตรทองมี ท (นอกเครือข่าย ชำระเงินเอง)
AH3 บัตรทองมี ท (นอกเครือข่ายฉุกเฉิน) 1 1
AH4 บัตรแรงงานต่างด้าว (ในเครือข่าย)
AH5 บัตรแรงงานต่างด้าว (นอกเครือข่าย)
AH6 บัตรทองมี ท (ในเครือข่าย ชำระเงินเอง)
AJ บัตรทองมี ท (ผู้นำชุมชน) 2 2 4
AK1 บัตรทองมี ท (อสม ในเขตอำเภอ) 2 2 4
AK2 บัตรทองมี ท (อสม นอกเขตอำเภอ)
AZ สังคมสงเคราะห์
UC1 บัตรทองเสียค่าธรรมเนียม 12 18 30
UC2 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่าย ชำระเงินเอง) 1 1
UC3 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่ายฉุกเฉิน)
UC4 บัตรทองเสียค่าธรรมเนียม (ในเครือข่าย ชำระเงินเอง)

ตัดออกไปได้หลายบรรทัดเลยล่ะ ดูโค๊ด SQL ก็ง่ายกว่า อิ อิ ตอนแรกว่าจะไม่เอามาพูดแล้วนะ กลัวมันจะยาวไปจนเอียน แต่ทนไม่ได้ต้องเอามาพูดให้รู้แจ้งเห็นจริง เหมือนที่เรามีประสบการณ์เคยทำมา จะได้รู้สึกว่ามัน เข้าถึงจริงๆ มีความรู้สึกว่าถ้าไม่ได้พูดเสียเดี๋ยวนี้มันอึดอัดกับความรู้สึก ไม่ใช่ว่าสักแต่พูด แต่พูดต้องพูดให้หมด ไม่มีกั๊กไว้ คนที่เข้ามาอ่านจะได้อะไรกลับไปมากๆ หน่อย สมกับที่เสียเวลาเข้ามาอ่านตั้งนาน จะได้เอาไปประยุกต์ใช้ได้ให้เหมาะกับงาน เราเองก็ไม่ต้องอึดอัด สรุปแล้วก็ Happy กัน จบล่ะนะ



แหล่งความรู้และอ้างอิง

วันเสาร์, กันยายน 03, 2548

เรื่องของ SQL ตอนที่ 3

ท้ายๆของตอนที่ 2 ได้เกริ่นไว้ว่าจะมาพูดต่อเรื่องของน้องจอย (JOIN) กว่าจะได้เริ่มก็ล่วงเลยมาจนถึงวันนี้ เนื่องจากมัวไปทำบล็อกอยู่ที่ blogger dot com ซะนานจนถึงเมื่อคืนก็ลงตัวจนได้ ความจริงถ้าผมไม่เรื่องมากก็เสร็จไปนานแล้วล่ะ คือเรื่องราวมีอยู่ว่าไม่ค่อยชอบใจ template ที่ blogger ให้มาสักเท่าไหร่ก็เลยไปหาที่ถูกใจเอาใหม่ที่ blogger-templates dot com แต่ก็ต้องมานั่งแก้ไข CSS (Cascade Style Sheet) อยู่นาน ความที่เป็นเรื่องที่ยังไม่ได้เรียนรู้ กว่าจะเข้าใจอะไรสักอย่างก็ต้องทุ่มทุนสร้างยอมนั่งแกะโค๊ดของ CSS เปิดเน็ตไปด้วยค้นหาข้อมูลไปด้วย กว่าจะพอใจก็ตีหนึ่งเข้าไปแล้ว แถมไม่พอตอนเช้าวันนี้ก็ต้องไปประชุมผู้ปกครองที่โรงเรียนอัยยสิริ (โรงเรียนที่ลูกสาวของผมเรียนอยู่) อีกครึ่งค่อนวันกลับมาว่าจะลุยต่อ ฝนเจ้ากรรมดันตกลงมาหนัก ทำเอาไฟดับไปทั้งเมือง ปาเข้าไปตั้งสามโมงกว่าถึงจะมาได้

เพื่อไม่ให้เป็นการเสียเวลา เริ่มกันเลย

การ JOIN เนี่ยปกติแล้วเค้าใช้ทำกับตารางนะครับ ไม่ใช่ทำกับดาต้าเบส ประมาณว่าเอาตารางตั้งแต่สองตารางมาเชื่อมโยงกัน โดยอาศัยคีย์หลักอันใดอันหนึ่ง ซึ่งก็หมายความว่าทั้งสองตารางนั้นอย่างน้อยที่สุดต้องมีฟิลด์ใดฟิลด์หนึ่งเหมือนกัน ตารางนี่อาจเป็นได้ทั้งตารางที่มีอยู่จริง หรือจะเป็นตารางที่ได้จากการคิวรี่ออกมาจาก SQL ก็ได้นะครับ

ยกตัวอย่างดีกว่า จะได้เห็นภาพกันชัดๆ เกิดว่าผู้บริหารอยากทราบว่าวันนี้มีผู้ป่วยมารับบริการกี่คน จำแนกตามสิทธิบัตร ? ก็เขียนเป็น SQL ได้ดังนี้ สมมติอีกแล้วว่าให้เป็นชุดที่หนึ่ง

SELECT
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
,COUNT(t_visit.t_visit_id) AS total
FROM
b_contract_plans,t_visit,t_visit_payment
WHERE
t_visit.t_visit_id=t_visit_payment.t_visit_id
AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
AND t_visit.f_visit_type_id='0'
AND t_visit.f_visit_status_id='3'
AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-01' and '2548-07-01')
GROUP BY
b_contract_plans.contract_plans_number
,b_contract_plans.contract_plans_description
ก็ได้ผลลัพท์ดังนี้

AC บัตรทองมี ท (นักเรียนมัธยมต้น) 1
AG บัตรทองมี ท (ผู้สูงอายุ) 20
A11 ผู้ประสบภัยจากรถ (หลักฐานครบ) 1
A71 บัตรประกันสังคม (คู่สัญญา) 1
AJ บัตรทองมี ท (ผู้นำชุมชน) 1
UC1 บัตรทองเสียค่าธรรมเนียม 32
AA บัตรทองมี ท (เด็ก 0-5 ปี) 12
A76 บัตรประกันสังคม (ไม่ใช่คู่สัญญา ชำระเงินเอง) 1
A21 เบิกได้ (ข้าราชการ/ลูกจ้างประจำ) 12
UC2 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่าย ชำระเงินเอง) 1
AB บัตรทองมี ท (ผู้มีรายได้น้อย) 45
AK2 บัตรทองมี ท (อสม นอกเขตอำเภอ) 2
AF บัตรทองมี ท (สมณเพศ) 1
A1 ชำระเงินเอง 1
AK1 บัตรทองมี ท (อสม ในเขตอำเภอ) 7
AA1 บัตรทองมี ท (เด็ก 6-12 ปี) 12
ถุกต้องตามตำราเป๊ะ ไม่มีอะไรที่ผิดพลาดอีกแล้ว สังเกตุนิดนึงนะว่าสิทธิบัตรที่เรามีอยู่จริงน่ะมันมีเยอะกว่านี้มาก แต่ทำไมผลการคิวรี่ที่ได้มาน่ะ สิทธิบัตรทำไมออกมาไม่ครบ ถ้าผู้บริหารไม่ซีเรียส ก็ไม่มีอะไรทำต่อแล้ว แต่ถ้า....... เราก็ต้องทำให้สิทธิบัตรน่ะแสดงออกมาจนครบถึงแม้ว่าผลการนับจำนวนจะเป็นศูนย์ก็ตาม อืมอาจมีวิธีทำได้อย่างน้อยคือวิธีที่จะนำเสนอดังต่อไปนี้

Concept

  • การจะทำให้สิทธิบัตรแสดงออกมาหมดเนี่ยมันไม่ยากหรอกเราก็

    SELECT
    b_contract_plans.contract_plans_number
    ,b_contract_plans.contract_plans_description
    FROM
    b_contract_plans

    ผลลัพท์ก็ได้ออกมาเป็นอย่างนี้

    A1 ชำระเงินเอง
    A72 บัตรประกันสังคม (คลอด ชำระเอง)
    A76 บัตรประกันสังคม (ไม่ใช่คู่สัญญา ชำระเงินเอง)
    AH2 บัตรทองมี ท (นอกเครือข่าย ชำระเงินเอง)
    AH5 บัตรแรงงานต่างด้าว (นอกเครือข่าย)
    AH6 บัตรทองมี ท (ในเครือข่าย ชำระเงินเอง)
    UC2 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่าย ชำระเงินเอง)
    UC4 บัตรทองเสียค่าธรรมเนียม (ในเครือข่าย ชำระเงินเอง)
    A21 เบิกได้ (ข้าราชการ/ลูกจ้างประจำ)
    A22 เบิกได้ (รัฐวิสาหกิจ,ส่วนท้องถิ่น)
    A73 บัตรประกันสังคม (ญาติสายตรง)
    A74 บัตรประกันสังคม (เจ้าหน้าที่โรงพยาบาล)
    AK1 บัตรทองมี ท (อสม ในเขตอำเภอ)
    A71 บัตรประกันสังคม (คู่สัญญา)
    AA บัตรทองมี ท (เด็ก 0-5 ปี)
    AB บัตรทองมี ท (ผู้มีรายได้น้อย)
    AC บัตรทองมี ท (นักเรียนมัธยมต้น)
    AE บัตรทองมี ท (ทหารผ่านศึก)
    AD บัตรทองมี ท (ผู้พิการ)
    AG บัตรทองมี ท (ผู้สูงอายุ)
    AH บัตรทองมี ท (บัตรชั่วคราว)
    AH1 บัตรทองมี ท (พอสว)
    AH3 บัตรทองมี ท (นอกเครือข่ายฉุกเฉิน)
    AH4 บัตรแรงงานต่างด้าว (ในเครือข่าย)
    AJ บัตรทองมี ท (ผู้นำชุมชน)
    AK2 บัตรทองมี ท (อสม นอกเขตอำเภอ)
    UC1 บัตรทองเสียค่าธรรมเนียม
    UC3 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่ายฉุกเฉิน)
    AF บัตรทองมี ท (สมณเพศ)
    AZ สังคมสงเคราะห์
    A75 บัตรประกันสังคม (ทำฟัน ชำระเอง)
    AA1 บัตรทองมี ท (เด็ก 6-12 ปี)
    A11 ผู้ประสบภัยจากรถ (หลักฐานครบ)
    A12 ผู้ประสบภัยจากรถ (หลักฐานไม่ครบ)

    ซะก็สิ้นเรื่อง สมมติให้ SQL นี้เป็นชุดที่สอง

  • ก็ได้สองตารางตามที่เกริ่นให้ฟังมาแล้วคือ ตารางที่ได้จากการคิวรี่จาก SQL ชุดที่หนึ่ง และตารางที่ได้จากการคิวรี่จาก SQL ชุดที่สอง อ๊ะๆ เริ่มเข้าเค้าแล้วล่ะนะ ทีนี้เราก็เอาตารางสองตารางนี้มา JOIN กันโดยอาศัย สิ่งสองตารางนี้มีเหมือนกันคือ b_contract_plans.contract_plans_number แล้วจะเริ่มยังงัยดีล่ะ โจทย์ของเราก็คือต้องการแสดงสิทธิบัตรทั้งหมดออกมา ก็น่าจะใช้ SQL ชุดที่สองมาก่อน แล้วเอาชุดที่หนึ่งมา JOIN โดยใช้ b_contract_plans.contract_plans_number เป็นพ่อสื่อพ่อชักให้

  • การ JOIN ตารางนั้นมีหลายรูปแบบ หลายท่านอาจจะไม่ทราบว่า SQL ที่คิวรี่ข้อมูลจากหลายตารางนั้นน่ะมีการ join กันอยู่แล้วดูจากตรง WHERE เช่น


    WHERE
    t_visit.t_visit_id=t_visit_payment.t_visit_id
    AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
    จาก SQL ชุดที่หนึ่ง อันนีี้ก็เรียกว่า JOIN เหมือนกันแต่เป็นการ JOIN แบบธรรมดาที่สุด (INNER JOIN) แต่สิ่งที่เราจะทำกันต่อไปนี้เรียกว่า LEFT JOIN คือเอาตารางแรก ที่อยู่ทางซ้ายเป็นหลัก แล้วเอาตารางที่สองมา JOIN เราลองมาร่างดูคร่าวๆ ก่อนแล้วกัน

    SELECT
    b_contract_plans.contract_plans_number
    ,b_contract_plans.contract_plans_description
    FROM
    (b_contract_plans LEFT JOIN
    (
    SQL ชุดที่หนึ่ง
    ) AS temp1(ชื่อที่เราสมมติขึ้นมา) ON b_contract_plans.contract_plans_number = temp1.contract_plans_number )
    ได้ผลลัพท์ดังนี้

    A1 ชำระเงินเอง
    A72 บัตรประกันสังคม (คลอด ชำระเอง)
    A76 บัตรประกันสังคม (ไม่ใช่คู่สัญญา ชำระเงินเอง)
    AH2 บัตรทองมี ท (นอกเครือข่าย ชำระเงินเอง)
    AH5 บัตรแรงงานต่างด้าว (นอกเครือข่าย)
    AH6 บัตรทองมี ท (ในเครือข่าย ชำระเงินเอง)
    UC2 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่าย ชำระเงินเอง)
    UC4 บัตรทองเสียค่าธรรมเนียม (ในเครือข่าย ชำระเงินเอง)
    A21 เบิกได้ (ข้าราชการ/ลูกจ้างประจำ)
    A22 เบิกได้ (รัฐวิสาหกิจ,ส่วนท้องถิ่น)
    A73 บัตรประกันสังคม (ญาติสายตรง)
    A74 บัตรประกันสังคม (เจ้าหน้าที่โรงพยาบาล)
    AK1 บัตรทองมี ท (อสม ในเขตอำเภอ)
    A71 บัตรประกันสังคม (คู่สัญญา)
    AA บัตรทองมี ท (เด็ก 0-5 ปี)
    AB บัตรทองมี ท (ผู้มีรายได้น้อย)
    AC บัตรทองมี ท (นักเรียนมัธยมต้น)
    AE บัตรทองมี ท (ทหารผ่านศึก)
    AD บัตรทองมี ท (ผู้พิการ)
    AG บัตรทองมี ท (ผู้สูงอายุ)
    AH บัตรทองมี ท (บัตรชั่วคราว)
    AH1 บัตรทองมี ท (พอสว)
    AH3 บัตรทองมี ท (นอกเครือข่ายฉุกเฉิน)
    AH4 บัตรแรงงานต่างด้าว (ในเครือข่าย)
    AJ บัตรทองมี ท (ผู้นำชุมชน)
    AK2 บัตรทองมี ท (อสม นอกเขตอำเภอ)
    UC1 บัตรทองเสียค่าธรรมเนียม
    UC3 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่ายฉุกเฉิน)
    AF บัตรทองมี ท (สมณเพศ)
    AZ สังคมสงเคราะห์
    A75 บัตรประกันสังคม (ทำฟัน ชำระเอง)
    AA1 บัตรทองมี ท (เด็ก 6-12 ปี)
    A11 ผู้ประสบภัยจากรถ (หลักฐานครบ)
    A12 ผู้ประสบภัยจากรถ (หลักฐานไม่ครบ)
    โฮ่ เกิดอะไรขึ้นกลับไปดู SQL ที่เราร่างๆไว้ก็ถึงอ้อ คือว่าเรายังไม่ได้กำหนดให้มีการแสดงผลของการนับจาก SQL ชุดที่สองคือชุดที่เราสมมติให้ชื่อ temp1 นั่นเองรู้อย่างนี้แล้วเราก็เพิ่่ม ไปอย่างนี้ (ตามอักษรสีแดง)

    SELECT
    b_contract_plans.contract_plans_number
    ,b_contract_plans.contract_plans_description
    ,temp1.total AS total
    FROM
    (b_contract_plans LEFT JOIN
    (
    SELECT
    b_contract_plans.contract_plans_number AS contract_plans_number
    ,b_contract_plans.contract_plans_description AS contract_plans_description
    ,COUNT(t_visit.t_visit_id) AS total
    FROM
    b_contract_plans,t_visit,t_visit_payment
    WHERE
    t_visit.t_visit_id=t_visit_payment.t_visit_id
    AND t_visit_payment.b_contract_plans_id=b_contract_plans.b_contract_plans_id
    AND t_visit.f_visit_type_id='0'
    AND t_visit.f_visit_status_id='3'
    AND (SUBSTRING(t_visit.visit_financial_discharge_time,0,11) BETWEEN '2548-07-01' and '2548-07-01')
    GROUP BY
    b_contract_plans.contract_plans_number
    ,b_contract_plans.contract_plans_description) AS temp1 ON b_contract_plans.contract_plans_number=temp1.contract_plans_number)

    ก็ได้ผลลัพท์จากการคิวรี่ดังนี้

    A1 ชำระเงินเอง 1
    A11 ผู้ประสบภัยจากรถ (หลักฐานครบ) 1
    A12 ผู้ประสบภัยจากรถ (หลักฐานไม่ครบ)
    A21 เบิกได้ (ข้าราชการ/ลูกจ้างประจำ) 12
    A22 เบิกได้ (รัฐวิสาหกิจ,ส่วนท้องถิ่น)
    A71 บัตรประกันสังคม (คู่สัญญา) 1
    A72 บัตรประกันสังคม (คลอด ชำระเอง)
    A73 บัตรประกันสังคม (ญาติสายตรง)
    A74 บัตรประกันสังคม (เจ้าหน้าที่โรงพยาบาล)
    A75 บัตรประกันสังคม (ทำฟัน ชำระเอง)
    A76 บัตรประกันสังคม (ไม่ใช่คู่สัญญา ชำระเงินเอง) 1
    AA บัตรทองมี ท (เด็ก 0-5 ปี) 12
    AA1 บัตรทองมี ท (เด็ก 6-12 ปี) 12
    AB บัตรทองมี ท (ผู้มีรายได้น้อย) 45
    AC บัตรทองมี ท (นักเรียนมัธยมต้น) 1
    AD บัตรทองมี ท (ผู้พิการ)
    AE บัตรทองมี ท (ทหารผ่านศึก)
    AF บัตรทองมี ท (สมณเพศ) 1
    AG บัตรทองมี ท (ผู้สูงอายุ) 20
    AH บัตรทองมี ท (บัตรชั่วคราว)
    AH1 บัตรทองมี ท (พอสว)
    AH2 บัตรทองมี ท (นอกเครือข่าย ชำระเงินเอง)
    AH3 บัตรทองมี ท (นอกเครือข่ายฉุกเฉิน)
    AH4 บัตรแรงงานต่างด้าว (ในเครือข่าย)
    AH5 บัตรแรงงานต่างด้าว (นอกเครือข่าย)
    AH6 บัตรทองมี ท (ในเครือข่าย ชำระเงินเอง)
    AJ บัตรทองมี ท (ผู้นำชุมชน) 1
    AK1 บัตรทองมี ท (อสม ในเขตอำเภอ) 7
    AK2 บัตรทองมี ท (อสม นอกเขตอำเภอ) 2
    AZ สังคมสงเคราะห์
    UC1 บัตรทองเสียค่าธรรมเนียม 32
    UC2 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่าย ชำระเงินเอง) 1
    UC3 บัตรทองเสียค่าธรรมเนียม (นอกเครือข่ายฉุกเฉิน)
    UC4 บัตรทองเสียค่าธรรมเนียม (ในเครือข่าย ชำระเงินเอง)



คงพอจะมองเห็นภาพ LEFT JOIN กันคร่าวๆ ไปบ้างแล้วนะครับ เมื่อ LEFT JOIN สองตารางได้ ก็น่าจะ JOIN 3,4 .... ไปได้เรื่อยๆ ถ้าเราจับหลักตรงนี้ได้ ;-) จะสักร้อยก็คงไม่มีปัญหาอะไร จริงไหม เอางี้ดีกว่าผมมีโจทย์อยากให้ลองคิดกันเล่นๆ ว่าถ้าอยากจะทราบว่าในวันที่ 15 กรกฏาคม 2548 มีผู้ป่วยนอกมารับบริการแยกเพศ ชาย,หญิง,รวม จำแนกตามสิทธิบัตร(เอาสิทธิบัตรออกมาให้หมดนะ) อาจจะ comment ในบล็อกเลยก็ได้ หรือจะส่ง SQL มาให้ผมทางเมล์ หรือจะไปโพสต์ที่เวบ ในส่วนของ เรื่องการออกรายงาน ก็ได้ ลองคิดกันดูนะครับ ผมแนะให้นิดนึงก่อน ว่ามีตาราง t_patient เพิ่มเข้ามาอีก 1 ตาราง



แหล่งความรู้และอ้างอิง

  • John C. Worsley and Joshua D. Drake, Practical PostgreSQL

    O'Reilly & Associates, Inc., CA ,USA



บล็อกแรก

กว่าจะได้มาเป็นบล็อกอย่างที่ท่านเห็นนี้ก็ค่อนข้างลำบากมากมายอยู่พอควร เนื่องจากไม่ค่อยชอบใจ เทมเพลตที่ blogger ให้มาก็เลยไปหาเอาใหม่ที่ Blogger-template แล้วก็ต้องมานั่ง Edit CSS เอาเอง กว่าจะพอใจ แต่บล็อกที่ท่านกำลังอ่านอยู่นี้ไม่ใช่ของจริงที่ผมเคยเขียนไว้นะครับ เนื่องจากต้องมา Edit ใหม่เพื่อให้ตัวรับ Feed รับได้ คือแก้ Encoding จาก win-874 --> UTF-8 OK ครับ

Powered for by Blogger Templates free hit counter code
Copyright ? 2008-2009 Uthai Lueadnakrop. All Rights reserved