เก่งโค้ดงาน Business Intelligence ตอนที่ 5
![เก่งโค้ดงาน Business Intelligence ตอนที่ 5](/sites/default/files/images/articles/business-Intelligence-part-3_0.jpg)
เก่งโค้ดงาน Business Intelligence ตอนที่ 5
คุณสมบัติการปิด
ฟังก์ชันใด ๆ สามารถส่งค่ากลับเป็นฟังก์ชันได้ และฟังก์ชันนั้นอาจขึ้นกับค่าของพารามิเตอร์หนึ่งตัวหรือมากกว่าของฟังก์ชันเดิมในรูป แสดงคุณสมบัติการปิด ในโค้ดนี้ฟังก์ชันที่คู่กับฟิลด์ MyFunction ส่งค่ากลับเป็นฟังก์ชันที่ส่งค่าของพารามิเตอร์ที่กำหนดให้แก่ตัวมัน ค่าใหม่ของฟังก์ชันจะถูกส่งกลับมาทำ แต่ละครั้งที่ฟังก์ชันถูกเรียก ค่าของพารามิเตอร์จึงถูกส่งกลับไป
ฟังก์ชันกับสภาพแวดล้อม
นอกเหนือจากพารามิเตอร์แล้วไส้ของฟังก์ชัน (ส่วนที่เป็นนิพจน์) สามารถอ้างถึงตัวแปรที่อยู่ภายในสภาพแวดล้อมตอนที่ฟังก์ชันเริ่มการทำงาน ยกตัวอย่างเช่น ในรูป ฟังก์ชันที่ถูกนิยามโดยฟิลด์ MyFunction สามารถเข้าถึงฟิลด์ C ที่อยู่ภายในเรคคอร์ A ได้ เมื่อเราเรียกฟังก์ชัน MyFunction มันจะอ่านค่าตัวแปร C ซึ่งสามารถทำได้ แม้ว่าเราจะเรียกให้มันทำงานจากภายในสภาพแวดล้อม B ซึ่งไม่มีตัวแปร C
การประกาศแบบลดรูป
นิพจน์ each คือซินแท็กซ์แบบลดรูปสำหรับใช้ประกาศฟังก์ชันที่ไม่มีไทป์ที่รับพารามิเตอร์ชื่อ _ (ขีดเส้นใต้) เราสามารถใช้ซินแท็กซ์การประกาศแบบลดรูปเพื่อทำให้โค้ดอ่านง่ายขึ้นเมื่อเรียกฟังก์ชันที่มีลำดับสูงกว่า ยกตัวอย่างเช่นในรูป
บรรทัด 3 คือการเขียนลดรูปของโค้ดบรรทัดที่ 4 ซึ่งมีการทำงานเหมือนกันทุกประการ และบรรทัด 6 คือการเขียนลดรูปของ 7 และ 9 คือการลดรูปของ 10
บรรทัด 3 คือการเขียนลดรูปของโค้ดบรรทัดที่ 4 ซึ่งมีการทำงานเหมือนกันทุกประการ และบรรทัด 6 คือการเขียนลดรูปของ 7 และ 9 คือการลดรูปของ 10
การส่งเออเรอร์
ซินแท็กซ์ของการส่งเออเรอร์ในภาษาเพาเวอร์คิวรีเป็นอย่างที่เห็นนในรูป เราสามารถใช้ค่าตัวอักษรเพื่อเป็นการเขียนแบบสั้นแทนค่าเออเรอร์ได้อย่างที่เห็นในบรรทัดที่ 7
บรรทัดที่ 10 คือใช้วิธีสร้างเรคคอร์ดด้วยฟังก์ชัน Error.Record ที่เขียนเขียนเต็มรูปแบบจะเป็นอย่างบรรทัด 12-17 เมื่อส่งเออเรอร์แล้วการทำงานจะหยุดที่นิพจน์นั้น
บรรทัดที่ 10 คือใช้วิธีสร้างเรคคอร์ดด้วยฟังก์ชัน Error.Record ที่เขียนเขียนเต็มรูปแบบจะเป็นอย่างบรรทัด 12-17 เมื่อส่งเออเรอร์แล้วการทำงานจะหยุดที่นิพจน์นั้น
การจัดการกับเออเรอร์
ซินแท็กซ์ของการจัดการกับเออเรอร์เป็นอย่างที่เห็นในรูป
บรรทัดที่ 4-11 จะเห็นว่ามีนิพจน์ต่าง ๆ อยู่สี่แบบให้เลือกใช้งาน ยกตัวอย่างวิธีใช้งานคือถ้าการทำงานของนิพจน์ไม่มีเออเรอร์และได้ค่าเป็น x หากเกิดเออเรอร์จะได้เรคคอรด์หน้าตาอย่างที่เห็นในบรรทัดที่ 16 หรือถ้าการทำงานของนิพจน์ทำให้เกิดเออเรอร์ e ผลลัพธ์ของนิพจน์ y การเออเรอร์จะได้เป็นเรคคอร์อย่างที่เห็นในบรรทัดที่ 17
บรรทัดที่ 4-11 จะเห็นว่ามีนิพจน์ต่าง ๆ อยู่สี่แบบให้เลือกใช้งาน ยกตัวอย่างวิธีใช้งานคือถ้าการทำงานของนิพจน์ไม่มีเออเรอร์และได้ค่าเป็น x หากเกิดเออเรอร์จะได้เรคคอรด์หน้าตาอย่างที่เห็นในบรรทัดที่ 16 หรือถ้าการทำงานของนิพจน์ทำให้เกิดเออเรอร์ e ผลลัพธ์ของนิพจน์ y การเออเรอร์จะได้เป็นเรคคอร์อย่างที่เห็นในบรรทัดที่ 17
บรรทัด 4-8 แสดงตัวอย่างนิพจน์จัดการเออเรอร์ในกรณีที่ไม่เกิดเออเรอร์
บรรทัด 10-14 คือกรณีที่เกิดเออเรอร์ เราสามารถใช้คำสั่ง otherwise เพื่อแทนที่การดักเออเรอร์ให้ไปทำงานนิพนจ์อื่นแทน
บรรทัด 16,17 แต่ถ้านิพจน์ของ otherwise เกิดเออร์ด้วยเหมือนกันก็จะมีผลเหมือนนิพจน์ try ทั้งก้อนเกิดเออเรอร์อย่างบรรทัดที่ 19,20
บรรทัด 10-14 คือกรณีที่เกิดเออเรอร์ เราสามารถใช้คำสั่ง otherwise เพื่อแทนที่การดักเออเรอร์ให้ไปทำงานนิพนจ์อื่นแทน
บรรทัด 16,17 แต่ถ้านิพจน์ของ otherwise เกิดเออร์ด้วยเหมือนกันก็จะมีผลเหมือนนิพจน์ try ทั้งก้อนเกิดเออเรอร์อย่างบรรทัดที่ 19,20
บรรทัด 4-12 ตัวกำหนดค่าเริ่มต้นให้แก่เรคคอร์ดที่มีฟิลด์ A ซึ่งมีค่าการส่งเออเรอร์และมีผู้เรียกหาสองตัวคือฟิลด์ B และ C โดยฟิลด์ B ไม่มีตัวจัดการเออเรอร์ที่ A ส่งมาแต่ฟิลด์ C มี ส่วนฟิลด์ D ไม่ได้อ้างถึง A จึงไม่มีผลต่อการส่งเออเรอร์ของ A เมื่อเรคคอร์ถูกประเมินค่าจะได้ผลลัพธ์อย่างที่เป็นในบรรทัด 14-19 เนื่องจากในภาษาเอ็มการกำหนดค่าเริ่มต้นให้แก่ฟิลด์ และการทำงานของคุณสมบัติการปิด มีการทำงานเป็นแบบ “ประวิง” (lazy field initialization) ดังนั้นจึงควรให้โค้ดซึ่งทำหน้าที่จัดการเออเรอร์อยู่ใกล้ตำแหน่งที่จะเกิดเออเรอร์เอาไว้
บรรทัด 21-25 แสดงตัวอย่างการพยายามจัดการกับเออเรอร์ที่ทำได้ได้ถูกต้อง โดยเป็นการทำงานที่อาศัยนิพจน์ try
บรรทัด 21-25 แสดงตัวอย่างการพยายามจัดการกับเออเรอร์ที่ทำได้ได้ถูกต้อง โดยเป็นการทำงานที่อาศัยนิพจน์ try
บ่อยครั้งที่ระหว่างการพัฒนาโปรแกรมเราอาจต้องการใส่ภาคส่วนของโค้ดไว้ก่อน แต่ยังไม่ต้องการใส่ตัวนิพจน์ที่เป็นไส้ในตอนนั้น ในกรณีนี้เราควรจะใส่โค้ดการทำเออเรอร์เพื่อใช้ระบุว่ายังไม่ได้ใส่โค้ดไว้
บรรทัดที่ 4-8 คือตัวอย่างโค้ดการทำเออเรอร์เพื่อใช้ระบุว่ายังไม่ได้ใส่โค้ด ภาษาเอ็มมีซินแท็กซ์ที่ช่วยให้เราสามารถเขียนย่อโค้ดนี้ลงได้
บรรทัดที่ 10 คือโค้ดที่เราสามารถใส่จุดสามจุดเขียนติดกันแทนที่ได้ นั่นคือเราจะเขียนแบบเต็มอย่างบรรทัดที่ 4-8 ก็ได้ หรือจะเขียนย่ออย่างบรรทัดที่ 13 ก็ได้ ทั้งสองแบบให้ผลลัพธ์การทำงานเหมือนกัน
บรรทัดที่ 4-8 คือตัวอย่างโค้ดการทำเออเรอร์เพื่อใช้ระบุว่ายังไม่ได้ใส่โค้ด ภาษาเอ็มมีซินแท็กซ์ที่ช่วยให้เราสามารถเขียนย่อโค้ดนี้ลงได้
บรรทัดที่ 10 คือโค้ดที่เราสามารถใส่จุดสามจุดเขียนติดกันแทนที่ได้ นั่นคือเราจะเขียนแบบเต็มอย่างบรรทัดที่ 4-8 ก็ได้ หรือจะเขียนย่ออย่างบรรทัดที่ 13 ก็ได้ ทั้งสองแบบให้ผลลัพธ์การทำงานเหมือนกัน
การแบ่งกลุ่มโค้ด
ในภาษาเอ็มเราสามารถจัดกลุ่มของโค้ดได้โดยอาศัยซินแท็กซ์ที่เรียกว่า “เซคชัน” (section) เราแบ่งเซคชันของโค้ดเพื่อให้นิพจน์ที่มีความสัมพันธ์กันอยู่เป็นกลุ่มเดียวกัน ในหนึ่งเซคชันประกอบด้วยชื่อของเซคชัน ทำหน้าที่จำแนกความแตกต่างและไว้ใช้อ้างถึงเซคชัน และส่วนชื่อของสมาชิกต่าง ๆ ที่ถูกประกาศไว้ภายในเซคชัน บรรทัดที่ 4-6 เป็นโค้ดตัวอย่างเซคชันหนึ่งเซคชัน
สมาชิกของเซคชันหนึ่งจะมองไม่เห็นสมาชิกของเซคชันอื่น ๆ แต่สมาชิกของเซคชันหนึ่งสามารถอ้างถึงสมาชิกของอีกเซคชันหนึ่งได้โดยใช้วิธี “นิพจน์เข้าถึงเซคชัน” (Section Access Expression ย่อ SAE) วิธีทำคือให้ใส่ชื่อเซคชันที่มีสมาชิกที่ต้องการ ใส่เครื่องหมายตกใจ ! แล้วตามด้วยชื่อสมาชิก ยกตัวอย่างเช่นบรรทัดที่ 10 เมื่อฟิลด์ B ซึ่งเป็นสมาชิกของเซคชัน Section1 ต้องอ้างถึงฟิดล์ A ที่เป็นสมาชิกของเซคชัน Section2 ก็สามารถทำได้โดยวิธี SAE ด้วยการเขียนว่า Section2!A
เราอาจใช้คำสั่ง shared เพื่อประกาศว่าสมาชิกของเซคชันหนึ่ง ๆ สามารถเข้าถึงจากเซคชันอื่น ๆ ได้โดยไม่ต้องใช้วิธี SAE นั่นคือสมาชิกของเซคชันใด ๆ จะมองเห็นสมาชิกที่เป็นแบบแชร์ของเซคชันอื่นได้โดยตรง แต่มีข้อแม้ว่าเซคชันที่มีโค้ดเพื่ออ้างถึงจะต้องไม่มีสมาชิกที่มีชื่อซ้ำกันกับสมาชิกแบบแชร์ของเซคชันปลายทาง
ยกตัวอย่างเช่น บรรทัด 16,17 คือเซคชันชื่อ Section1
บรรทัด 17 กระกาศฟิลด์ A โดยมีคำสั่ง shared นำหน้า มีผลให้นิพจน์ในเซคชันอื่น ๆ จะสามารถอ้างถึงสมาชิกตัวนี้ได้โดยไม่ต้องเขียนแบบ SAE
บรรทัด 20 ฟิลด์ B ซึ่งเป็นสมาชิกของเซคชัน Section2 สามารถอ้างถึง A ได้โดยไม่ต้องเขียนแบบ SAE
บรรทัด 25 ฟิลด์ C ซึ่งเป็นสมาชิกของเซคชัน Section3 ไม่สามารถอ้างถึง A ได้โดยตรง แต่ต้องเขียนแบบ SAE เพราะใน Section3 เองก็มีฟิลด์ที่ชื่อ A เป็นสมาชิกอยู่ด้วยเหมือนกัน หากไม่เขียนแบบ SAE จะเกิดความกำกวมว่าเป็นการอ้างถึง A ตัวในบรรทัดที่ 23 หรือ 17
บรรทัด 17 กระกาศฟิลด์ A โดยมีคำสั่ง shared นำหน้า มีผลให้นิพจน์ในเซคชันอื่น ๆ จะสามารถอ้างถึงสมาชิกตัวนี้ได้โดยไม่ต้องเขียนแบบ SAE
บรรทัด 20 ฟิลด์ B ซึ่งเป็นสมาชิกของเซคชัน Section2 สามารถอ้างถึง A ได้โดยไม่ต้องเขียนแบบ SAE
บรรทัด 25 ฟิลด์ C ซึ่งเป็นสมาชิกของเซคชัน Section3 ไม่สามารถอ้างถึง A ได้โดยตรง แต่ต้องเขียนแบบ SAE เพราะใน Section3 เองก็มีฟิลด์ที่ชื่อ A เป็นสมาชิกอยู่ด้วยเหมือนกัน หากไม่เขียนแบบ SAE จะเกิดความกำกวมว่าเป็นการอ้างถึง A ตัวในบรรทัดที่ 23 หรือ 17
การอ้างชื่อแบบ SAE จะมีผลให้เกิดเออเรอร์กรณีที่กำหนดชื่อสมาชิกแบบแชร์ไว้ซ้ำกันในหลายเซคชัน ยกตัวอย่างเช่น
บรรทัด 5 เซคชัน Section1 มีสมาชิกแบบแชร์ชื่อ A และบรรทัด 8 เซคชัน Section2 ก็มีสมาชิกแบบแชร์ชื่อ A ด้วย
บรรทัด 11 สมาชิก B ของเซคชัน Section3 พยายามอ้างถึงสมาชิกแบบแชร์จึงมีผลให้เกิดความกำกวมว่าเป็นการอ้างถึง A ในบรรทัดที่ 5 หรือ 8
บรรทัด 5 เซคชัน Section1 มีสมาชิกแบบแชร์ชื่อ A และบรรทัด 8 เซคชัน Section2 ก็มีสมาชิกแบบแชร์ชื่อ A ด้วย
บรรทัด 11 สมาชิก B ของเซคชัน Section3 พยายามอ้างถึงสมาชิกแบบแชร์จึงมีผลให้เกิดความกำกวมว่าเป็นการอ้างถึง A ในบรรทัดที่ 5 หรือ 8
ตัวแปร #sections เป็นตัวแปรของระบบมีไว้ตรวจสอบว่ามีเซคชันอะไรบ้างในขณะนั้นโดยให้ค่าเป็นเรคคอร์ด ยกตัวอย่างเช่น เรามีเซคชันสองเซคชัน คือ Section1, Section2 อย่างที่เห็นในบรรทัด 13-19 ค่าของ #sections จะเป็นอย่างที่เห็นในบรรทัด 22-24
ตัวแปร #shared เป็นตัวแปรของระบบมีไว้ตรวจสอบว่ามีสมาชิกอะไรบ้างที่ถูกแชร์อยุ่ในขณะนั้นโดยให้ค่าเป็นเรคคอร์ด ยกตัวอย่างเช่น เรามีเซคชันสองเซคชัน คือ Section1, Section2 อย่างที่เห็นในบรรทัด 26-32 ค่าของ #shared จะเป็นอย่างที่เห็นในบรรทัด 33-37
ตัวอย่างโค้ดที่ทำงานกับตาราง
เราสามารถเขียนโค้ดอ่านตารางเวิร์กชีตมาจากฮาร์ดดิสก์แล้วเขียนโค้ดเพื่อทำสิ่งต่าง ๆ กับข้อมูลในตารางได้ ยกตัวอย่างเช่น
แสดงโค้ดการนับจำนวนแถวข้อมูลในตารางโดยใช้ฟังก์ชัน TableRow.Count() เมื่อคิวรีนี้ทำงานจะได้ตัวเลขจำนวนเต็มหนึ่งตัว แสดงจำนวนแถวข้อมูล โดย CountRowsInTable เป็นตารางที่มีแถวข้อมูลเพียงแถวเดียวและมีคอลัมน์อยู่เพียงคอลัมน์เดียว
แสดงโค้ดการนับจำนวนแถวข้อมูลในตารางโดยใช้ฟังก์ชัน TableRow.Count() เมื่อคิวรีนี้ทำงานจะได้ตัวเลขจำนวนเต็มหนึ่งตัว แสดงจำนวนแถวข้อมูล โดย CountRowsInTable เป็นตารางที่มีแถวข้อมูลเพียงแถวเดียวและมีคอลัมน์อยู่เพียงคอลัมน์เดียว
ในกรณีที่ต้องการผลลัพธ์เป็นชนิดข้อมูลแบบตารางหรือถ้าต้องการทำแอกกริเกต (aggregation การรวมตัวหรือการจัดกลุ่ม) แบบอื่น ๆ เราจะต้องใช้ฟังก์ชัน Table.Group() แทนการใช้ฟังก์ชัน TableRow.Count() โดยฟังก์ชัน Table.Group() มีซิกเนเจอร์อย่างที่เห็นในบรรทัดที่ 11,12 พารามิเตอร์ตัวแรกคือตารางที่มีข้อมูลที่จะแอกริเกต พารามิเตอร์ตัวที่สองคือรายการซึ่งประกอบด้วยรายชื่อของคอลัมน์ที่จะจับกลุ่มด้วยการทำ group by พารามิเตอร์ตัวที่สามใช้กำหนดวิธีแอกริเกต บรรทัด 14-21 แสดงตัวอย่างโค้ดการนับจำนวนแถวข้อมูลในตาราง
โปรดสังเกตบรรทัด 19, 20 พารามิเตอร์ตัวแรกคือ Source ซึ่งได้จากการทำงานในบรรทัดที่ 16 พารามิเตอร์ตัวที่สองคือ “ลิสต์ว่าง” เพราะในกรณีนี้เราไม่ต้องการจัดกลุ่มคอลัมน์ใด ๆ ในตาราง ถัดมาคือพารามิเตอร์ตัวที่สามคือลิสต์ซึ่งมีหน่วยเป็นลิสต์ ซึ่งลิสต์ภายในเป็นลิสต์ที่มีหน่วยข้อมูลอยู่สามหน่วย ได้แก่ชื่อคอลัมน์ นิพจน์ each ซึ่งเรียกฟังก์ชัน Table.RowCount() และการกำหนดชนิดข้อมูลให้เป็นแบบ number
แสดงตัวอย่างการใช้ฟังก์ชัน Table.Group() ที่เต็มรูปแบบมากขึ้น โดยมีโจทย์ว่า “ต้องการจัดกลุ่มตามคอลัมน Quarter แล้วหาผลรวมของคอลัมน์ Sales เมื่อรันโค้ดนี้แล้วจะได้ผลลัพธ์เป็นผลรวมของแต่ละกลุ่ม”
โปรดสังเกตพารามิเตอร์ตัวที่สองซึ่งไม่ได้เป็นลิสต์ว่างอย่างในตัวอย่างก่อนหน้า แต่เป็นลิสต์ที่มีหนึ่งหน่วย เป็นคำว่า Quarter ซึ่งเป็นชื่อคอลัมน์ที่จะใช้ในการทำ group by ส่วนพารามิเตอร์ตัวที่สองคราวนี้มีลิสต์เพิ่มขึ้นมาอีกตัวที่ใช้ฟังก์ชัน List.Sum() เพื่อหาผลรวมคอลัมน์ Sales
บทความตอนนี้พูดถึงคุณสมบัติและซินแท็กซ์เบื้องต้นของภาษาเอ็มหรือภาษาเพาเวอร์คิวรี และพูดถึงการประยุกต์ใช้งานควิรีกับตารางเวิร์กชีต ในตอนต่อไปจะเป็นเรื่องการประยุกต์ใช้คิวรีภาษาเอ็มในการทำสิ่งต่าง ๆ ที่มีประโยชน์ต่อการทำบิซิเนสอินเทลลิเจนซ์