Video call กับไอดอลครั้งแรก

Video call กับไอดอลครั้งแรก

วันนี้มาเล่าเรื่องประสบการณ์ Video call กับไอดอลครั้งแรก จริงๆมันคือการบันทึกความทรงจำและความรู้สึก ณ ตอนนี้ไว้เผื่อในอนาคตจะได้กลับมาอ่าน เพราะความรู้สึกในเวลานี้กับอีกระยะเวลานึงมันไม่เหมือนกัน ก็เลยอยากจะเก็บความทรงจำนี้ไว้ผ่านตัวอักษร

เรื่องมันเริ่มมาจาก

เรื่องมันเริ่มมาจากน้องไอดอลคนนึงโพสต์เชิญชวนมาให้ Video call ด้วย ไอเราก็คิดว่าเฮ้ยไม่จริงจังหรอกมั้ง แต่พอเห็นน้องมันโพสต์ถี่ (จริงๆจะตั้งเวลาก็ได้แหละ) เออ ดูมีความพยายามบวกกับก็เคยเป็นไอดอลที่เรารู้จักอยู่แล้ว น้องมันก็น่ารักดี ก็เลยลองดูละกัน จะได้สนับสนุนวงด้วย จะได้ทำเพลงใหม่ๆอีกมาประกับวงการ

สิ่งที่ได้มาหลังจากจอง Video call

หลังจากได้เงินเรียบร้อยแล้วเขาจะส่งเมลล์มาบอกว่าเราจะได้ Video call ประมาณกี่โมง แล้วต้องใช้ App อะไรซึ่งของผมก็คือ Zoom ซึ่งก็ต้องไปหา Download มาติดตั้ง พร้อมทดลองใช้ซึ่งแม่งก็ไม่รู้จะทดลองยังไง สุดท้ายทั้งเมลล์มีแค่นี้ ผมนี่ก็ …. แล้วจะรู้ไหมว่าเป็นยังไง คือปกติผม Video call ประชุมกับที่ทำงานนะ คือมันเหมือนคนไปคุยงานกันเล่นกัน มันไม่มีธรรมเนียมอะไร แบบ ต้องสวัสดีครับ รออย่างโน้นอย่างนี้ไหมก็เลยงงๆ

ไม่ทันตั้งตัว

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

1
2
3
Staff : ได้ยินไหมคะ

โปรแกรมเมอร์ : อ่าครับได้ยินครับ

แล้วอยู่ดีๆก็มี Video ขึ้นมาน่าจะเป็น Single ที่สองของวงมั้งนะ แล้วอยู่ดีๆก็ตัดมาให้คุยกับน้องแบบงงๆ แบบ เฮ้ยไรวะ ยังไม่ทันเตรียมตัวยังดึง Context ที่เขียน Code ออกจากหัวไม่ได้เลย

แล้วบทสนทนาแบบงงๆก็เริ่มต้นขึ้น

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

AIRI : เราเคยเจอกันมาก่อนไหมคะ

โปรแกรมเมอร์ : อ่าไม่เคยเจอครับ

AIRI : งั้นก็เป็นครั้งแรกน่ะสิ แล้วรู้จักหนูได้ไงคะ

โปรแกรมเมอร์ : จริงๆพี่ก็รู้จักน้องตอนอยู่วงเก่าแล้วอะนะ

AIRI : อ้าวเหรอคะ แล้วทำไมไม่มาเจอกัน

โปรแกรมเมอร์ : คนมันเยอะน้องพี่เข้าไปไม่ถึง

AIRI : แล้วปกติตามวงอะไรคะ

โปรแกรมเมอร์ : อ่าก็ตาม Siam dream กับ Melt mallow แต่ Melt mallow ยุบวงไปแล้ว

AIRI : แล้วจากนี้จะตามหนูไหมคะ

โปรแกรมเมอร์ : อ่าก็ถ้ามีโอกาสเดี๋ยวพี่จะลองไปดูนะ

AIRI : แล้วช่วงนี้เป็นยังไงบ้างคะ

โปรแกรมเมอร์ : ก็สบายดีงานเยอะนิดหน่อย

แล้วจากนั้นก็คุยกันไปอีกประมาณ 1 นาทีก็จบ Video call

สรุป

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

น้อง AIRI

น้องน่ารักมาก ไปติดตามน้องได้ที่ https://www.facebook.com/hatobitoofficial.airi หรือกด Link ใต้รูปก็ได้

AIRI

ปัญญางาน - MANAGING ONESELF

ปัญญางาน - MANAGING ONESELF

ปัญญางาน - MANAGING ONESELF

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

คำถาม

หนังสือเล่มนี้ไม่ใช่หนังสือที่อ่านเล่าเรื่องของผู้บริหาร บอกเป็น Case study แต่เป็นการตั้งคำถาม เช่น งานแบบไหนที่เราถนัด , คุณชอบตัดสินใจหรือชอบให้เขาปรึกษา โดยความง่ายของคำถามคือมันเป็นคำถามปลายปิดมีตัวเลือกแค่ 2 ข้อ จากนั้นตัวคนเขียนก็เล่าว่าต้องเป็นแบบไหน ชอบแบบไหน หรือรู้สึกแบบไหน ถึงจะตรงกับตัวเลือกที่ 1 เป็นแบบไหน ถึงจะเป็นตัวเลือก 2

ผู้ให้คำปรึกษา หรือ ผู้ตัดสินใจ

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

ทำงานได้ดีใน องค์กรขนาดใหญ่ หรือ องค์กรขนาดเล็ก

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

หาที่ทางของตัวเอง

ในหลายๆคำถามที่ถามไปนำพามาถึงสิ่งที่หนังสือพยายามบอกเรื่องนึงคือ “หาที่ทางของตัวเอง” เมื่อรู้ว่าตัวเองเป็นคนแบบไหน ชอบงานแบบใด ก็ควรพาตัวเองไปอยู่ในจุดที่ตัวเองชอบ เช่น อย่างผมชอบเป็นที่ปรึกษาไม่ชอบการตัดสินใจ ผมก็พาตัวเองไปอยู่ในส่วนงาน Techniacl และ Specialist แม้หลายครั้งหัวหน้าจะพยายามให้ผมไปอยู่ในตำแหน่งเช่น หัวหน้าทีม ผมก็พยายามบอกเสมอว่า ผมไม่ถนัดงานด้านนี้ ให้ทำได้ แต่ถ้ามันออกมาไม่ดีผมขอกลับมาอยู่ตำแหน่งนี้ ซึ่งจากการทดลองได้คุมคนก็พบว่า เออ เราไม่ถนัด ทำแล้วไม่มีความสุข มันวิตกกังวล มันจะดีหรือไม่ดีวะที่ตัดสินใจแบบนั้น ถึงแม้ทางที่เราคิดมาแล้วจะดีที่สุดก็เถอะ

สรุป

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

เพลงประกอบการเขียน Blog

โรคแอบชอบเพลงที่ตรงกับตัวผม เพราะมักจะแอบชอบผู้หญิงที่มีโอกาสได้เจอกันไม่ว่าจะเป็นเพื่อนตอน ประถม มัธยม ม.ปลาย คนที่ทำงาน หรือคนที่เจอกันบน BTS เป็นประจำ แต่สุดท้ายมันก็ทำได้แค่แอบชอบ

Violet Evergarden

Violet Evergarden

ขอพูดตามตรงเลยว่าไม่เคยได้ยินชื่อเรื่องนี้เลย แบบ Blank มากๆ มารู้ก็ตอนวันที่ 27 ก.พ. ว่า Major จัดโปรโมชั่นดูหนังราคา 28 บาทในวันที่ 28 ก.พ. ก็เลยไปหา List หนังที่จะดูซึ่งก็เจอเรื่องนี้ แต่เป็นชื่อภาษาไทยว่า จดหมายฉบับสุดท้าย… แด่เธอผู้เป็นที่รัก ดูเวลาก็โอเคน่าจะทำธุระเสร็จแล้วไปดูทัน

ตัวอย่าง

เปิดเรื่องมาชวนให้ติดตาม

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

ต่อจากนี้อาจจะสปอยเนื้อหา ดังนั้นถ้าอยากดูก่อนไม่ควรอ่าน

การมาของเทคโนโลยี

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

ปัญหาของการสื่อสาร

การสื่อสารอาจเป็นใจความสำคัญหลักของเรื่องนี้ การสื่อสารมีหลายแบบทั้งที่เจอกันต่อหน้าและไม่ต่อหน้า โต้ตอบกันได้หรือโต้ตอบกันไม่ได้ ทุกการสื่อสารมีความเฉพาะ มีข้อดีข้อเสียแตกต่างกัน (เรื่องนี้ทำให้เราเห็นชัดมาก ชัดแบบ เอ้อเราไม่เคยมองจุดนี้กันเลย) หลายครั้งที่ความคิดของเรานั้นคิดแบบนึง แต่การสื่อสารออกไปนั้นเป็นแบบนึง มันเป็นเรื่องประหลาดแล้วเรื่องประหลาดเหล่านี้นั้นผูกปมให้กับมนุษย์มามากมาย คำพูดบางคำ การแสดงออกบางเรื่องส่งผลลากยาวเป็น 10 20 ปี หรือเลวร้ายถึงทั้งชีวิตคนหนึ่งคน ทั้งๆที่ต่างคนต่างก็อยากทำเพื่ออีกฝ่ายแท้ๆ เรื่องนี้ทำให้เห็นปมพวกนี้ชัดมาก ชัดจนแบบนี่มันคือเรื่องจริงที่เราเจอกัน

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

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

วรรคทองของเรื่อง

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

ภาพสวยมาก

เรื่องนี้ภาพสวยงามมาก มันมีความเป็น Anime แบบที่เราดูกันตอนเด็ก ไม่แบบ 3D ให้เห็นแบบขัดอารมณ์ ความสวยของสี การเคลื่อนไหว งดงามราวกับภาพในนิยาย เสื้อผ้า การแต่งตัว องค์ประกอบในเรื่องนี้นี่จัดเต็ม ไม่ใช่งานลวกแน่นอน ภาพมี 10 ผมให้ 10 เลยเรื่องนี้

เสียง

ผมชอบเสียงประกอบเรื่องนี้มาก เสียงเดินของตัวเองนี่แบบ ให้อารมณ์เสียงคนเดินจริงๆ เสียดายที่ OST นั้นยังไม่ดึงดูดเท่า Firework คือเรื่อง Firework นี่ OST ฟังแล้วหยุดไม่ได้ต้องฟังแล้วฟังอีกวนไปเรื่อยๆ

ข้อเสีย

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

สรุป

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

Spring - ใช้ Shedlock แบบ Manual เพื่อใช้ในการทำ Lock

Spring - ใช้ Shedlock แบบ Manual เพื่อใช้ในการทำ Lock

ในยุคที่การเขียน Application เน้นหนักไปที่การทำให้สามารถ Scale out เพื่อรองรับ Load หรือแบ่งงานกันทำ ซึ่งนั่นแปลว่า Application ที่เราเขียนนั้นจะมีหลายตัวทำงานพร้อมๆกัน ทุกอย่างฟังดู OK ไม่มีปัญหา แต่หาก Application ของท่านมีงานสักงานที่ต้องการให้มีแค่ 1 instance (thread , process บลาๆ) ทำงานเท่านั้น

ตัวอย่างงานที่ต้องการแค่คนเดียวทำ

  1. งานที่กำหนดเวลาที่จะเริ่มทำงานได้

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

    • ทุกสิ้นเดือนจะทำการอ่านข้อมูลจาก database เพื่อออกเป็นรายงาน

    • ทุกวันขึ้นปีใหม่จะทำการแก้เลข Running เป็น 0 ใหม่

    • ทุกสิ้นเดือนทำการลบข้อมูลที่เก่ากว่า 3 เดือนทิ้งไป

      จะเห็นว่างานพวกนี้ต้องการ Run ด้วยคนเดียว (instance, thread , process) ไม่ต้องการให้มีหลายคนมาทำพร้อมกัน ซึ่งถ้าทำพร้อมกันก็อาจเกิดปัญหา เช่น ทำงานซ้ำซ้อน ได้ report 3 ใบให้งงเล่น หรือ แย่งกันลบข้อมูลทำให้เกิด error ว่ามีคนกำลังแย่งกันใช้งาน

  2. งานที่ไม่สามารถกำหนดเวลาที่จะเริ่มทำงานได้

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

    • ยิงไป Get Token จาก API Third party เมื่อมีลูกค้าเริ่มเข้ามาใช้งาน
      กรณีนี้คือเมื่อมีคนมาใช้งานเป็นการ Trigger ให้ Application เราเริ่มทำงาน แต่ Application เราต้องติดต่อ Third party ซึ่งต้องยิงไปขอ Token เพราะ Token ที่เก็บไว้หมดอายุ เราจึงต้องยิงไปขอ token เพื่อมาเก็บใหม่ ซึ่งถ้ามีลูกค้ามาใช้งานพร้อมกัน 50 คน มันจะกลายเป็น ยิงไปหา Third party 50 ครั้ง แล้วถ้า Third party token เป็นแบบ login แล้ว token เก่าจะใช้ไม่ได้ แปลว่าการยิง 49 ครั้งจะไม่มีความหมาย ดังนั้นเราต้องการแค่ คนเดียวเท่านั้นไปดึง token กลับมาแล้ว save ที่ระบบ

