CALCULATE เป็นฟังก์ชันหลักที่สำคัญที่สุดใน DAX ใช้สำหรับ evaluate expression ภายใต้ filter context ที่ถูกปรับเปลี่ยน สามารถเพิ่มตัวกรองใหม่ ลบตัวกรองเดิม หรือแทนที่ filter ที่มีอยู่ได้ รองรับทั้ง Boolean expression และ table expression เป็น filter arguments พร้อม filter modifier functions เช่น REMOVEFILTERS, ALL, ALLEXCEPT, KEEPFILTERS เพื่อควบคุมการกรองอย่างละเอียด มีพฤติกรรมพิเศษคือ context transition ที่เปลี่ยน row context เป็น filter context โดยอัตโนมัติ ทำให้เป็นเครื่องมือหลักในการสร้าง measure ที่ซับซ้อนและ calculated column ที่ต้องใช้ aggregation
=CALCULATE(<expression>[, <filter>[, <filter>[, ...]]])
=CALCULATE(<expression>[, <filter>[, <filter>[, ...]]])
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| expression | scalar | Yes | นิพจน์ที่ต้องการ evaluate (เช่น measure, DAX expression, หรือ aggregation function เช่น SUM, AVERAGE) จะถูกคำนวณเป็นลำดับสุดท้ายหลังจากเตรียม filter context ใหม่เสร็จแล้ว รองรับ scalar value เท่านั้น ไม่รองรับ table expression | |
| filter | boolean / table / filter modifier | Optional | ไม่มีตัวกรองเพิ่มเติม (ไม่บังคับ) | เงื่อนไขการกรองข้อมูล รองรับ 3 รูปแบบหลักที่แตกต่างกัน: (1) Boolean Expression เช่น Product[Color] = “Red” ซึ่งจะถูกแปลงเป็น FILTER(ALL(…)) อัตโนมัติและทำการ override filter เดิมที่มีอยู่ (2) Table Expression เช่น FILTER(Product, Product[Price] > 100) สำหรับสร้างเงื่อนไขการกรองที่ซับซ้อนและยืดหยุ่นมากขึ้น (3) Filter Modifier Functions เช่น REMOVEFILTERS, ALL, ALLEXCEPT, KEEPFILTERS สำหรับควบคุมการกรองอย่างละเอียดและแม่นยำ สามารถใส่ filter หลายตัวได้โดยจะรวมกันด้วย AND logic (ต้องผ่านทุกเงื่อนไข) โปรดทราบว่า filter arguments ทั้งหมดจะถูกประเมินค่าใน original context ก่อนที่จะเกิด context transition นี่เป็นพฤติกรรมที่สำคัญมากสำหรับการเข้าใจผลลัพธ์ที่ถูกต้อง |
ใช้ CALCULATE เพื่อคำนวณยอดรวมที่กรองเฉพาะบางเงื่อนไข เช่น ยอดขายเฉพาะสินค้าสีน้ำเงิน หรือยอดขายเฉพาะ channel ที่กำหนด โดยไม่สนใจ filter ที่มีอยู่จาก Slicer หรือ visual
ใช้ CALCULATE ร่วมกับ REMOVEFILTERS หรือ ALL เพื่อลบ filter บาง column ออก ทำให้คำนวณ grand total ได้ แล้วนำมาหารกับยอดย่อยเพื่อคำนวณเปอร์เซ็นต์
ใช้ CALCULATE เพื่อทำ context transition เปลี่ยน row context เป็น filter context ทำให้ aggregation function เช่น SUM, AVERAGE ทำงานถูกต้องใน calculated column หรือภายใน iterator function เช่น SUMX, FILTER
ใช้ CALCULATE ร่วมกับ time intelligence functions เช่น SAMEPERIODLASTYEAR, DATEADD เพื่อเปรียบเทียบข้อมูลในช่วงเวลาต่างกัน เช่น sales ปีก่อน, YTD (Year-To-Date), MTD (Month-To-Date)
Blue Revenue = CALCULATE( SUM(Sales[Sales Amount]), Product[Color] = "Blue" )Blue Revenue =
CALCULATE(
SUM(Sales[Sales Amount]),
Product[Color] = "Blue"
)
9,602,850.97 (ยอดขายเฉพาะสินค้าสีน้ำเงิน)
Revenue % Total Channel = DIVIDE( SUM(Sales[Sales Amount]), CALCULATE( SUM(Sales[Sales Amount]), REMOVEFILTERS(Sales[Channel]) ) )Revenue % Total Channel =
DIVIDE(
SUM(Sales[Sales Amount]),
CALCULATE(
SUM(Sales[Sales Amount]),
REMOVEFILTERS(Sales[Channel])
)
)
Internet: 26.74%, Reseller: 73.26%
Customer Segment = IF( CALCULATE( SUM(Sales[Sales Amount]), ALLEXCEPT(Customer, Customer[CustomerKey]) ) < 2500, "Low", "High" )Customer Segment =
IF(
CALCULATE(
SUM(Sales[Sales Amount]),
ALLEXCEPT(Customer, Customer[CustomerKey])
) < 2500,
"Low",
"High"
)
ลูกค้าที่มียอดซื้อรวมน้อยกว่า 2,500 = "Low", ที่เหลือ = "High"
High Value Blue Sales = CALCULATE( SUM(Sales[Sales Amount]), Product[Color] = "Blue", Product[List Price] > 1000 )High Value Blue Sales =
CALCULATE(
SUM(Sales[Sales Amount]),
Product[Color] = "Blue",
Product[List Price] > 1000
)
ยอดขายสินค้าที่เป็นสีน้ำเงิน AND ราคามากกว่า 1,000
Blue Sales (Intersect) = CALCULATE( SUM(Sales[Sales Amount]), KEEPFILTERS(Product[Color] = "Blue") )=Blue Sales (Intersect) =
CALCULATE(
SUM(Sales[Sales Amount]),
KEEPFILTERS(Product[Color] = "Blue")
)
ยอดขายสินค้าสีน้ำเงิน แต่ถ้า Slicer เลือกสีแดง ผลลัพธ์จะเป็น blank
Sales vs Last Year Growth = VAR CurrentYearSales = SUM(Sales[Sales Amount]) VAR LastYearSales = CALCULATE( SUM(Sales[Sales Amount]), SAMEPERIODLASTYEAR(Calendar…Sales vs Last Year Growth =
VAR CurrentYearSales = SUM(Sales[Sales Amount])
VAR LastYearSales =
CALCULATE(
SUM(Sales[Sales Amount]),
SAMEPERIODLASTYEAR(Calendar[Date])
)
VAR GrowthAmount = CurrentYearSales - LastYearSales
VAR GrowthPercent = DIVIDE(GrowthAmount, LastYearSales, 0)
RETURN
GrowthPercent
0.15 (เติบโต 15% เมื่อเทียบกับปีก่อน)
เพราะ DAX แปลง Boolean expression เป็น FILTER(ALL(column), condition) โดยอัตโนมัติ และ ALL(column) ทำงานได้เฉพาะ single column เท่านั้น ถ้าต้องการกรองหลายตารางพร้อมกัน ต้องใช้ table expression เช่น FILTER(Product, …) แทน Boolean expression
เกิดขึ้นเมื่อ CALCULATE ถูกเรียกใช้ใน row context (เช่นใน calculated column หรือภายใน iterator function เช่น SUMX, FILTER) CALCULATE จะเปลี่ยน row context เป็น filter context โดยอัตโนมัติ ทำให้ aggregation function ทำงานได้ถูกต้อง สำคัญมาก: Filter arguments ถูกประเมินก่อน context transition จึงไม่ได้รับผลจาก context transition
Boolean Filter เช่น Product[Color] = “Red” จะถูกแปลงเป็น FILTER(ALL(Product[Color]), Product[Color] = “Red”) โดยอัตโนมัติ ดังนั้นทั้งสองรูปแบบให้ผลลัพธ์เหมือนกัน แต่ Boolean Filter เขียนสั้นกว่าและอ่านง่ายกว่า ข้อจำกัดคือ Boolean Filter ต้อง reference column จากตารางเดียว ส่วน FILTER(…) ยืดหยุ่นกว่า ใช้เงื่อนไขซับซ้อนและ reference หลายตารางได้
ใช้ KEEPFILTERS เมื่อต้องการให้ filter ใหม่ทำงานร่วมกับ filter เดิมแบบ intersect (AND logic) แทนการ override Boolean Filter ปกติจะ override filter เดิมทิ้งเสมอ ตัวอย่าง: ถ้า Slicer เลือกสีแดงอยู่ การใช้ CALCULATE(…, Product[Color] = “Blue”) จะได้ Blue (override) แต่การใช้ CALCULATE(…, KEEPFILTERS(Product[Color] = “Blue”)) จะได้ blank เพราะไม่มีข้อมูลที่เป็นทั้ง Red และ Blue
REMOVEFILTERS และ ALL ให้ผลลัพธ์เหมือนกันเมื่อใช้เป็น filter modifier ใน CALCULATE แต่ REMOVEFILTERS อ่านง่ายกว่าและชัดเจนกว่า เพราะชื่อบอกว่าทำอะไร (ลบ filter) ในขณะที่ ALL มีหลายความหมายขึ้นอยู่กับบริบท Microsoft และ SQLBI แนะนำให้ใช้ REMOVEFILTERS ใน modern DAX code เพื่อให้โค้ดอ่านง่ายและบำรุงรักษาง่ายขึ้น
CALCULATE คือฟังก์ชันที่มีความสำคัญมากที่สุดในภาษา DAX ทำหน้าที่ประมวลผลนิพจน์ภายใต้บริบทการกรองข้อมูลที่ถูกปรับเปลี่ยนตามเงื่อนไขที่คุณกำหนดไว้
.
เอาจริงๆ ถ้าคุณเข้าใจ CALCULATE อย่างถ่องแท้ คุณจะเข้าใจ DAX ทั้งระบบได้เลยครับ 💡
.
เพราะฟังก์ชันนี้ถือเป็นหัวใจหลักของการควบคุม Filter Context และ Context Transition ซึ่งเป็นแนวคิดพื้นฐานที่สำคัญที่สุดของภาษา DAX ทั้งระบบ เรียกได้ว่าเป็น “ตัวเป็นตัวตาย” ของสาย Power BI เลยก็ว่าได้ 😎
Filter Context คือชุดของตัวกรองที่กำหนดว่าข้อมูลส่วนไหนของตารางจะถูกนำมาใช้ในการคำนวณผลลัพธ์สุดท้าย
.
ตัวอย่างเช่น เมื่อคุณใช้เครื่องมือ Slicer เพื่อเลือกสี “Blue” ใน Power BI ระบบจะสร้าง Filter Context ที่มีเงื่อนไข Product[Color] = “Blue” ขึ้นมา ทำให้การคำนวณทั้งหมดในรายงานจะเห็นและประมวลผลเฉพาะข้อมูลของสินค้าที่มีสีน้ำเงินเท่านั้น
CALCULATE ทำหน้าที่อะไร?
.
ฟังก์ชันนี้ช่วยให้คุณสามารถ ปรับเปลี่ยน Filter Context ได้อย่างยืดหยุ่นเป็นการชั่วคราวสำหรับการคำนวณเฉพาะครั้งนั้น
.
คุณสามารถเพิ่มตัวกรองเงื่อนไขใหม่เข้าไป ลบตัวกรองเดิมออกไป หรือแทนที่ตัวกรองที่มีอยู่เดิมได้ตามความต้องการของการคำนวณในขณะนั้น ส่วนตัวผมใช้ CALCULATE เกือบทุก Measure เลยครับ 😎
CALCULATE รองรับการใช้ filter arguments ได้หลากหลายสองรูปแบบหลักดังนี้:
Product[Color] = "Red" สามารถเขียนได้ง่ายและอ่านได้ง่าย แต่มีข้อจำกัดคือสามารถอ้างอิงได้เฉพาะคอลัมน์จากตารางเดียวเท่านั้น และจะทำการแทนที่ตัวกรองเดิมทั้งหมดเสมอโดยอัตโนมัติFILTER(Product, Product[Price] > 100) มีความยืดหยุ่นมากกว่าแบบแรก สามารถใช้เงื่อนไขที่ซับซ้อนได้หลากหลาย และสามารถอ้างอิงหลายตารางพร้อมกันได้อย่างมีประสิทธิภาพข้อสำคัญที่ต้องเข้าใจ: เมื่อคุณใช้ Boolean Expression เช่น Product[Color] = "Blue" ระบบ DAX จะทำการแปลงให้เป็นรูปแบบ FILTER(ALL(Product[Color]), Product[Color] = "Blue") โดยอัตโนมัติในเบื้องหลัง
.
นี่คือเหตุผลที่สำคัญว่าทำไม Boolean Filter ถึงต้องแทนที่ตัวกรองเดิมทั้งหมดเสมอ เพราะฟังก์ชัน ALL จะทำการลบตัวกรองเดิมออกไปก่อนทั้งหมด เรื่องนี้เจอบ่อยมากครับ 😅
Context Transition เป็นพฤติกรรมพิเศษของ CALCULATE ที่จะเกิดขึ้นเมื่อมี row context อยู่ (เช่นใน calculated column หรือ iterator function อย่าง SUMX) CALCULATE จะเปลี่ยน row context นั้นให้เป็น filter context โดยอัตโนมัติ นี่เป็นกลไกที่สำคัญมากสำหรับการทำงานของ DAX
ตัวอย่างการทำงาน: ใน calculated column แต่ละแถวจะมี row context (แถวปัจจุบันที่กำลังประมวลผล) ถ้าคุณใช้ CALCULATE(SUM(Sales[Amount]), ...) ระบบ DAX จะเปลี่ยน row context ให้เป็นตัวกรองที่กรองเฉพาะแถวนั้น ทำให้ SUM สามารถคำนวณได้ถูกต้องตามที่ต้องการ
ข้อควรระวังสำคัญ: การเรียกใช้ measure ภายใน DAX expression จะมีการใส่ CALCULATE ครอบให้อัตโนมัติ ทำให้เกิด context transition ได้โดยที่คุณอาจไม่รู้ตัวว่ามีการเปลี่ยนแปลงเกิดขึ้น
เพื่อให้เข้าใจผลลัพธ์ที่ถูกต้องและแม่นยำ คุณต้องทราบลำดับการทำงานภายในของ CALCULATE ดังนี้:
การเข้าใจลำดับนี้จะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาดที่พบบ่อย โดยเฉพาะอย่างยิ่งเมื่อใช้ตัวกรองที่ซับซ้อนหรือมีการซ้อน CALCULATE หลายชั้นในสูตรเดียวกัน
CALCULATE สนับสนุน filter modifier functions หลายตัวที่ให้คุณควบคุมการกรองได้อย่างละเอียดและแม่นยำ: