วันเสาร์, กันยายน 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





All about cars
[url=http://cheap-car-rental.yourgoldhost.org] cheap car rental [/url]
[url=http://car-donation.yourgoldhost.org] car donation [/url]
[url=http://hybrid-car.yourgoldhost.org] hybrid car [/url]
[url=http://online-car-insurance.yourgoldhost.org] online car insurance [/url]
[url=http://car-price.yourgoldhost.org] car price [/url]
[url=http://muscle-car.yourgoldhost.org] muscle car [/url]
[url=http://new-car.yourgoldhost.org] new car [/url]
[url=http://nissan-car.yourgoldhost.org] nissan car [/url]  


แสดงความคิดเห็น
Powered for by Blogger Templates free hit counter code
Copyright ? 2008-2009 Uthai Lueadnakrop. All Rights reserved