วิธีแก้ปัญหา

ถ้าพูดถึงวิธีแก้ปัญหาเท่าที่คิดแบบง่ายๆในตอนนี้ก็มีหลายวิธีครับ เป็นวิธีบ้านๆเลย

  1. แยกส่วนที่ทำงานแบบนั้นออกเป็นอีก Application เลย

    วิธีนี้ออกจะกำปั้นทุบดินไปหน่อยแต่ก็เป็นวิธีที่ง่าย ไม่ต้องหาวิธีจัดการ แยกมันออกมาแล้วมันเป็นตัวเดียวที่ Run แค่ Instance เดียว วิธีนี้เหมาะกับงานพวก Schedule Task แต่ถ้าเป็นงานอื่นที่ต้องเรียกในเวลาไหนก็ได้ แล้วอยากให้ทำงานแค่ตัวเดียว วิธีนี้แก้ไม่ได้

  2. สร้างคนกลางขึ้นมาเพื่อใช้คุยกันตกลงว่าใครจะได้งาน

    วิธีนี้คือสร้างตัวกลางขึ้นมาเพื่อเก็บข้อมูลตรงกลางแล้วให้หลายๆ Instance เข้ามาใช้ข้อมูลตรงกลางซึ่งมี Application พวกนี้เกิดขึ้นมาขึ้นบนโลกนี้แล้วมากมายไม่ว่าจะเป็น Consul , Apache ZooKeeper และ Relational Database เช่น Mysql postgres โดยการใช้วิธีนี้อาจจะใช้ Lib ที่ติดต่อกับ Applicaion ที่กล่าวมาเพื่อทำบางอย่างเพื่อให้ได้งานมา เช่น

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

ดังนั้นด้วยความยืดหยุ่นและไม่ต้องแยก Application ออกมา ดังนั้นเราจะมาลองใช้วิธี สร้างคนกลางขึ้นมาแล้วให้ Application แต่ละ Instance เข้าไปขอ Lock เอง

ไม่ต้องเขียนเอง Shedlock ทำให้แล้ว

มาถึงจุดนี้หลายคนอาจกังวลว่ามันจะต้องมาเขียนเองหรืออะไรรึเปล่า ก็บอกตรงนี้เลยว่าไม่ต้องเขียนครับ มีคนเขียนให้แล้วเราไปใช้ของเขาดีกว่าครับ ซึ่ง Lib ที่ผมแนะนำคือ Shedlock ซึ่งตัว Shedlock นั้นสามารถใช้ได้กับ Database ทั่วไป , Consul, ZooKeeper, etc, และอื่นๆอีกมากมายสามารถอ่านได้ที่ Github เลย

ใช้ Shedlock กับ Schedule Task

อันนี้ไม่ยากเลยครับ สามารถทำตาม Manual ใน README ได้เลย Scheduled locking (Spring)

ใช้ Shedlock แบบ Manual

จากที่บอกไปงานบางงานมันไม่ได้ Run แบบ Schedule ดังนั้นเราจึงไม่สามารถใช้วิธีใส่ Annotation แบบ Schedule Task ได้ ดังนั้นเราจึงต้องมาทำแบบ Manual โดยผมเขียนตัวอย่างไว้แล้วที่

1
https://github.com/surapong-taotiamton/shedlock-example

สามารถ Clone ลงมาทดสอบได้เลย โดย Code นั้นเขียนโดยใช้ Framework spring แต่ไม่ใช่ Spring ก็สามารถใช้งานได้นะครับ ขอแค่สร้าง LockProvider ให้ได้ก็สามารถใช้งานได้แล้ว

Add lib เข้าไปใน pom.xml

เพิ่ม Dependency เข้าไปใน pom.xml โดยในงานนี้ผมขอใช้ Relational Database เป็นคนกลางในการจัดการ Lock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Shedlock -->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>4.20.1</version>
</dependency>

<!--
ใช้ Relational database เลย add dependency นี้ ถ้าใช้ตัวอื่นลองไปหาดูว่าต้อง import อะไร
-->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>4.20.1</version>
</dependency>

สร้าง Table ให้กับ Shedlock

เนื่องจากเราใช้ Database จึงต้องสร้าง Table ให้ shedlock ใช้ในการจัดการ Lock

1
2
3
4
5
6
7
CREATE TABLE shedlock(
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
);

สร้าง Bean Lock provider เพื่อใช้ดึง Lock

ส่วนนี้คือการสร้าง Bean Lock provider เพื่อให้สามารถ Inject ไปใช้ที่อื่นได้

Full Code:ShedlockConfiguration.java

1
2
3
4
5
6
7
@Configuration
public class ShedlockConfiguration {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}

ใช้งาน LockProvider

ในส่วนนี้ขอเป็นการจำลองงานที่เกิดแบบไม่เป็นเวลา แต่อยากให้งานมัน Run แค่ 1 งานในระยะเวลานึง ถ้ามีมาพร้อมกันตัวนึงจะได้ทำงานอีกตัวจะต้องถูกปฏิเสธกลับไป ตรงนี้ผมจะจำลองให้งานเกิดจากการรับ http request เข้ามา จากนั้นให้มันไปแย่ง Lock กัน

Full Code : TestLockController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@RestController
public class TestLockController {

private static final Logger logger = LoggerFactory.getLogger(TestLockController.class);

@Autowired
private LockProvider lockProvider;

@GetMapping("/test-lock")
public String testLock() throws Exception {

// จะตั้งชื่อ LOCK นั้นว่าอะไร ถ้าเป็นงานเดียวกันควรตั้งชื่อเดียวกัน
// เพราะ shedlock แยก lock ด้วยชื่อ
final String LOCK_NAME = "TEST-LOCK-NAME";


// Lock นี้จะ Lock นานสุดเท่าไหร่ อันนี้มีไว้กันเวลาไม่คืน Lock
// พอเกินเวลาที่กำหนดจะได้มีคนเข้าไปขอ Lock ใหม่ได้
Duration lockAtMost = Duration.ofSeconds(60);

// Lock นี้จะ Lock สั้นสุดเท่าไหร่ อันนี้อาจจะงง แต่ไม่งงครับ อันนี้ตั้งไว้ว่า
// หลังจากขอ Lock ไปแล้วจะไม่ให้มีใครมาขอ Lock ได้อีกนานเท่าไหร่
// ต่อให้ทำเสร็จก่อนก็ต้องรอจนกว่าจะถึงเวลาที่กำหนดถึงจะมาขอใหม่ได้
Duration lockAtLeast = Duration.ZERO;

// สร้าง LockConfiguration
LockConfiguration lockConfiguration = new LockConfiguration(
Instant.now(), LOCK_NAME, lockAtMost, lockAtLeast );

logger.info("Begin get lock");
// ขอ Lock
SimpleLock lock = lockProvider.lock(lockConfiguration).orElse(null);
logger.info("End get lock");


if (lock == null) {
// ถ้าไม่ได้ lock lock จะเป็นค่า null code ของเราต้องจัดการว่าถ้าไม่ได้ Lock
// จะทำยังไง ในตัวอย่างนี้ให้ Return กลับไปว่าไม่ได้ Lock
logger.info("Can not get lock");
return "Case : can not get lock";
} else {

// กรณีนี้คือได้ lock เมื่อได้ lock ก็ทำงานอะไรก็ได้ตามใจของเรา
// โดยของผมคือให้มัน Thread sleep ไป 10 วินาทีเพื่อจำลองว่าทำงานอะไรนาน
// ข้อสำคัญคือเมื่อทำงานเสร็จต้องคืน lock เสมอ ไม่ว่าจะสำเร็จไม่สำเร็จ
// จะเห็นว่าใน finally จะสั่ง unlock

logger.info("Get lock and begin do task");
try {
Thread.sleep(10L * 1000L);
logger.info("Do task complete");
} finally {
// อย่าลืมว่าต้อง unlock เสมอไม่ว่าจะสำเร็จหรือไม่สำเร็จ
lock.unlock();
logger.info("unlock complete");
}
return "Case : task complete";
}
}

}

ตัวอย่างการทำงาน

อันนี้ผมสร้าง Post man ยิงไปที่ Server 2 ตัวในเวลาไล่เลี่ยกัน โดยตัวแรกยิงไปก่อนผลลัพธ์จะได้เป็นทำงานสำเร็จ (รอประมาณ 10 วิ ตาม Code ที่ Sleep ไป 10 วิ)

ส่วนตัวที่ยิงไปทีหลังจะได้เป็นไม่สามารถดึง Lock มาใช้งานได้

คราวนี้เราลองมาสำรวจที่ Database ว่ามันทำงานยังไง หลังจากที่เรายิงเข้าเพื่อใช้งาน Lock ตัว shedlock จะเก็บข้อมูลที่ Database ดังนี้

จะเห็นว่าจะมี Lock name ที่ชื่อ TEST-LOCK-NAME โผล่ขึ้นมา โดยจะเห็นว่า locked_at ห่างกับ locked_until เป็นเวลา 60 วินาที ตามที่เราตั้งใน lockAtMost เลย นั่นแปลว่า lock จากนั้นเมื่อทำงานเสร็จ เรามาดู database อีกครั้ง

จะเห็นว่า locked_until จะมีค่าที่เปลี่ยนไป โดยหาสังเกตดีๆคือ 10 วินาทีหลังจาก locked_at โดยตรงนี้ทำให้เราเห็นว่าหลังจากงานของเราทำเสร็จ (ผมสั่ง sleep ไป 10 วินาที) ตัว shedlock ก็ปรับค่า locked_until เป็นเวลาปัจจุบันทันที เนื่องจากเรา set lockAtLeast เป็น 0 วินาที ดังนั้นหากอยากลอง lockAtLeast ว่ามีผลอย่างไรลองไปเปลี่ยนเล่นดูนะครับ เพื่อความเข้าใจที่มากขึ้น

สรุป

สำหรับตอนนี้เราได้รู้ว่าวิธีการใช้ Shedlock แบบ Manual ซึ่งด้วยความรู้เท่านี้ก็สามารถนำไปประยุกต์ใช้กับงานได้มากมาย เมื่อใดมีปัญหาอยากให้คนเดียวทำก็สามารถเอาความรู้ตรงไปประยุกต์ใช้ได้เลย สำหรับตอนต่อไปยังไม่รู้จะเขียนอะไร เอาเป็นว่าถ้างานที่ทำต้องเจออะไรแปลกๆแบบที่ไม่มีใน Internet จะมาเขียนใหม่ให้อ่านกันครับ

โปรโมท Page

ผมทำ Page บน Facebook แล้วนะครับ ใครสนใจรับการแจ้งเตือนเวลาผมอัพเดท Blog ก็ไปกดติดตามกันได้ครับ กดตามลิ้งไปได้เลย Facebook page

ไม่เกี่ยวกับ Code แต่เกี่ยวกับ Idol

น้องมุกวง Wisdom เป็นน้องที่คุยด้วยสนุกมาก เล่นมุกตลอด น่ารัก ลองไปติดตามน้องกันได้

Mook

เพลงประกอบการเขียน Code

เจอผู้หญิงที่ชอบอยากจะจีบแต่ก็เจอว่าเขามีคนคุยอยู่ด้วยแล้ว จะไปแข่งก็ใช่เรื่องก็เลยก็เลย…. ฮ่าๆๆๆๆ

Basic SQL Part 6 - ตะลุยโจทย์ประธานาธิบดี

ตะลุยโจทย์ประธานาธิบดี

เต้นรำพื้นบ้านที่ญี่ปุ่นครั้งแรก โรงแรมบอกว่าตอนเย็นมีเต้นรำ เราก็นึกว่าจะมีสาวญี่ปุ่นมาเต้นเราก็เลยไป สรุปไปมีแต่เราคนเดียวที่ไป เลยได้ท่าเต้นญี่ปุ่นตลกๆกลับมา

ผมเขียนเกี่ยวกับ SQL ไว้ 6 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ SQL ตอนต่างๆได้เลย

สำหรับตอนนี้เรามาลุยโจทย์ที่ผมเล่าให้ฟังเมื่อตอนที่แล้วกัน แต่ก่อนตะลุยโจทย์ก็ขอให้ทำการ Download sql แล้ว copy คำสั่งไปใส่ในเว็บ sqliteonline.com ก่อนเพื่อให้มีข้อมูลในการทำโจทย์ครับ แล้วก็ลองทำความเข้าใจแต่ละ Table โดยผมอธิบายว่าแต่ละ Table คือ Table ที่เกี่ยวข้องกับอะไร แต่ไม่ได้ลงว่ามี Column อะไรบ้าง ลองไป SELECT * ดูข้อมูลเล่นๆกันก่อนครับ พออ่านโจทย์แล้วจะได้มีไอเดีย

  • ADMINISTRATION

    เก็บข้อมูลการขึ้นมาดำรงตำแหน่งประธานาธิบดีว่าปีนี้ใครขึ้นมาเป็นประธานาธิบดีโดยเขาเลือกตั้งทุก 4 ปี (ถ้าไม่เกิดกรณีไม่ปกติ) เขาเก็บเป็นครั้งๆเลยว่าครั้งนี้ใครเป็น

  • ADMIN_PR_VP

    เก็บข้อมูลเกี่ยวกับว่าในสมัยนั้นใครเป็นประธานาธิบดี และ ใครเป็นรองประธานาธิบดี

  • ELECTION

    เก็บข้อมูลเกี่ยวกับการเลือกตั้งแต่ละครั้งว่ามีใครเข้าร่วมบ้าง ผลการโหวตเป็นอย่างไร ใครชนะด้วยคะแนนโหวตเท่าไหร่

  • PRESIDENT

    เก็บข้อมูลประธานาธิบดีท่านนั้นว่ามีอายุเท่าไหร่ อยู่พรรคไหน เกิดที่รัฐไหน

  • PRES_HOBBY

    เก็บข้อมูลว่าประธานาธิบดีท่านนั้นมีงานอดิเรกอะไรบ้าง

  • PRES_MARRIAGE

    เก็บข้อมูลว่าประธานาธิบดีแต่งงานกับใครบ้าง ตอนอายุเท่าไหร่ มีลูกกี่คน

  • STATE

    เก็บข้อมูลรัฐของสหรัฐว่าเข้ามาตอนปีที่เท่าไหร่ เข้ามาอันดับที่เท่าไหร่

1. แสดงอายุของภรรยาประธานาธิบดีที่ขณะแต่งงานมีอายุน้อยที่สุด และมีอายุเท่าไหร่

อันนี้ไม่ยากเท่าไหร่ ง่ายจัดๆเลย

1
2
SELECT MIN(SP_AGE)
FROM PRES_MARRIAGE

2. แสดงจํานวนของประธานาธิบดีที่ขณะแต่งงานมีอายุมากกว่าภรรยา 2 ปี

อันนี้อาจจะยากนิดนึงเพราะไม่เคยบอกว่ามันทำได้ แต่ถ้าลองเล่นกับการ + - * / ใน where ผมว่าทำได้ ซึ่งคำตอบก็คือ

1
2
3
4
5
6
7
8
SELECT COUNT(*)
FROM PRES_MARRIAGE
WHERE PR_AGE - SP_AGE = 2

-- อันนี้ถ้าอยากรู้ว่าใคร
SELECT *
FROM PRES_MARRIAGE
WHERE PR_AGE - SP_AGE = 2

3. หลังจากปี 1870 การเลือกตั้งครั้งใดที่มีผู้สมัครรับเลือกตั้งมากกว่า 2 คน

อันนี้ไม่ยากเลย ใช้ WHERE รวมกับ GROUP , HAVING

1
2
3
4
5
SELECT ELECTION_YEAR
FROM ELECTION
WHERE ELECTION_YEAR > 1870
GROUP BY ELECTION_YEAR
HAVING COUNT(*) > 2

4. แสดงรายชื่อของประธานาธิบดี จํานวนที่ดํารงตําแหน่ง สําหรับประธานาธิบดีที่ดํารงตําแหน่งนานที่สุด

อันนี้เริ่มซับซ้อนขึ้นมาละ แต่ไม่ยากเลย ก็แค่หาว่าการดำรงตำแหน่งนานที่สุดคือเท่าไหร่ แล้ว WHERE ด้วยค่านั้น ซึ่งเราเคยทำคล้ายๆแบบนี้ไปแล้ว ซึ่งนั่นคือการใช้ Sub query นั่นเอง (ส่วนใครจะใช้ ORDER BY ก็ได้นะครับ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- ใช้ Sub query
SELECT *
FROM PRESIDENT
WHERE YRS_SERV = (
SELECT MAX(YRS_SERV)
FROM PRESIDENT
)

-- ใช้ Order by แล้วใช้ Limit ต่อเอา แต่ Limit ไม่ใช่
-- SQL Standard เลยไม่เขียนนะครับ ใครอยากรู้ว่าเขียนยังไงไป
-- ลอง Search ดูได้
SELECT *
FROM PRESIDENT
ORDER BY YRS_SERV DESC

5. แสดงรายชื่อประธานาธิบดีที่แต่งงานอย่างน้อย 2 ครั้งและในการแต่งงานแต่ละครั้งมีบุตรอย่างน้อย 2 คน

อันนี้ก็ไม่ยากเลยใช้แค่ GROUP BY HAVINE เอาอยู่เลย

1
2
3
4
5
SELECT PRES_NAME
FROM PRES_MARRIAGE
WHERE NR_CHILDREN >= 2
GROUP BY PRES_NAME
HAVING COUNT(*) >= 2

6. แสดงรายชื่อประธานาธิบดีที่ดํารงตําแหน่ง (สมัย) มากกว่าจํานวนครั้งการแต่งงาน

อันนี้เริ่ม Advance ขึ้นมาหน่อย แต่ไม่ยากครับ Sub query ช่วยเราได้

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT *
FROM PRESIDENT p1
WHERE
(
SELECT COUNT(*)
FROM ADMINISTRATION a1
WHERE a1.PRES_NAME = p1.PRES_NAME
) >
(
SELECT COUNT(*)
FROM PRES_MARRIAGE p2
WHERE p2.PRES_NAME = p1.PRES_NAME
)

7. แสดงรายละเอียดของตาราง President สําหรับประธานาธิบดีที่เข้ารับตําแหน่งเป็นคนแรก หลังจากปีที่ประธานาธิบดี Reagan แต่งงานครั้งแรก

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

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT PRESIDENT.*  -- Query นี้ก็ JOIN กันระหว่าง ADMINISTRATION กับ PRESIDENT แล้วเพื่อเอา
FROM ADMINISTRATION -- YEAR_INAUGURATED ไปใช้ WHERE และเอาข้อมูลจาก PRESIDENT มาแสดง
INNER JOIN PRESIDENT
ON ADMINISTRATION.PRES_NAME = PRESIDENT.PRES_NAME
WHERE YEAR_INAUGURATED = (
SELECT MIN(YEAR_INAUGURATED) -- Query นี้หาปีที่น้อยที่สุดที่สุดที่ประธานาธิบดีเข้ารับตำแหน่ง
FROM ADMINISTRATION
WHERE YEAR_INAUGURATED > (
SELECT MIN(MAR_YEAR) -------- Query นี้หาปีการแต่งงานครั้งแรกของ Reagan R
FROM PRES_MARRIAGE
WHERE PRES_NAME = 'Reagan R'
)
)

8. แสดงรายชื่อประธานาธิบดีที่ไม่เคยชนะและไม่เคยแพ้การเลือกตั้ง

เฮ้ยโจทย์ข้อนี้น่าสนใจ ไม่เคยแพ้ ไม่เคยชนะ แต่มาเป็นประธานาธิบดี เออเว้ย ลองทำดูหน่อย ก็คิดง่ายๆว่าถ้าไม่เคยชนะและไม่เคยแพ้ แสดงว่าต้องไม่มีข้อมูลใน Table : ELECTION แน่นอน งั้นก็ใช้ Sub query จัดเลยดิ

1
2
3
4
5
SELECT *
FROM PRESIDENT
WHERE PRESIDENT.PRES_NAME NOT IN (
SELECT DISTINCT CANDIDATE FROM ELECTION
)

9. แสดงชื่อรัฐ สมัยการปกครอง ปีที่เข้าร่วมเป็นรัฐหนึ่งในประเทศสหรัฐอเมริกา สําหรับรัฐที่เข้ามาในสมัยการปกครองเดียวกันแต่ต่างปีที่เข้าร่วม

เจอข้อนี้ไปผมก็ช็อกเลย ทำยังไงดีวะ แต่คร่าวๆน่าจะใช้ sub query แล้วแหละ แล้วก็ถ้าเข้ามาปีเดียวกันมันต้องมีค่าเฉลี่ยนใน Group นั้นเท่ากันใช่มะ อ้าวงี้ก็สวยดิ ผมคิดออกละ คุณล่ะครับคิดออกยัง

1
2
3
4
5
6
7
SELECT *
FROM STATE s1
WHERE s1.YEAR_ENTERED != (
SELECT AVG(s2.YEAR_ENTERED)
FROM STATE s2
WHERE s1.ADMIN_ENTERED IS s2.ADMIN_ENTERED
)

10. แสดงชื่อและปีเกิดของประธานาธิบดีผู้ที่มีจํานวนครั้งการแพ้และชนะเลือกตั้งเท่ากัน

ข้อนี้เป็นข้อสุดท้ายละครับที่จะตะลุยโจทย์กัน ซึ่งผมก็ติด Stun นานอยู่เหมือนกัน แต่จริงๆไม่ยากเท่าไหร่เลย ใช้ Correlated subquery หาก็จบนี่

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT p1.PRES_NAME , p1.BIRTH_YR
FROM PRESIDENT p1
WHERE (
SELECT COUNT(*) -- หาจำนวนชนะ
FROM ELECTION e1
WHERE e1.CANDIDATE = p1.PRES_NAME AND WINNER_LOSER_INDIC = 'W'
) = (
SELECT COUNT(*) -- หาจำนวนแพ้
FROM ELECTION e2
WHERE e2.CANDIDATE = p1.PRES_NAME AND WINNER_LOSER_INDIC = 'L'
)
AND p1.PRES_NAME IN ( -- อันนี้บอกว่าต้องเคยลงแข่งแล้วแพ้หรือชนะ เพราะมีบางคนไม่ได้ลงแข่งก็เข้ามาเป็นประธานาธิบดี
SELECT DISTINCT CANDIDATE
FROM ELECTION
)

จบละจริงๆไม่มีตอนต่อไปเกี่ยวกับเรื่องนี้แล้ว

จริงๆมีโจทย์อีกหลายข้อเลยโดยสามารถไป Download (ตัวโจทย์นี้ผมไปเจอมาใน Internet มันเป็นภาษาไทย ผมเลยคิดว่ามันน่าจะง่ายกว่าเอาโจทย์จากสมุดที่อาจารย์ผมให้มามาโชว์) มาลองทำได้ รับรองว่าด้วยความรู้จาก 5 ตอนที่อธิบายไปสามารถเอาไปทำโจทย์ได้ทุกข้อแน่นอน

เพลงประกอบการเขียน Code

ช่วงนี้กระแส 2021 ราตรีมันดังมาก เรื่องการ Remake หรือเรียกว่า Cover ดี พอนึกถึงเพลงที่เอามาทำใหม่แล้วประทับใจคือเพลง “ค่อยค่อยพูด” เวอร์ชั่นพี่อี๊ด ที่มาเล่นในรายการตำนานหมู่สู้ฟัด ซึ่งพี่อี๊ดแกเอามาเพลงมาทำทำนองใหม่ เปลี่ยนอารมณ์เพลงใหม่หมด เล่นเอาเป็นเพลงสบายๆไปซะงั้นเลย แล้วมารู้ทีหลังด้วยว่าแกทำคนเดียว

เวอร์ชันต้นฉบับของ Y NOT 7

Basic SQL Part 5 - Sub query

Sub query

ตั๋วรถไฟตอนที่ไปสิงคโปร์ครั้งแรก

ผมเขียนเกี่ยวกับ SQL ไว้ 6 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ SQL ตอนต่างๆได้เลย

Sub query จริงๆมันก็ไม่มีอะไรมากครับ มันก็แค่ Query ใน Query แล้วก็การใช้ SUb query เนี่ยก็ไม่ค่อยนิยมเท่าไหร่เพราะมันเริ่มซับซ้อน และอาจเริ่มมีผลกับ Performance ซึ่งก็ไม่ใช่ทุกกรณีที่ใช้ Sub query แล้วจะมีผลต่อ Performance

เหมือนคนอ่านมาถึงตรงนี้แล้วอาจจะเริ่มรู้สึกว่า เฮ้ย ตกลงมันควรใช้ไหม อันนี้ขึ้นอยู่กับว่าใช้ที่ไหน ใช้ยังไงมากกว่า ถ้าไปใช้กับงาน Real time แล้วไป Sub query ท่ายาก ก็อาจจะทำให้เกิดปัญหาเรื่อง Performance ได้ แต่ถ้าใช้กับ Database ที่ถูกแยกออกมาเพื่อออก Report โดยเฉพาะการใช้ Sub query ก็อาจไม่มีผลกับ Performance บอกข้อเสีย (สุ่มเสี่ยงว่าจะมีทำให้เกิดปัญหาแล้ว) มาพูดถึงข้อดีของการใช้ Sub query กันบ้าง ข้อดีของมันสะดวกสบายแบบใช้ SQL แล้วจบเลยไม่ต้องไปเขียน Code ข้างนอกเพิ่ม เดี๋ยวในตอนนี้จะเห็นเองว่ามันมีโจทย์แบบนี้อยู่

ก่อนเริ่มให้ Download sql แล้ว copy คำสั่งไปใส่ในเว็บ sqliteonline.com

ใช้ Sub query แบบง่ายๆกันก่อน

ถ้าเราอยากรู้ว่าประธานาธิบดีคนไหนไม่ได้แต่งงาน เราจะเขียน SQL ยังไง ถ้าด้วยความรู้จากการ Join เราสามารถเขียนได้ด้วยวิธีแบบนี้

1
2
3
4
5
SELECT PRESIDENT.*
FROM PRESIDENT
LEFT JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME
WHERE PRES_MARRIAGE.PRES_NAME IS NULL

แนวคิดอันนี้คือเราเอาข้อมูลมา LEFT JOIN แล้ว ROW ไหน JOIN ไม่ติดค่าฝั่ง PRES_MARIAGE จะเป็นค่า NULL เราก็แค่ WHERE ด้วย Column ใน PRES_MARIAGE ว่ามีค่าเท่ากับ NULL ไหมเราก็จะได้คำตอบ

แต่มีอีกแนวคิดนึงในการค้นหาก็คือ ถ้าเรารู้ชื่อมีประธานาธิบดีที่แต่งงาน เราก็เอามาใช้ตรง where ใน not in ก็จะสามารถหาคำตอบได้เช่นกัน

1
2
3
4
5
-- Query 1

SELECT *
FROM PRESIDENT
WHERE PRESIDENT.PRES_NAME not in ( [ List ชื่อของประธานาธิบดีที่แต่งงานแล้ว ] )

คราวนี้ถ้าเราจะหาชื่อของประธานาธิบดีทั้งหมดที่แต่งงานแล้วเราจะหาด้วย Query แบบนี้เลยใช่มะ

1
2
3
4
-- Query 2

SELECT PRES_NAME
FROM PRES_MARRIAGE

ถ้าสมมุติเราสามารถเอา Query 2 ไปใส่ใน Query 1 ตรง List ได้ เราก็จะสามารถตอบคำถามได้แล้วใช่ไหมล่ะ แล้วก็เป็นที่น่ายินดีว่า SQL อนุญาตให้เราทำแบบนั้นครับ ซึ่งเราจะรวม Query ออกมาเป็นแบบนี้

1
2
3
4
5
6
7
8
-- รวม 2 Query เป็น Query เดียว

SELECT *
FROM PRESIDENT
WHERE PRESIDENT.PRES_NAME not in (
SELECT PRES_NAME
FROM PRES_MARRIAGE
)

มาลองอีกตัวอย่าง ถ้าอยากรู้ข้อมูลประธานาธิบดีคนไหนที่อายุตอนตายมากที่สุดเราจะเขียน SQL ยังไง วิธีง่ายๆก็คือ SELECT แล้ว ORDER ด้วยอายุตอนตายแบบ DESC

1
2
3
SELECT *
FROM PRESIDENT
ORDER BY DEATH_AGE DESC

แต่เราสามารถเขียนอีกแบบได้โดยใช้ Sub query คือ ถ้าเรารู้ว่า Death age มากที่สุดคือเท่าไหร่ เราก็สามารถ Where ด้วย Death age นั้น ซึ่งเราจะได้ sql แบบนี้

1
2
3
4
5
6
SELECT *
FROM PRESIDENT
WHERE DEATH_AGE = (
SELECT MAX(DEATH_AGE)
FROM PRESIDENT
)

จากทั้งสองตัวอย่างจะเห็นว่าเราสามารถเอา Sub query มาประยุกต์เขียนเป็น query หาคำตอบได้แล้ว โดยหากสังเกตดีๆ Sub query จะเป็น Sub query ที่จบในตัวเองไม่เกี่ยวข้องกับ Query อื่น ว่าง่ายๆเราสามารถดึง Sub query ไปทำแล้วเอาค่ามาแปะได้เลย เอา sub query ไป run ก่อนได้

Sub query แบบยาก (Correlated subquery)

จริงๆ Query แบบนี้มีชื่อทางการว่า Correlated subquery แต่ผมเรียกมันว่า Sub query แบบยากละกัน ว่าแต่มันเป็นยังไงผมก็อธิบายไม่ถูกผมว่ามาดูตัวอย่างกันเลยดีกว่า ถ้ามีคำถามถามว่า จงแสดงข้อมูลของประธานาธิบดีที่แต่งงานและภรรยาคนล่าสุด ไม่ต้องแสดงข้อมูลภรรยาคนก่อน อ่ะ ด้วยคำถามนี้เราจะทำยังไงดีล่ะ ใช้ JOIN แล้ว GROUP ได้ไหม เราลองมาพยายามกันดู

1
2
3
4
5
6
7
8
-- Query นี้ไม่ถูกแค่ลองพยายามเขียนว่ามันจะเขียนยังไง

SELECT PRESIDENT.PRES_NAME, -- จะเอาชื่อภรรยามาแสดงไม่ได้เพราะ GROUP BY ด้วย PRES_NAME แต่ถ้า
-- จะ GROUP BY ด้วย SPOUSE_NAME ก็ไม่ได้เพราะพอทำแล้วการจัดกลุ่มจะไม่เป็นเฉพาะประธานาธิบดีคนนั้น
FROM PRESIDENT
INNER JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME
GROUP BY PRESIDENT.PRES_NAME

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

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

1
2
3
4
SELECT *
FROM PRESIDENT
INNER JOIN PRES_MARRIAGE
WHERE PRES_MARRIAGE.MAR_YEAR = (MAR_YEAR มากสุดของประธานาธิบดีคนนั้น)

ตามภาพถ้าเราสามารถส่ง PRES_NAME เข้าไปใน Sub query ได้ เราก็จะสามารถหาคำตอบได้ ซึ่งก็โชคดีครับเพราะ SQL ทำได้ครับ โดย Query จะออกมาแบบนี้

1
2
3
4
5
6
7
8
9
10
SELECT *
FROM PRESIDENT p1
INNER JOIN PRES_MARRIAGE p2
ON p1.PRES_NAME = p2.PRES_NAME
WHERE p2.MAR_YEAR = (
SELECT MAX(MAR_YEAR)
FROM PRES_MARRIAGE p3
WHERE p2.PRES_NAME = p3.PRES_NAME
)
-- ตรง p1, p2, p3 นั้นใช้เป็นตัวแทนตารางนั้น เพราะตารางมันชื่อซ้ำกันเลยต้องกำหนดชื่อให้มัน

จาก Query เราจะเห็นว่าตรง Sub query “p2.PRES_NAME = p3.PRES_NAME” เราส่ง p2.PRES_NAME เข้าไปใน Sub query ดังนั้นเราสามารถคิดโดยคร่าวๆได้ว่าเอาข้อมูลมา JOIN กันก่อนพอได้ผลลัพธ์การ JOIN ก็เอาผลลัพธ์ส่งเข้าใน Sub query พอได้ผลลัพธ์ของ Sub query ก็เอามา WHERE กับ Query หลัก

เราจะเห็นความแตกต่างระหว่าง Sub query แบบยากกับแบบง่ายแล้วนะครับ แบบง่ายคือ Query มันจบในตัวเองไม่ต้องส่งข้อมูลจาก Query หลักเข้าไปใน Sub query แต่ถ้าเป็น Query แบบยาก (Correlated subquery) คือจะมีการส่งข้อมูลจาก Query หลักไปใน Sub query

ซึ่งถ้ามองดีๆเราจะเห็นว่าการใช้ Correlated subquery นั่นสุ่มเสี่ยงว่าจะมีผลกับ Performance เพราะเหมือนจะมีการ Query เพิ่มอีก เช่น จากตัวอย่างผลลัพธ์การ JOIN มีทั้งหมดมีทั้งหมด 44 ROW ดังนั้นต้องไปทำ Sub query อีก 44 Sub query นี่จึงเป็นเหตุผลที่การใช้ Sub query แบบ Correlated subquery นั้นสุ่มเสี่ยงที่จะมีผลกับ Performance แต่ๆๆๆๆๆๆๆ อยากให้คิดเสมอว่ามันคือวิธีที่แย่ที่สุดครับในการทำครับ คนที่เขาเขียน Database เขาอาจจะเขียนวิธี Optimize การทำอะไรแบบนี้ทำให้มันเร็วก็ได้ครับ

1
2
3
4
SELECT count(*) -- 44
FROM PRESIDENT
INNER JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

จบละ

สำหรับตอนนี้เราก็เรียนรู้เกี่ยวกับ Sub query กันแล้วนะครับ ทั้ง Sub query แบบง่าย Sub query แบบยาก (Correlated subquery) ซึ่งทำให้เราสามารถสร้าง Query ที่ตอบคำถามที่ไม่จบด้วย Query เดียวได้แล้ว สำหรับใครที่อ่านมาตั้งแต่ตอนแรกมาถึงตอนนี้ ผมขอบอกเลยว่าตอนนี้คุณสามารถเขียน Query หาคำตอบได้เกือบทุกรูปแบบแล้ว จะขาดแต่เรื่อง UNION ซึ่งตั้งแต่ผมทำงานมาไม่เคยใช้เลย แล้วก็ LIMIT ซึ่งแต่ละ Database ใช้ไม่เหมือนกันผมเลยไม่พูดถึง ส่วนใครไม่เชื่อเดี๋ยวตอนหน้าเรามาลองตะลุยโจทย์ SQL เกี่ยวกับประธานาธิบดีกัน โจทย์นี้อาจารย์ที่เคยสอนผมบอกว่าเป็นโจทย์ที่ใช้สอนคนที่หัดใช้ Database IBM ซึ่งอาจารย์เคยบอกว่าถ้าทำโจทย์พวกนี้ได้โจทย์ งานจริงก็แทบจะทำได้หมดแล้ว

เพลงประกอบการเขียน Code

ซ้ำเติม เพลงนี้เคยฟังครั้งแรกตอนทำงานคือเปิด List เพลงเก่าไปเรื่อยๆจนได้มาเจอเพลงนี้ คือแบบ เฮ้ย โดนทั้งทำนอง ทั้งเนื้อร้อง แล้วตอนฟังนี่อยู่ในช่วงโดนเทแล้วเหตุการณ์ตรงกับเพลงเลย เพลงนี้ก็เลยอยู่ใน List ที่เปิดฟังบ่อยๆตอนทำงานแล้วก็เขียน Blog

Basic SQL Part 4 - JOIN

JOIN

ภาพวังอะไรสักอย่างที่จีน จำไม่ได้ละ อาจจะเป็นการไปจีนครั้งแรกและครั้งเดียวในชีวิต

ผมเขียนเกี่ยวกับ SQL ไว้ 6 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ SQL ตอนต่างๆได้เลย

ตอนนี้เรามาพูดถึง KEYWORD สำคัญของ SQL ซึ่งนั่นก็คือ JOIN นั่นเอง ซึ่งนั่นทำให้เราสามารถเชื่อมต่อข้อมูลหลายๆตารางมาใช้งานร่วมกันได้

เพิ่มตารางใหม่เข้าไปใน Database

ส่วนต่อจากนี้คือการเพิ่มข้อมูลลง Database โดยจะมีข้อมูลตารางดังต่อไปนี้

  1. PRESIDENT เก็บข้อมูลเกี่ยวกับประธานาธิบดีท่านนั้นว่าอยู่พรรคไหน เกิดปีอะไร ชื่ออะไร ตายเมื่ออายุเท่าไหร่ เป็นคนรัฐไหน
  2. PRES_HOBBY เก็บข้อมูลเกี่ยวงานอดิเรกของประธานาธิบดี
  3. PRES_MARRIAGE เก็บข้อมูลเกี่ยวกับการแต่งงานของประธานาธิบดีว่าแต่งงานกับใคร ตอนอายุเท่าไหร่ มีลูกด้วยกันกี่คน
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
CREATE TABLE IF NOT EXISTS PRES_HOBBY (
`PRES_NAME` VARCHAR(128) ,
`HOBBY` VARCHAR(128)
);
INSERT INTO PRES_HOBBY VALUES
('Adams J Q','Billiards'),
('Adams J Q','Swimming'),
('Adams J Q','Walking'),
('Arthur C A','Fishing'),
('Cleveland G','Fishing'),
('Coolidge C','Fishing'),
('Coolidge C','Golf'),
('Coolidge C','Indian Clubs'),
('Coolidge C','Mechanical Horse'),
('Coolidge C','Pitching Hay'),
('Eisenhower D D','Bridge'),
('Eisenhower D D','Golf'),
('Eisenhower D D','Hunting'),
('Eisenhower D D','Painting'),
('Eisenhower D D','Fishing'),
('Garfield J A','Billiards'),
('Harding W G','Golf'),
('Harding W G','Poker'),
('Harding W G','Riding'),
('Harrison B','Hunting'),
('Hayes R B','Croquet'),
('Hayes R B','Driving'),
('Hayes R B','Shooting'),
('Hoover H C','Fishing'),
('Hoover H C','Medicine Ball'),
('Jackson A','Riding'),
('Jefferson T','Fishing'),
('Jefferson T','Riding'),
('Johnson L B','Riding'),
('Kennedy J F','Sailing'),
('Kennedy J F','Swimming'),
('Kennedy J F','Touch Football'),
('Lincoln A','Walking'),
('McKinley W','Riding'),
('McKinley W','Swimming'),
('McKinley W','Walking'),
('Nixon R M','Golf'),
('Roosevelt F D','Fishing'),
('Roosevelt F D','Sailing'),
('Roosevelt F D','Swimming'),
('Roosevelt T','Boxing'),
('Roosevelt T','Hunting'),
('Roosevelt T','Jujitsu'),
('Roosevelt T','Riding'),
('Roosevelt T','Shooting'),
('Roosevelt T','Tennis'),
('Roosevelt T','Wrestling'),
('Taft W H','Golf'),
('Taft W H','Riding'),
('Taylor Z','Riding'),
('Truman H S','Fishing'),
('Truman H S','Poker'),
('Truman H S','Walking'),
('Van Buren M','Riding'),
('Washington G','Fishing'),
('Washington G','Riding'),
('Wilson W','Golf'),
('Wilson W','Riding'),
('Wilson W','Walking');
CREATE TABLE IF NOT EXISTS PRESIDENT (
`PRES_NAME` VARCHAR(128) ,
`BIRTH_YR` INT,
`YRS_SERV` INT,
`DEATH_AGE` INT ,
`PARTY` VARCHAR(128) ,
`STATE_BORN` VARCHAR(128)
);
INSERT INTO PRESIDENT VALUES
('Washington G',1732,7,'67','Federalist','Virginia'),
('Adams J',1735,4,'90','Federalist','Massachusetts'),
('Jefferson T',1743,8,'83','Demo-Rep','Virginia'),
('Madison J',1751,8,'85','Demo-Rep','Virginia'),
('Monroe J',1758,8,'73','Demo-Rep','Virginia'),
('Adams J Q',1767,4,'80','Demo-Rep','Massachusetts'),
('Jackson A',1767,8,'78','Democratic','South Carolina'),
('Van Buren M',1782,4,'79','Democratic','New York'),
('Harrison W H',1773,0,'68','Whig','Virginia'),
('Tyler J',1790,3,'71','Whig','Virginia'),
('Polk J K',1795,4,'53','Democratic','North Carolina'),
('Taylor Z',1784,1,'65','Whig','Virginia'),
('Fillmore M',1800,2,'74','Whig','New York'),
('Pierce F',1804,4,'64','Democratic','New Hampshire'),
('Buchanan J',1791,4,'77','Democratic','Pennsylvania'),
('Lincoln A',1809,4,'56','Republican','Kentucky'),
('Johnson A',1808,3,'66','Democratic','North Carolina'),
('Grant U S',1822,8,'63','Republican','Ohio'),
('Hayes R B',1822,4,'70','Republican','Ohio'),
('Garfield J A',1831,0,'49','Republican','Ohio'),
('Arthur C A',1830,3,'56','Republican','Vermont'),
('Cleveland G',1837,8,'71','Democratic','New Jersey'),
('Harrison B',1833,4,'67','Republican','Ohio'),
('McKinley W',1843,4,'58','Republican','Ohio'),
('Roosevelt T',1858,7,'60','Republican','New York'),
('Taft W H',1857,4,'72','Republican','Ohio'),
('Wilson W',1856,8,'67','Democratic','Virginia'),
('Harding W G',1865,2,'57','Republican','Ohio'),
('Coolidge C',1872,5,'60','Republican','Vermont'),
('Hoover H C',1874,4,'90','Republican','Iowa'),
('Roosevelt F D',1882,12,'63','Democratic','New York'),
('Truman H S',1884,7,'88','Democratic','Missouri'),
('Eisenhower D D',1890,8,'79','Republican','Texas'),
('Kennedy J F',1917,2,'46','Democratic','Massachusetts'),
('Johnson L B',1908,5,'65','Democratic','Texas'),
('Nixon R M',1913,5,NULL,'Republican','California'),
('Ford G R',1913,2,NULL,'Republican','Nebraska'),
('Carter J E',1924,4,NULL,'Democratic','Georgia'),
('Reagan R',1911,3,NULL,'Republican','Illinois');
CREATE TABLE IF NOT EXISTS PRES_MARRIAGE (
`PRES_NAME` VARCHAR(128) ,
`SPOUSE_NAME` VARCHAR(128) ,
`PR_AGE` INT,
`SP_AGE` INT,
`NR_CHILDREN` INT,
`MAR_YEAR` INT
);
INSERT INTO PRES_MARRIAGE VALUES
('A','B',NULL,NULL,NULL,NULL),
('Washington G','Custis M D',26,27,0,1759),
('Adams J','Smith A',28,19,5,1764),
('Jefferson T','Skelton M W',28,23,6,1772),
('Madison J','Todd D D P',43,26,0,1794),
('Monroe J','Kortright E',27,17,3,1786),
('Adams J Q','Johnson L C',30,22,4,1797),
('Jackson A','Robards R D',26,26,0,1794),
('Van Buren M','Hoes H',24,23,4,1807),
('Harrison W H','Symmes A T',22,20,10,1795),
('Tyler J','Christian L',23,22,8,1813),
('Tyler J','Gardiner J',54,24,7,1844),
('Polk J K','Childress S',28,20,0,1824),
('Taylor Z','Smith M M',25,21,6,1810),
('Fillmore M','Powers A',26,27,2,1826),
('Fillmore M','McIntosh C C',58,44,0,1858),
('Pierce F','Appleton J M',29,28,3,1834),
('Lincoln A','Todd M',33,23,4,1842),
('Johnson A','McCardle E',18,16,5,1827),
('Grant U S','Dent J B',26,22,4,1848),
('Hayes R B','Webb L W',30,21,8,1852),
('Garfield J A','Rudolph L',26,26,7,1858),
('Arthur C A','Herndon E L',29,22,3,1859),
('Cleveland G','Folson F',49,21,5,1886),
('Harrison B','Scott C L',20,21,2,1853),
('Harrison B','Dimmick M S L',62,37,1,1896),
('McKinley W','Saxton I',27,23,2,1871),
('Roosevelt T','Lee A H',22,19,1,1880),
('Roosevelt T','Carow E K',28,25,5,1886),
('Taft W H','Herron H',28,25,3,1886),
('Wilson W','Axson E L',28,25,3,1885),
('Wilson W','Galt E B',58,43,0,1915),
('Harding W G','De Wolfe F K',25,30,0,1891),
('Coolidge C','Goodhue G A',33,26,2,1905),
('Hoover H C','Henry L',24,23,2,1899),
('Roosevelt F D','Roosevelt A E',23,20,6,1905),
('Truman H S','Wallace E V',35,34,1,1919),
('Eisenhower D D','Doud G',25,19,2,1916),
('Kennedy J F','Bouvier J L',36,24,3,1953),
('Johnson L B','Taylor C A',26,21,2,1934),
('Nixon R M','Ryan T C',27,28,2,1940),
('Ford G R','Warren E B',35,30,4,1948),
('Carter J E','Smith R',21,18,4,1946),
('Reagan R','Wyman J',28,25,2,1940),
('Reagan R','Davis N',41,28,2,1952);

เริ่มกันเลย Join กันเลย

ขอบอกเลยว่าการ Join นั้นง่ายมากๆ ถ้าสมมุติเราอยาก Join ข้อมูลระหว่างตาราง PRESIDENT กับ PRES_HOBBY เราสามารถเขียนคำสั่ง SQL ได้ดังนี้

1
2
SELECT * 
FROM PRESIDENT, PRES_HOBBY -- ตรง FROM ใส่ตารางที่อยากให้ JOIN กันลงไป

ซึ่งผลลัพธ์ที่ได้จะประมาณนี้

ซึ่งถ้าคุณสังเกตดีๆจะพบว่า PRES_NAME ที่แสดงชื่อมันไม่ตรงกัน ซึ่งมันเริ่มแปลกๆแล้วใช่ไหม ถ้าคุณลอง count(*) ตาราง PRESIDENT , ตาราง PRES_HOBBY และ การ JOIN ระหว่างตาราง PRESIDENT กับ PRES_HOBBY มันจะได้ผลลัพธ์ดังนี้

1
2
3
4
5
6
7
8
SELECT COUNT(*) -- 39
FROM PRESIDENT

SELECT COUNT(*) -- 59
FROM PRES_HOBBY

SELECT COUNT(*) -- 2301
FROM PRESIDENT, PRES_HOBBY

หากสังเกตดีๆจะพบว่า 2301 = 39 x 59 นั่นเอง แปลว่าการ JOIN แบบนี้คือการเอาแต่ละ ROW ของ 2 TABLE มาเชื่อมกันทั้งหมดจึงเกิดทุกความเป็นไปได้ขึ้นมา

อ้าวแล้วถ้าอยาก JOIN เฉพาะข้อมูลที่ถูกต้องล่ะทำยังไง คำตอบไม่ยากครับ เราต้องมีเงื่อนไขการ JOIN ครับ ซึ่งมันไม่ยากเลย หากเราดูข้อมูลทั้ง 2 TABLE จะพบว่า COLUMN : PRES_NAME เนี่ยแหละเป็นตัวบอกว่าต้องเอา ROW นี้ของ Table PRESIDENT ควรไปต่อกับ ROW นี้ของ Table PRES_HOBBY ดังนั้นเราจึงสามารถเพิ่มเงื่อนไขเข้าไปตรง WHERE แบบนี้

1
2
3
4
5
6
7
SELECT * 
FROM PRESIDENT, PRES_HOBBY
WHERE PRESIDENT.PRES_NAME = PRES_HOBBY.PRES_NAME

-- ตรง WHERE นั้นปกติเราจะใส่แค่ชื่อ COLUMN แต่ทีนี้มันหลาย TABLE ดังนั้นเราจึง
-- ระบุ TABLE เข้าไปด้วยว่า COLUMN จาก TABLE ไหน จากตัวอย่างจะเป็น
-- PRESIDENT.PRES_NAME ก็คือ COLUMN : PRES_NAME จาก TABLE PRESIDENT

คราวนี้จะมีคำถามว่าอ้าวแล้วจะรู้ได้ไงว่าจะเอา COLUMN ไหนไป WHERE กับ COLUMN ไหนนั้น จริงๆคนที่เก็บข้อมูลเขาจะทำสิ่งที่เรียกว่า Relation ไว้ใน Database บอกว่า Table นี้กับ Table นี้มี Column ไหนที่ใช้ JOIN กันได้ หรือถ้าเขาไม่เขียนใน Database เขาจะเขียนไว้ใน Manual ของการเก็บข้อมูลนี้ว่า JOIN กันด้วย COLUMN ไหนกับ COLUMN ไหน หรือ แบบแย่สุดคือเขาจะไม่มี MANUAL เราต้องไปดูเองแต่โดยปกติเขาจะตั้งชื่อ COLUMN ที่ JOIN กันได้เป็นชื่อเดียวกัน เพื่อให้เราพอเดาได้ว่า COLUMN นี้กับ COLUMN นี้ JOIN กันได้

ต่อมา ถ้าอยากรู้ว่าเพิ่มว่า ประธานาธิบดีคนไหนชอบตีกอล์ฟและอยู่พรรค Republican บ้างก็สามารถหาได้ด้วยคำสั่ง

1
2
3
SELECT * 
FROM PRESIDENT, PRES_HOBBY
WHERE PRESIDENT.PRES_NAME = PRES_HOBBY.PRES_NAME AND PRES_HOBBY.HOBBY = 'Golf' AND PRESIDENT.PARTY = 'Republican'

แต่พอเรามาดูจะเห็นว่า WHERE มันเริ่มเยอะและเริ่มงงว่า WHERE ไหนใช้เพื่อการ JOIN WHERE ไหนใช้เพื่อเป็นเงื่อนไขในการค้นหา เพื่อให้ง่ายแก่การเขียนจึงมี KEYWORD เพื่อใช้ง่ายต่อการ JOIN ขึ้นมานั่นคือ JOIN และ ON โดยจาก SQL ตัวที่แล้วเราสามารถเปลี่ยนเป็น SQL ดังนี้

1
2
3
4
5
SELECT *
FROM PRESIDENT
INNER JOIN PRES_HOBBY -- JOIN กันด้วยรูปแบบ INNER เดี๋ยว INNER จะอธิบายต่อจากนี้ แต่ให้เข้าใจว่าการ JOIN มีหลายแบบ
ON PRESIDENT.PRES_NAME = PRES_HOBBY.PRES_NAME -- อันนี้เงื่อนไขการ JOIN ว่า JOIN ด้วยเงื่อนไขอะไร
WHERE PRES_HOBBY.HOBBY = 'Golf' AND PRESIDENT.PARTY = 'Republican'

คำถามต่อมาถ้า JOIN มากกว่า 2 ตารางล่ะ ทำได้ไหม คำตอบคือได้ครับ เดี๋ยวเราจะ JOIN ทั้ง 3 table เลยคือ PRESIDENT, PRES_MARRIAGE, PRES_HOBBY

1
2
3
4
5
6
SELECT *
FROM PRESIDENT
INNER JOIN PRES_HOBBY
ON PRESIDENT.PRES_NAME = PRES_HOBBY.PRES_NAME
INNER JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

ชนิดการ JOIN

คราวนี้เรามาดูชนิดของการ JOIN กันครับ โดยเราจะมาดูวิธีการทำงานของมันกัน โดยเราจะ JOIN 2 Table เข้าด้วยกันคือ PRESIDENT กับ PRES_MARRIAGE โดยใช้เงื่อนไขการ JOIN คือ PRESNAME

INNER JOIN

INNER JOIN ก็คือเอาผลลัพธ์เฉพาะที่ JOIN กันได้เท่านั้น

1
2
3
4
SELECT *
FROM PRESIDENT
INNER JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

การทำงานก็จะดังภาพคือไล่ทีละ ROW ของตาราง PRESIDENT ไปหาคู่ JOIN ที่ ROW ในตาราง PRES_MARRIAGE ถ้าเจอก็เอาข้อมูลมาต่อกันเป็นผลลัพธ์ด้านล่างจะเห็นว่าจะไม่มีผลลัพธ์ของ ROW : “Buchanan J” จากตาราง PRESIDENT

LEFT JOIN

LEFT JOIN เอาทางซ้ายหมด กับ ที่ JOIN ติด

เอาตารางทางซ้ายไปไล่ JOIN ถ้า JOIN ติดก็เอาผลลัพธ์ที่ JOIN ติด ถ้า JOIN ไม่ติดเอาข้อมูลจากตารางที่อยู่ทางซ้ายมาส่วนข้อมูลที่ JOIN ไม่ติดให้ใส่ค่า NULL ไปแทน ตัวอย่างจะเป็นดังภาพ

1
2
3
4
SELECT *
FROM PRESIDENT
LEFT JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

จะเห็นว่า ROW : “Buchanan J” จะโผล่มาในผลลัพธ์ด้วยแต่ข้อมูลเป็นมาจากตาราง PRES_MARIAGE เป็นค่า NULL หมด

RIGHT JOIN (ตัว WEB ไม่ Support นะครับ แต่จริงๆสลับไปใช้ LEFT JOIN ก็ได้)

RIGHT JOIN เอาทางขวาทั้งหมด กับ ที่ JOIN ติด

อันนี้คล้ายๆกับ LEFT JOIN เลย แต่เปลี่ยนเป็นเอาทางขวาหมด อันไหนที่ JOIN ไม่ติดที่อยู่กับตารางทางซ้ายจะมีค่าเป็น NULL

1
2
3
4
SELECT *
FROM PRESIDENT
RIGHT JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

จะเห็น ROW ที่ JOIN ไม่ติด ข้อมูลตารางที่อยู่ด้านซ้ายจะมีค่าเป็น NULL

FULL JOIN (ตัว WEB ไม่ Support นะครับ)

1
2
3
4
SELECT *
FROM PRESIDENT
FULL JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

FULL JOIN เอาทั้งซ้าย ทั้งขวา และที่ JOIN ติด

อันนี้คือเอาทั้งหมดเลยสมชื่อ FULL ผลลัพธ์ก็จะได้ดังภาพ

สรุปเกี่ยวกับ Type การ JOIN

สำหรับเรื่อง Type การ JOIN อาจจะมีหลายอันแต่จริงๆเวลาทำงานผมเคยใช้อยู่แค่ 2 TYPE คือ INNER JOIN กับ LEFT JOIN เท่านั้น RIGHT JOIN นี่ไม่เคยคิดจะใช้เพราะว่ามันแค่สลับตารางขึ้นก่อนก็เป็น LEFT JOIN ละ เลยไม่มีเหตุผลที่จะต้องใช้ ส่วน FULL JOIN นี่ยิ่งแล้วใหญ่ไม่เคยมีงานไหนที่ต้องการผลลัพธ์แบบนั้นเลย

แล้วเราจะใช้ LEFT JOIN ตอนไหนล่ะ จริงๆมันจะมีโจทย์บางอย่างที่ต้องการข้อมูลของตารางซ้ายทั้งหมด ส่วนตารางขวาเป็นข้อมูลประกอบ ไม่มีก็ให้แสดง NULL ได้ เช่น แสดงข้อมูลประธานาธิบดี และ ภรรยาทั้งหมดก็จะได้ SQL ประมาณนี้

1
2
3
4
SELECT PRESIDENT.PRESIDENT, PRES_MARRIAGE.SPOUSE_NAME
FROM PRESIDENT
LEFT JOIN PRES_MARRIAGE
ON PRESIDENT.PRES_NAME = PRES_MARRIAGE.PRES_NAME

จบเรื่อง JOIN

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

เพลงประกอบการเขียน Blog

เพลงที่โคตรเก่าแต่เนื้อเพลงนี่อย่างโดน ตอนฟังครั้งแรก นี่แบบอะไรวะ พอมีประสบการณ์ชอบคนมีแฟนแล้วนี่เข้าใจเพลงนี้เลย คือแบบ “หมาคาบไปแดก” จริงๆ คือทั้งเพลงคือความคิดของเราเลยแบบ ฝันให้เขาเลิกกัน ให้ผู้ชายนอกใจ เขาจะได้โสด แต่แม่งแค่ฝันไง เขารักกันจะตายห่า จะแต่งงานกันอยู่ละ

Basic SQL Part 3 - GROUP BY , Build in function , HAVING

GROUP BY , Build in function , HAVING

รูปตอนไปฮ่องกงครั้งแรก

ผมเขียนเกี่ยวกับ SQL ไว้ 6 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ SQL ตอนต่างๆได้เลย

ตอนนี้เราจะเริ่มใช้ความสามารถของ SQL มากยิ่งขึ้น ตอนนี้อาจจะยากนิดนึงแต่เชื่อเถอะว่าไม่ยากจนเข้าใจไม่ได้ แต่ก่อนเริ่ม GROUP BY , Build in function , HAVING ผมขอเริ่มด้วย KEY WORD : DISTINCT กับ COUNT(*) ก่อน

COUNT(*) มีไว้นับ ROW

COUNT เป็น Build in function ของ SQL มันมีไว้ใช้นับจำนวน ROW โดยถ้าเราอยากจะนับ ROW ทั้งหมดที่ได้ออกมาตามเงื่อนไขเนี่ย เราสามารถใช้คำสั่ง SQL แบบนี้

1
2
SELECT COUNT(*)
FROM PRESIDENT

จากผลลัพธ์นั้นทำให้เรารู้ว่าในตาราง PRESIDENT เนี่ยมีข้อมูลทั้งหมด 39 ROW หรือถ้าเราอยากรู้ว่ามีประธานาธิบดีกี่คนที่อยู่พรรค Republican บ้างก็สามารถใช้คำสั่ง

1
2
3
SELECT COUNT(*)
FROM PRESIDENT
WHERE PARTY = 'Republican'

จากผลลัพธ์ทำให้เรารู้ว่ามีประธานาธิบดีอยู่ในพรรค Republican จำนวน 16 คน

DISTINCT มีไว้แสดงข้อมูลไม่ซ้ำ

ถ้ามีความต้องการอยากรู้ว่าประธานาธิบดีมาจากพรรคไหนบ้าง เราก็สามารถเขียน SQL ได้ดังนี้

1
2
SELECT PARTY
FROM PRESIDENT

ผลลัพธ์แบบไม่ DISTINCT

ซึ่งจากผลลัพธ์จะเห็นว่าค่า PARTY ที่ออกมานั้นแสดงผลซ้ำออกมา ทำให้เราต้องมาไล่ดูทุก ROW ว่ามีค่าอะไรบ้างแล้วมานั่งจำเอาเองว่าซ้ำไม่ซ้ำ ด้วยความต้องการที่อยากเห็นข้อมูลไม่ซ้ำ SQL เลยให้ KEY WORD : DISTINCT ขึ้นมา โดยเราสามารถเขียนคำสั่ง SQL ได้ดังนี้

1
2
SELECT DISTINCT PARTY
FROM PRESIDENT

ผลลัพธ์แบบ DISTINCT

ผลลัพธ์จะเห็นว่าแสดงข้อมูล PARTY ออกมาไม่ซ้ำเลย ตรงตามความต้องการของเรา โดยการทำงานของ DISTINCT นั้นขอให้คิดว่ามันทำงานแบนี้ (เป็นการทำงานแบบให้เข้าใจง่ายแต่การทำงานจริงๆอาจไม่ใช่แบบนี้) หลังจากทำการ WHERE ตัดเอาเฉพาะ ROW ที่ต้องการหมดแล้ว ถ้ามี DISTINCT จะเอาทุก ROW มาตรวจสอบ ถ้าเจอซ้ำจะเอามาแค่อันเดียว

คราวนี้เราอยากรู้ว่าแต่ละพรรคเนี่ยมีประธานาธิบดีจากรัฐอะไรบ้างล่ะ คำตอบนั้นไม่อยากเลยครับ เราก็แค่เลือก PARTY กับ STATE_BORN แล้ว DISTINCT ออกมา เราจะได้ว่าแต่ละพรรคนั้นมีประธานาธิบดีจากรัฐอะไรบ้าง

1
2
SELECT DISTINCT PARTY, STATE_BORN
FROM PRESIDENT

GROUP BY , Build in function

สองเรื่องนี้มันมาพร้อมกันเลยต้องพูดพร้อมกัน เรามาพูดถึง GROUP BY กันก่อน

GROUP BY

ถ้าอยากรู้ว่าแต่ละพรรคนั้นมีประธานาธิบดีมาแล้วกี่คน เราจะรู้ได้อย่างไร ถ้าด้วยความรู้ที่เรามีเราสามารถใช้คำสั่ง SQL ประมาณนี้

1
2
3
4
5
6
7
8
9
SELECT COUNT(*)
FROM PRESIDENT
WHERE PARTY = 'Republican'

SELECT COUNT(*)
FROM PRESIDENT
WHERE PARTY = 'Democratic'

-- ทำไปเรื่อยๆทุกพรรค

หากสังเกตดีๆเราจะเห็นว่าคำถามแบบนี้นั้นมันคือเราต้องการจัดข้อมูลเป็นกลุ่มด้วยการใช้ค่า PARTY เป็นตัวจัดกลุ่มจากนั้นเราก็ใช้ COUNT(*) นับ ROW ด้วยความต้องการแบบนี้ตัว SQL ก็เลยอำนวยความสะดวกตรงนี้ให้กับเรา โดยใช้ KEY WORD : GROUP BY โดยสามารถเขียนคำสั่ง SQL ได้แบบนี้

1
2
3
SELECT PARTY, COUNT(*)
FROM PRESIDENT
GROUP BY PARTY

ผลลัพธ์ออกมาสวยงาม ช่วยให้เราไม่ต้องไปเขียนคำสั่ง SQL หลายๆคำสั่งแล้วเอาผลลัพธ์มาต่อเอง

เพื่อความเข้าใจที่มากขึ้นโดยเพิ่มพวกเงื่อนไขการ WHERE เข้าไปด้วย ผมจะลองตั้งคำถามใหม่เป็น “อยากรู้ว่ามีพรรคไหนบ้างมีประธานาธิบดีที่ดำรงตำแหน่งเกิน 4 ปี แล้วมีกี่คน” ด้วยความต้องการนี้เราสามารถเขียนคำสั่ง SQL ได้ดังนี้

1
2
3
4
SELECT PARTY, COUNT(*)
FROM PRESIDENT
WHERE YRS_SERV > 4
GROUP BY PARTY

คราวนี้เรามาอธิบายการทำงานของการทำงาน GROUP BY กัน โดยคำสั่ง GROUP BY นั้นจะทำงานหลังคำสั่ง WHERE ก็คือ หลังใช้ WHERE เลือก ROW ที่เอาทั้งหมดแล้ว เราจะเริ่มจับกลุ่มด้วยคำสั่ง GROUP BY แบ่งข้อมูลออกเป็น GROUP จากนั้นดูที่ SELECT ต่อครับว่าให้เอาอะไรไปแสดง

คราวนี้มีเรื่องสำคัญจะบอกครับใน SELECT จะเป็นการเอาข้อมูลออกไปแสดงโดยจะเอาข้อมูลไปแสดงได้แค่ COLUMN ที่โดนสั่ง GROUP BY กับ Build in function เท่านั้น คราวนี้จะเกิดคำถามว่าทำไมเลือกแสดงได้แค่ COLUMN ที่โดน GROUP BY ล่ะ ก็ง่ายครับถ้าเราเจาะลึกลงไปในผลลัพธ์จากการ GROUP BY ด้วย PARTY โดยผมจะ Show ของ GROUP ของพรรค Republican

จะเห็นว่าผลลัพธ์ที่อยู่ใน GROUP นี้มีหลาย ROW ถ้าสมมุติจะ SELECT field อื่นที่ไม่ใช่ PARTY ไปแสดงจะเอา ROW ไหนไปแสดงล่ะ ในเมื่อไม่รู้สามารถตัดสินใจได้ก็เลยห้ามไม่ให้ทำซะเลยดีกว่า ส่วน Build in function นั้นจะทำงานกับกลุ่มของ ROW แล้วผลลัพธ์เหลือผลลัพธ์เดียวอยู่แล้วดังนั้นจึงสามารถเอาไปแสดงได้ ตัวอย่างเช่น COUNT(*) คือนับทุก ROW ในกลุ่มแล้วผลลัพธ์ออกมาเป็นค่าเดียวคือจำนวน ROW ในกลุ่ม

Build in function

Build in function ก็เป็น Function ที่ Database มีให้เราใช้ครับ โดย Database แต่ละเจ้าก็จะมี Build in function ให้เราเลือกใช้มากมาย โดย Build in function ที่ผมจะนำเสนอในตอนนี้จะเป็น Build in function ที่ทำงานกับกลุ่มของ ROW แล้วย่อยมันเหลือแค่คำตอบเดียว ส่วน Build in function อื่นๆค่อยพูดทีหลัง

Build in function ที่ทำงานกับกลุ่มของ ROW ที่เจอกันบ่อยๆจะมีดังนี้

  • COUNT
    มีไว้นับจำนวน ROW ในกลุ่มของ ROW นั้นว่ามีเท่าไหร่
  • MIN , MAX
    มีไว้หาค่าสูงสุดต่ำสุดของ COLUMN ที่ต้องการในกลุ่มนั้น
  • AVG
    มีไว้หาค่าเฉลี่ยของ COLUMN ที่ต้องการในกลุ่มนั้น
  • SUM
    มีไว้หาค่าผลรวมของ COLUMN ที่ต้องการในกลุ่มนั้น

ผมรวมทุก Build in function ที่นำเสนอมาในคำสั่งเดียวเลยละกัน

1
2
3
4
5
6
7
8
9
10
SELECT 
PARTY,
COUNT(*), -- นับทุก ROW
COUNT(DISTINCT STATE_BORN), -- นับ COLUMN STATE_BORN โดยนับเฉพาะที่ไม่ซ้ำ
MAX(YRS_SERV),
MIN(YRS_SERV),
AVG(YRS_SERV),
SUM(YRS_SERV)
FROM PRESIDENT
GROUP BY PARTY

Having

Having นั้นทำงานคล้ายๆ WHERE แต่ทำงานหลัง GROUP BY ง่ายๆคือจะเอา GROUP ไหนไปแสดง ตัวอย่างเช่น จาก QUERY ที่แล้ว อยากแสดงเฉพาะพรรคที่มีจำนวนประธานาธิบดีมากกว่า 4 ขึ้นไป เราสามารถเขียน Query ได้ดังนี้

1
2
3
4
5
6
7
8
9
10
11
SELECT 
PARTY,
COUNT(*),
COUNT(DISTINCT STATE_BORN),
MAX(YRS_SERV),
MIN(YRS_SERV),
AVG(YRS_SERV),
SUM(YRS_SERV)
FROM PRESIDENT
GROUP BY PARTY
HAVING COUNT(*) > 4

จะเห็นว่าผลลัพธ์ที่ทำการเพิ่ม HAVING COUNT(*) > 4 ผลลัพธ์จะแสดงเฉพาะกลุ่มที่ COUNT(*) > มากกว่า 4 ก็สำหรับ HAVING ก็ทำงานแค่นี้เลยง่ายมะ

จบตอนนี้แล้ว

ก็สำหรับตอนนี้ยาวหน่อยเพราะต้องพูดหลายเรื่องต้องปูทาง COUNT(*) กับ DISTINCT ก่อนเพื่อให้ไม่งง โดยหลังจากอ่านตอนนี้จบเราก็รู้เกี่ยวกับ KEY WORD เกือบจะทั้งหมดของ SQL แล้วไม่ว่าจะเป็น SELECT , FROM, WHERE, GROUP BY, HAVING, ORDER BY สำหรับตอนหน้าเราจะเข้าสู่เรื่อง JOIN ซึ่งเป็นอีก KEY WORD สำคัญที่จะทำให้เราสามารถเอาข้อมูลจากตารางอื่นๆมาใช้ได้ สำหรับตอนนี้จบแค่นี้ครับ

เพลงประกอบการเขียน Blog

เพลง “ออกอาการ” เพลงนี้ผมฟังตอนสมัยเรียนอุดมศึกษา ช่วงนั้น Facebook กับ Line กำลังดังมาก ตอนดู MV นี้ครั้งแรกอย่างงงเลยว่าจะสื่ออะไร แต่พอดูจบแล้วว้าวมากคือคิดได้ไงครับ ส่วนตัวเนื้อเพลงผมชอบมากคือมันคืออาการแบบนี้จริงๆเวลาคุยกับใครสักคนแล้วพอเขาเริ่มคิดว่าเราไม่ใช่เขาก็เริ่ม “ออกอาการ” บางอย่างให้เราเห็น

Basic SQL Part 2 - หาข้อมูลที่ต้องการด้วย WHERE และเรียงด้วย ORDER BY

หาข้อมูลที่ต้องการด้วย WHERE และเรียงด้วย ORDER BY

ผมเขียนเกี่ยวกับ SQL ไว้ 6 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ SQL ตอนต่างๆได้เลย

ตอนที่แล้วเราลองเล่นคำสั่ง SQL แบบ Basic มากๆไปแล้ว ตอนนี้เรามาลองเล่น SQL ภาษา SQL เพิ่มในส่วนของ WHERE และ ORDER กัน ซึ่งถ้าสามารถเขียนตรง WHERE กับ ORDER ได้นี่ก็จะเขียน SQL ได้เกิน 50 % ละ ดังนั้นเรามาเริ่มกันเลยดีกว่า

WHERE

WHERE คือ Keyword ที่ใช้บอกว่าจะเอา Row ไหนบ้างด้วยเงื่อนไขอะไร ตัวอย่างเช่น อยากรู้ว่าประธานาธิบดีคนไหนอยู่พรรค Republican บ้าง เราก็แค่เขียนคำสั่ง SQL ดังนี้ ซึ่งจะได้ผลลัพธ์ดังภาพ

1
2
3
SELECT *
FROM PRESIDENT
WHERE PARTY = 'Republican'

จะเห็นว่าผลลัพธ์ตรง Column PARTY ของทุก Row นั้นเป็น Republican ทั้งหมดเลย วิธีการทำงานของ WHERE นั้นขอให้คิดง่ายๆว่า มันจะไล่ดูทีละ Row ว่าตรงเงื่อนไขที่ให้มาไหม ถ้าใช่จะเก็บ Row นั้นไว้ ถ้าไม่ใช่ทิ้งทันที ถ้าจากตัวอย่างเราตั้งเงื่อนไขว่า จะเอาเฉพาะ Row ที่ Column : PARTY มีค่า Republican ออกมาเท่านั้น

( นอกเรื่องไม่อ่านก็ได้ การทำงานจริงๆของ DB อาจจะไม่ได้ไล่อ่านทีละ ROW ก็ได้นะครับ จริงๆมันอาจหาข้อมูลด้วยการใช้ Index ซึ่งจะเร็วกว่าการ SCAN หลายเท่า)

เชื่อมเงื่อนไขด้วย AND และ OR

โอเคเราสามารถ WHERE หาข้อมูลได้แล้ว แต่ถ้าสมมุติอยากรู้ว่า มีประธานาธิบดีคนไหนบ้างที่ไม่ได้อยู่พรรค Republican และไม่ได้อยู่พรรค Democratic (ตอนเด็กได้ยินแต่สองพรรคนี้เลยอยากรู้ว่ามีพรรคอื่นไหม) ซึ่งจากคำถามนี้เราสามารถเขียนคำสั่ง SQL ได้ดังนี้

1
2
3
SELECT *
FROM PRESIDENT
WHERE PARTY != 'Republican' AND PARTY != 'Democratic'

เมื่อกี้ลอง AND แล้วคราวนี้มาลอง OR บ้าง ถ้าสมมุติมีคำถามว่า อยากรู้ว่ามีประธานาธิบดีคนไหนเกิดที่รัฐ New York หรือ รัฐ New Jersey บ้าง คำถามนี้สามารถเขียนเป็นภาษา SQL ได้ดังนี้

1
2
3
SELECT * 
FROM PRESIDENT
WHERE STATE_BORN = 'New York' OR STATE_BORN = 'New Jersey'

ถ้าคราวนี้เราอยากรู้ว่ามี ประธานาธิบดีคนไหน ไม่ได้อยู่พรรค Republican และไม่ได้อยู่พรรค Democratic และ เกิดที่รัฐ New York หรือ รัฐ New Jersey เราจะเขียนยังไง คำตอบคือง่ายมากครับก็คอมโบต่อกันเลย

1
2
3
SELECT *
FROM PRESIDENT
WHERE ( PARTY != 'Republican' AND PARTY != 'Democratic' ) AND ( STATE_BORN = 'New York' OR STATE_BORN = 'New Jersey' )

WHERE มี Operation อะไรให้ใช้บ้าง

Operation ที่ SQL มีให้ใช้ก็มีไม่เยอะเท่าไหร่ครับก็มี

  • = , !=

    อันนี้ก็ง่ายๆเลยใช้เทียบว่าค่า = หรือ != ค่าที่อยากหารึเปล่า

  • >= , <= > , <

    อันนี้เหมือนในคณิตศาสตร์เลยครับหาค่ามากกว่าน้อยกว่า มากกว่าเท่ากับ น้อยกว่าเท่ากับ ตามเครื่องหมายเลย

  • IN , NOT IN

    อันนี้อาจจะเป็นของใหม่ แต่จริงๆมันไม่ใหม่หรอกมันแค่ส่งเสริมความขี้เกียจคือ บางทีเราอยากได้ค่าเท่ากับหลายๆค่า เช่น จากตัวอย่างที่เราพึ่งทำไป อยากรู้ว่ามีประธานาธิบดีคนไหนเกิดที่รัฐ New York หรือ รัฐ New Jersey บ้าง แทนที่จะเขียนแบบเดิม เราสามารถเขียนโดยการใช้ IN แทนได้ดังข้างล่าง

    1
    2
    3
    SELECT * 
    FROM PRESIDENT
    WHERE STATE_BORN IN ('New York','New Jersey')

    IN ก็คือ อยากให้ค่าที่หาตรงกับค่าใดได้บ้างก็ใช้ IN

    ในทำนองเดียวกันกับตัวอย่างเรื่องพรรค เราก็สามารถเปลี่ยนมาใช้ NOT IN ได้

    1
    2
    3
    SELECT *
    FROM PRESIDENT
    WHERE PARTY NOT IN ('Republican', 'Democratic')
  • LIKE อันนี้เป็น KEY WORD ใหม่อีกอัน อันนี้มีใช้ทำงานกับพวกข้อมูลที่เป็น String (อะไรที่เป็นชุดของตัวอักษร) เช่น ถ้าอยากรู้ว่าประธานาธิบดีคนไหนบ้างที่ชื่อ ขึ้นต้นด้วยตัว N ด้วยความต้องการแบบนี้เลยเกิด LIKE ขึ้นมา โดยเราสามารถเขียนคำสั่ง SQL ได้ดังนี้

    1
    2
    3
    SELECT * 
    FROM PRESIDENT
    WHERE PRES_NAME LIKE 'T%'

    ตรงค่า ‘T%’ นั้น % หมายความว่าอะไรก็ได้ ดังนั้น T% จึงแปลว่าค้นหา String ที่ขึ้นต้นด้วย T แล้วตามด้วยอะไรก็ได้

    ถ้าสมมุติเราอยากรู้ว่าประธานาธิบดีคนไหนมีตัวอักษร x อยู่ในชื่อบ้าง เราก็สามารถเขียน SQL ได้เป็น

    1
    2
    3
    SELECT * 
    FROM PRESIDENT
    WHERE PRES_NAME like '%x%'

    ‘%x%’ แปลว่า String อะไรก็ได้ที่ขึ้นต้นด้วยอะไรก็ได้ แล้วมี x แล้วลงท้ายอะไรก็ได้ ว่าง่ายมี x อยู่ใน String นั้น

  • IS
    อันนี้เหมือน = เลย แต่เราจะใช้ IS กับค่าที่เป็น NULL โดย NULL แปลว่าไม่ได้กำหนด ส่วนใหญ่เราจะใช้ NULL กับค่าที่ไม่ได้กำหนด ไม่รู้ว่าคืออะไร NULL นั้นไม่ใช่ค่าว่าง ‘’ นะครับ ค่าว่างคือรู้ค่าว่าคือค่าว่าง แต่ NULL คือไม่รู้ค่าเลยว่าเป็นอะไรเลยให้เป็น NULL ตัวอย่างการใช้ NULL ก็คือ อยากรู้ว่าประธานาธิบดีคนไหนยังไม่ตาย ซึ่งการยังไม่ตายนั้นแปลว่าไม่มีค่า DEATH_AGE ซึ่งก็แปลว่า DEATH_AGE นั้นมีค่าเป็น NULL เราจึงสามารถเขียนคำสั่ง SQL ได้ดังนี้

    1
    2
    3
    SELECT * 
    FROM PRESIDENT
    WHERE DEATH_AGE IS NULL

ORDER BY

ORDER BY เป็น keyword ที่มีไว้สำหรับการเรียง ซึ่งเกิดมาจากในงานจริงเราอยากดูข้อมูลที่เรียงด้วยอะไรบางอย่างอยู่บ่อยๆ ถ้าอย่างเรื่องเรียนก็อยากดูข้อมูลโดยเรียงลำดับคนที่ได้คะแนนมากไปหาน้อย หรือ อยากดูข้อมูลนักเรียนเรียงตามเลขที่ อยากดูบริษัทที่มียอดสั่งซื้อสูงสุดเรียงไปหาต่ำสุด คราวนี้ถ้าอยากแสดงข้อมูลประธานาธิบดีที่อยู่พรรค Republican โดยเรียงตามปีเกิด เราจะเขียนคำสั่ง SQL ได้ดังนี้

1
2
3
4
SELECT *
FROM PRESIDENT
WHERE PARTY = 'Republican'
ORDER BY BIRTH_YR

แต่ถ้าอยากเรียงจากปีเกิดที่มากไปน้อยล่ะจะทำไง ก็ไม่อยากเลยครับเติม Key word DESC ตามหลังชื่อฟิลล์ที่อยากให้เรียงเท่านั้นเอง

1
2
3
4
SELECT *
FROM PRESIDENT
WHERE PARTY = 'Republican'
ORDER BY BIRTH_YR DESC

อันนี้จะต้องมีคำถามแน่ๆว่า “เรียงหลาย field ได้ไหม” ซึ่งก็ตอบเลยว่าได้ ไม่ยากด้วยก็แค่ใส่ชื่อ field ที่อยากเรียงตามต่อไป เช่น แสดงข้อมูลประธานาธิบดีที่อยู่พรรค Republican โดยตาม จำนวนปีที่ดำรงตำแหน่งจากมากไปหาน้อย จากนั้นเรียงด้วยชื่อจากน้อยไปหามาก ด้วยคำถามนี้เราสามารถเขียน SQL แบบนี้

1
2
3
4
SELECT *
FROM PRESIDENT
WHERE PARTY = 'Republican'
ORDER BY YRS_SERV DESC, PRES_NAME

จบตอนนี้แล้ว

สำหรับตอนนี้เราได้รู้เกี่ยวกับการ WHERE ด้วยเงื่อนไขต่างๆการใช้ AND OR เชื่อมเงื่อนไข และการใช้ ORDER BY ในการเรียงข้อมูล ซึ่งในจากเรื่องที่เรียนตอนนี้ผมว่าหลายๆคนคงจะเริ่มเข้าใจการทำงานของ SQL มากขึ้นแล้ว สำหรับตอนต่อไปเราจะมีพูดถึงเรื่องการใช้ GROUP BY , Build in function และ HAVING กันว่ามันคืออะไร ทำงานอย่างไร คำถามแบบไหนที่เจอแล้วเข้าข่ายว่าจะใช้ Key word พวกนี้ สำหรับตอนนี้ขอตัดจบก่อนครับ

เพลงประกอบการเขียน Blog

เพลงเหนื่อยของวง SUDDENLY ฟังแล้วอารมณ์คล้ายๆกับเพลง เหนื่อยใจ เลย พอฟังเพลงแนวนี้ทีไรนึกถึงตอนเรียนวิชา Digital ที่พูดถึงเรื่อง AND gate ที่ถ้าขานึงมันเป็น FALSE แล้ว มันจะได้ FALSE เสมอ ไม่ว่าจะพยายามใส่ค่าที่ขาอีกข้างหนึ่งเป็นอะไรมันไร้ประโยชน์

Basic SQL Part 1 - เริ่มต้นกับ SQL ด้วยวิธีธรรมดา ไม่ยาก ไม่ง่าย

เริ่มต้นกับ SQL ด้วยวิธีธรรมดา ไม่ยากแล้วก็ไม่ง่าย

ผมเขียนเกี่ยวกับ SQL ไว้ 6 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ SQL ตอนต่างๆได้เลย

ในยุคสมัยที่งานเกี่ยวกับ Data กำลังดังแบบหยุดไม่อยู่ ใครๆก็อยากมาทำงานสาย Data ถ้าจะก้าวย่างเข้ามาสายนี้ก็คงจะเคยได้ยินคำว่า SQL (อ่านได้หลายอย่าง เอส-คิว-แอล , ซี-ควล , ซี-เควล ใครจะอ่านแบบไหนก็ตามใจเลยครับ การเรียกมันแล้วแต่ถิ่นที่นั้นจะเรียกแบบไหน ไม่มีถูกไม่มีผิด) แล้ว SQL คืออะไร จริงๆมันย่อมาจาก Structured Query Language ซึ่งมีอธิบายไว้มากมายซึ่งน่าจะอธิบายดีกว่าผมสามารถไปอ่านได้ WIKI MEDIUM ของคุณ Todspol Wonhchomphu

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

แต่ก่อนจะอธิบาย SQL จนยืดยาวเรามาอธิบายเรื่อง Database กันก่อน

Database คือที่เก็บข้อมูล

Database คือที่เก็บข้อมูลครับ พอเราจะเก็บข้อมูลเราจะมาเก็บที่ Database คราวนี้ก็จะมีคำถามว่าเก็บยังไงใช่ไหมครับ ซึ่ง Database ก็มีวิธีเก็บข้อมูลหลากหลายรูปแบบตามแต่ละชนิดของ Database เลย โดย Database ที่เราจะใช้กับภาษา SQL นั้นจะถูกเก็บและแสดงข้อมูลในลักษณะตาราง (จริงๆผมควรใช้คำว่า Interface ที่ Database แสดงให้เราเห็นเวลาดึง หรือ เก็บข้อมูล เป็นแบบตาราง แต่การ Implement การเก็บข้อมูลจริงๆนั้น อาจจะไม่เป็นตาราง แต่เดี๋ยวจะงง และผมก็เชื่อว่าคนที่อ่านในวงเล็บนี่น่าจะงงแล้ว ) ตัวอย่างเช่น ข้อมูลประธานาธิบดีสหรัฐ

ข้อมูลประธานาธิบดีสหรัฐ

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

ดังนั้นถ้าเราอยากตอบคำถามด้านบนเราก็แค่ออกคำสั่งว่า “แสดงข้อมูลของประธานาธิบดีที่มีอายุตอนตายมากกว่า 60” ตัว Database ก็จะไปเอาข้อมูลออกมาให้ คำสั่งนี่แหละคือ SQL ไง ง่ายไหม SQL ก็คือคำสั่งที่สั่งให้ Database ไปเอาข้อมูลที่ต้องการออกมาให้

ลองสร้าง Database กัน

ตอนผมหัดเล่น SQL ตอนเรียนปี 3 นั้น พบความยุ่งยากเกี่ยวกับการที่ต้องมานั่ง Install ตัว Database server ที่ใช้เก็บข้อมูล เพื่อนผมบางคนลงแล้ว Run ไม่ได้ ถอดใจไม่ลองเล่นเลยก็มี แต่โชคดีตอนนี้เราสามารถสร้าง Database แล้วใช้งานแบบ Online โดยไม่ต้องลงโปรแกรมได้แล้ว โดยเราจะใช้งานผ่าน Web : https://sqliteonline.com/

จากนั้น copy คำสั่งด้านล่างนี้เพื่อเก็บข้อมูลเกี่ยวกับประธานาธิบดีสหรัฐลงใน Database

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
CREATE TABLE IF NOT EXISTS PRESIDENT (
`PRES_NAME` VARCHAR(128) ,
`BIRTH_YR` INT,
`YRS_SERV` INT,
`DEATH_AGE` INT ,
`PARTY` VARCHAR(128) ,
`STATE_BORN` VARCHAR(128)
);
INSERT INTO PRESIDENT VALUES
('Washington G',1732,7,'67','Federalist','Virginia'),
('Adams J',1735,4,'90','Federalist','Massachusetts'),
('Jefferson T',1743,8,'83','Demo-Rep','Virginia'),
('Madison J',1751,8,'85','Demo-Rep','Virginia'),
('Monroe J',1758,8,'73','Demo-Rep','Virginia'),
('Adams J Q',1767,4,'80','Demo-Rep','Massachusetts'),
('Jackson A',1767,8,'78','Democratic','South Carolina'),
('Van Buren M',1782,4,'79','Democratic','New York'),
('Harrison W H',1773,0,'68','Whig','Virginia'),
('Tyler J',1790,3,'71','Whig','Virginia'),
('Polk J K',1795,4,'53','Democratic','North Carolina'),
('Taylor Z',1784,1,'65','Whig','Virginia'),
('Fillmore M',1800,2,'74','Whig','New York'),
('Pierce F',1804,4,'64','Democratic','New Hampshire'),
('Buchanan J',1791,4,'77','Democratic','Pennsylvania'),
('Lincoln A',1809,4,'56','Republican','Kentucky'),
('Johnson A',1808,3,'66','Democratic','North Carolina'),
('Grant U S',1822,8,'63','Republican','Ohio'),
('Hayes R B',1822,4,'70','Republican','Ohio'),
('Garfield J A',1831,0,'49','Republican','Ohio'),
('Arthur C A',1830,3,'56','Republican','Vermont'),
('Cleveland G',1837,8,'71','Democratic','New Jersey'),
('Harrison B',1833,4,'67','Republican','Ohio'),
('McKinley W',1843,4,'58','Republican','Ohio'),
('Roosevelt T',1858,7,'60','Republican','New York'),
('Taft W H',1857,4,'72','Republican','Ohio'),
('Wilson W',1856,8,'67','Democratic','Virginia'),
('Harding W G',1865,2,'57','Republican','Ohio'),
('Coolidge C',1872,5,'60','Republican','Vermont'),
('Hoover H C',1874,4,'90','Republican','Iowa'),
('Roosevelt F D',1882,12,'63','Democratic','New York'),
('Truman H S',1884,7,'88','Democratic','Missouri'),
('Eisenhower D D',1890,8,'79','Republican','Texas'),
('Kennedy J F',1917,2,'46','Democratic','Massachusetts'),
('Johnson L B',1908,5,'65','Democratic','Texas'),
('Nixon R M',1913,5,NULL,'Republican','California'),
('Ford G R',1913,2,NULL,'Republican','Nebraska'),
('Carter J E',1924,4,NULL,'Democratic','Georgia'),
('Reagan R',1911,3,NULL,'Republican','Illinois');

พอกด Run เสร็จจะได้ผลลัพธ์ดังภาพด้านล่าง ซึ่งจะเห็นว่ามีตาราง PRESIDENT โผล่ขึ้นมาแล้ว

ตัว Database แบบนี้นั้นจะเก็บข้อมูลเป็นตาราง โดยสามารถเก็บได้หลายตาราง โดยแต่ละตารางเป็นข้อมูลที่เกี่ยวข้องกันหรือไม่เกี่ยวข้องกันก็ได้ แต่ละตารางสามารถมี Column ที่จะเก็บข้อมูลไม่เหมือนกันก็ได้ เช่น จากตัวอย่าง

ตาราง PRESIDENT

เก็บข้อมูล 5 Column คือ

  • PRES_NAME : ชื่อประธานาธิบดี
  • BIRTH_YR : เกิดปี ค.ศ. อะไร
  • YRS_SERV : จำนวนปีที่ดำรงตำแหน่ง
  • DEATH_AGE : อายุรวมกี่ปีตอนเสียชีวิต
  • STATE_BORN : เกิดที่รัฐไหน

ตาราง DEMO

เก็บข้อมูล 3 Column คือ

  • ID
  • NAME
  • HINT

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

ลองคำสั่ง Basic SQL กัน

เรามาลองคำสั่งที่ Basic ที่สุดของภาษา SQL นั่นคือคำสั่ง SELCT * FROM โดยทำการลอง Copy code ข้างล่างไปใส่ในช่อง Query จากนั้นทำการกด Run ตามภาพ

1
2
SELECT *
FROM PRESIDENT

ซึ่งผลลัพธ์ที่ได้คือข้อมูลทั้งหมดในตาราง PRESIDENT ออกมา คราวนี้เราลองเปลี่ยนคำสั่งเป็นคำสั่งด้านล่าง แล้วลอง Run ดู

1
2
SELECT PRES_NAME, BIRTH_YR, DEATH_AGE
FROM PRESIDENT

จะเห็นว่าผลลัพธ์ที่ออกมาจะเหลือแค่ 3 Column คือ PRES_NAME, BIRTH_YR, DEATH_AGE ซึ่งพอลองมาถึงตรงนี้ก็คงจะพอเข้าใจ Key word SELECT กับ FROM แล้ว

อธิบาย

1
2
3
4
5
6
7
8
SELECT PRES_NAME, BIRTH_YR, DEATH_AGE 
-- SELECT เป็นการบอกว่าจะแสดงข้อมูล Column อะไรบ้าง
-- โดยในตัวอย่างคือแสดง Column : PRES_NAME, BIRTH_YR, DEATH_AGE
-- ถ้าเป็น * แปลว่าเอาทุก Column

FROM PRESIDENT
-- FROM เป็นการออกบอกว่าไปเอาข้อมูลจากตารางอะไร
-- ในตัวอย่างนี้คือเอาข้อมูลจากตาราง PRESIDENT

ลองเล่นดูเองบ้าง

คราวนี้เพื่อความเข้าใจลองเล่นคำสั่ง SQL กันเองดูบ้างเช่น เปลี่ยน FROM เป็นค่าอื่น เปลี่ยนค่า SELECT เป็นค่าอื่น แล้วดูว่าจะเกิดอะไรขึ้น

1
2
3
4
5
6
7
8
9
10
11
12
-- SQL 1
SELECT *
FROM demo


-- SQL 2
SELECT PRES_NAME, BIRTH_YR, DEATH_AGE
FROM demo

-- SQL 3
SELECT ID
FROM PRESIDENT

สรุป

สำหรับตอนนี้เราได้รู้จักว่า SQL คืออะไร Database ที่จะใช้กับ SQL เก็บข้อมูลในลักษณะแบบไหน แล้วก็ลองสร้างและใช้ Database ผ่านเว็บ https://sqliteonline.com/ และก็ได้ทดลองใช้คำสั่ง SQL พื้นฐานกัน ในส่วนตอนถัดไปเราจะมาลงลึกเกี่ยวกับ SQL กันต่อ ส่วนตอนนี้ขอจบเท่านี้ครับ

เพลงประกอบการเขียน Blog

เพลง my moon ของ น้องแจม และ น้องข้าวเจ้า