CALCULATETABLE evaluate table expression ภายใต้ filter context ที่ถูกปรับเปลี่ยน แล้วคืนค่าเป็น table (ตาราง) ซึ่งแตกต่างจาก CALCULATE ที่คืนค่าเป็น scalar value รองรับ filter arguments 3 รูปแบบ: Boolean expression, table expression, และ filter modifier functions (REMOVEFILTERS, ALL, KEEPFILTERS, USERELATIONSHIP, CROSSFILTER) มีพฤติกรรมเหมือน CALCULATE ในทุกแง่มุมของการจัดการ filter context รวมถึง context transition แต่เหมาะสำหรับการสร้าง intermediate table ที่ถูกกรองแล้วส่งต่อให้ iterator functions หรือใช้ใน calculated table มักมี performance ดีกว่า FILTER ใน simple filtering scenarios เพราะ DAX engine สามารถทำ cardinality estimation และ optimization ได้ดีกว่า
=CALCULATETABLE(<table>[, <filter>[, <filter>[, ...]]])
=CALCULATETABLE(<table>[, <filter>[, <filter>[, ...]]])
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| table | table | Yes | Table expression ที่ต้องการ evaluate เช่น ชื่อตาราง (Sales, Products), VALUES(column), FILTER(table, condition), SUMMARIZE(…) จะถูกประเมินค่าเป็นขั้นตอนสุดท้ายหลังจากเตรียม filter context ใหม่เสร็จแล้ว ต้องเป็น expression ที่คืนค่าเป็น table ไม่สามารถใช้ scalar value ได้ | |
| filter | boolean / table / filter modifier | Optional | ไม่มีตัวกรองเพิ่มเติม (ไม่บังคับ) | เงื่อนไขการกรองข้อมูล รองรับ 3 รูปแบบ: (1) Boolean Expression เช่น Sales[Channel] = “Online” ซึ่งจะถูกแปลงเป็น FILTER(ALL(…)) อัตโนมัติและทำการ override filter เดิม ต้อง reference column จากตารางเดียว (2) Table Expression เช่น FILTER(Sales, Sales[Amount] > 1000) สำหรับเงื่อนไขซับซ้อนและยืดหยุ่นมากขึ้น (3) Filter Modifier Functions เช่น REMOVEFILTERS, ALL, ALLEXCEPT, KEEPFILTERS, USERELATIONSHIP, CROSSFILTER สำหรับควบคุม filter context อย่างละเอียด สามารถใส่หลาย filter ได้โดยจะรวมกันด้วย AND logic สำคัญมาก: filter arguments ทั้งหมดจะถูกประเมินค่าใน original context ก่อนที่จะเกิด context transition |
ใช้ CALCULATETABLE เพื่อสร้าง table ที่ถูกกรองตามเงื่อนไขเฉพาะ แล้วส่งต่อให้ iterator functions เช่น SUMX, AVERAGEX, COUNTX เพื่อทำการคำนวณที่ซับซ้อน เหมาะกับการทำ conditional aggregation ที่ต้องการควบคุม filter context อย่างละเอียด
ใช้ CALCULATETABLE ใน calculated table definition เพื่อสร้าง table ที่ถูกกรองตามเงื่อนไขพิเศษ เช่น สร้าง table Customers ที่มียอดซื้อมากกว่า 10,000 โดยการกรองจะทำงานแบบ dynamic ตาม filter context ที่มีอยู่
ใช้ CALCULATETABLE ร่วมกับ ALLSELECTED เพื่อสร้าง totals ที่เคารพ filter จาก slicers แต่ไม่รับผลกระทบจาก row/column context ภายใน visual เหมาะสำหรับการคำนวณเปอร์เซ็นต์ของยอดรวมใน matrix หรือ table visual
ใช้ CALCULATETABLE ร่วมกับ USERELATIONSHIP เพื่อเปิดใช้งาน inactive relationship ชั่วคราวสำหรับการสร้าง table เช่น ใช้ ShipDate แทน OrderDate ในการกรองข้อมูล เหมาะกับ role-playing dimensions เช่น OrderDate, ShipDate, DueDate ที่เชื่อมกับ Date table เดียวกัน
ใช้ CALCULATETABLE เพื่อสร้าง custom date table ที่ถูกกรองตามช่วงเวลาเฉพาะ เช่น เฉพาะ business days หรือ fiscal calendar แล้วใช้ร่วมกับ time intelligence functions สำหรับการวิเคราะห์แบบ temporal
// Data Model Context: // Sales table มี columns: SalesID, Channel, Amount, Quantity // มีข้อมูล 1,000 rows โดย Channel มีค่า "Online" และ "Retail" Online Sales…// Data Model Context:
// Sales table มี columns: SalesID, Channel, Amount, Quantity
// มีข้อมูล 1,000 rows โดย Channel มีค่า "Online" และ "Retail"
Online Sales Table =
CALCULATETABLE(
Sales,
Sales[Channel] = "Online"
)
// Result: Table ที่มีเฉพาะแถวที่ Channel = "Online"
// ถ้า Sales มี 600 rows ของ Online และ 400 rows ของ Retail
// ผลลัพธ์จะเป็น table ที่มี 600 rows (เฉพาะ Online)
Table ที่มีเฉพาะแถวที่ Sales[Channel] = "Online" (600 rows)
// Data Model Context: // Sales table: SalesID, Channel, Amount, Quantity, Date // ตัวอย่างข้อมูล: // | Channel | Amount | Quantity | // | Online | 1500 | 3 | /…=// Data Model Context:
// Sales table: SalesID, Channel, Amount, Quantity, Date
// ตัวอย่างข้อมูล:
// | Channel | Amount | Quantity |
// | Online | 1500 | 3 |
// | Online | 800 | 2 | (ถูกกรองออกเพราะ Amount <= 1000)
// | Retail | 2000 | 4 | (ถูกกรองออกเพราะ Channel != "Online")
// | Online | 1200 | 5 |
High Value Online Sales =
VAR FilteredTable =
CALCULATETABLE(
Sales,
Sales[Channel] = "Online",
Sales[Amount] > 1000
)
VAR TotalValue =
SUMX(
FilteredTable,
Sales[Amount] * Sales[Quantity]
)
RETURN
TotalValue
// FilteredTable จะมี 2 rows: (1500, 3) และ (1200, 5)
// SUMX คำนวณ: (1500 * 3) + (1200 * 5) = 4,500 + 6,000 = 10,500
10,500 (ผลรวมของ Amount × Quantity สำหรับ Online sales ที่ Amount > 1,000)
// Data Model Context: // Product table: ProductID, ProductName, Category, Color, Size // สมมติ user เลือก slicer: Category = "Electronics", Color = "Black", Si…// Data Model Context:
// Product table: ProductID, ProductName, Category, Color, Size
// สมมติ user เลือก slicer: Category = "Electronics", Color = "Black", Size = "Medium"
// Product table มี 500 products ใน Electronics category
// โดย 50 products เป็น Black, 30 products เป็น Medium
// แต่มี 500 products ทั้งหมดใน Electronics (ไม่สนใจ Color และ Size)
All Products By Category =
VAR CategoryProducts =
CALCULATETABLE(
VALUES(Product[ProductName]),
REMOVEFILTERS(Product[Color]),
REMOVEFILTERS(Product[Size])
)
VAR ProductCount =
COUNTROWS(CategoryProducts)
RETURN
ProductCount
// Result: 500 (จำนวน products ทั้งหมดใน Electronics category)
// ไม่ใช่ 50 หรือ 30 เพราะเราลบ filter ของ Color และ Size ออกแล้ว
500 (จำนวน products ทั้งหมดใน Category ปัจจุบัน โดยไม่สนใจ Color และ Size)
// Data Model Context: // Sales table: SalesID, ProductID, Amount, Date // Matrix visual แสดง Amount by Product, มี slicer Year = 2024 // ข้อมูลตัวอย่างหลัง fil…// Data Model Context:
// Sales table: SalesID, ProductID, Amount, Date
// Matrix visual แสดง Amount by Product, มี slicer Year = 2024
// ข้อมูลตัวอย่างหลัง filter Year = 2024:
// | Product | Amount |
// | Laptop | 50,000 |
// | Mouse | 10,000 |
// | Keyboard | 15,000 |
// Visual Total: 75,000
% of Visual Total =
VAR CurrentValue = SUM(Sales[Amount])
VAR VisualTotal =
CALCULATE(
SUM(Sales[Amount]),
ALLSELECTED(Sales)
)
VAR Percentage =
DIVIDE(CurrentValue, VisualTotal, 0)
RETURN
Percentage
// ใน row Laptop: CurrentValue = 50,000, VisualTotal = 75,000
// Percentage = 50,000 / 75,000 = 0.6667 (66.67%)
// ใน row Mouse: CurrentValue = 10,000, VisualTotal = 75,000
// Percentage = 10,000 / 75,000 = 0.1333 (13.33%)
Laptop: 66.67%, Mouse: 13.33%, Keyboard: 20.00% (เทียบกับยอดรวม 75,000 ที่ถูก filter ด้วย Year = 2024)
// Data Model Context: // Sales table: SalesID, OrderDate, ShipDate, Amount // Date table: Date, Year, Month, Quarter // Relationships: // - ACTIVE: Sales[Order…=// Data Model Context:
// Sales table: SalesID, OrderDate, ShipDate, Amount
// Date table: Date, Year, Month, Quarter
// Relationships:
// - ACTIVE: Sales[OrderDate] → Date[Date]
// - INACTIVE: Sales[ShipDate] → Date[Date]
// ต้องการนับ transactions ที่ ship ในปี 2024 (ใช้ ShipDate ไม่ใช่ OrderDate)
Shipped Sales Count =
VAR ShippedSales =
CALCULATETABLE(
Sales,
USERELATIONSHIP(Sales[ShipDate], 'Date'[Date]),
'Date'[Year] = 2024
)
VAR ShippedCount =
COUNTROWS(ShippedSales)
RETURN
ShippedCount
// สมมติ Sales table มี:
// | OrderDate | ShipDate | Amount |
// | 2023-12-28 | 2024-01-05 | 1000 | ✓ นับ (ship ในปี 2024)
// | 2024-01-10 | 2024-01-15 | 1500 | ✓ นับ (ship ในปี 2024)
// | 2024-03-20 | 2024-04-01 | 2000 | ✓ นับ (ship ในปี 2024)
// | 2024-11-25 | 2025-01-03 | 1200 | ✗ ไม่นับ (ship ในปี 2025)
// Result: 3 transactions
3 (จำนวน transactions ที่ ship ในปี 2024 ตาม ShipDate)
// Data Model Context: // Sales table: SalesID, Channel, Amount // User เลือก slicer Channel = "Retail" // มี measure ที่ต้องการ filter เฉพาะ "Online" // Patter…// Data Model Context:
// Sales table: SalesID, Channel, Amount
// User เลือก slicer Channel = "Retail"
// มี measure ที่ต้องการ filter เฉพาะ "Online"
// Pattern 1: ไม่ใช้ KEEPFILTERS (Override Behavior)
Online Sales Override =
VAR FilteredTable =
CALCULATETABLE(
Sales,
Sales[Channel] = "Online"
)
RETURN
COUNTROWS(FilteredTable)
// Result: จำนวน Online sales (ไม่สนใจ slicer ที่เลือก Retail)
// ถ้า Online มี 600 rows → Result = 600
// Pattern 2: ใช้ KEEPFILTERS (Intersect Behavior)
Online Sales Intersect =
VAR FilteredTable =
CALCULATETABLE(
Sales,
KEEPFILTERS(Sales[Channel] = "Online")
)
RETURN
COUNTROWS(FilteredTable)
// Result: Retail AND Online (impossible!) → Result = 0
// เพราะไม่มี row ไหนที่ Channel เป็นทั้ง Retail และ Online พร้อมกัน
Override: 600 rows, Intersect: 0 rows (เพราะ Retail AND Online เป็นไปไม่ได้)
ความแตกต่างหลักคือ return type โดย CALCULATE คืนค่าเป็น scalar value (ตัวเลข, ข้อความ, หรือค่าเดี่ยวใดก็ตาม) ในขณะที่ CALCULATETABLE คืนค่าเป็น table (ตาราง)
.
อย่างไรก็ตาม ทั้งสองฟังก์ชันมีพฤติกรรมเหมือนกันในทุกแง่มุมของการจัดการ filter context รองรับ filter modifier functions เหมือนกัน ทำ context transition เหมือนกัน และมีลำดับการ evaluate filter arguments เหมือนกัน
.
ใช้ CALCULATE เมื่อต้องการ scalar result (เช่น Total Sales = CALCULATE(SUM(Sales[Amount]), …)) และใช้ CALCULATETABLE เมื่อต้องการ table result ที่จะส่งต่อให้ฟังก์ชันอื่น (เช่น SUMX(CALCULATETABLE(…), …)) หรือใช้ใน calculated table ครับ 😎
ใช้ CALCULATETABLE เมื่อต้องการปรับเปลี่ยน filter context หรือใช้ filter modifier functions (REMOVEFILTERS, ALL, KEEPFILTERS, USERELATIONSHIP) และมักจะมี performance ดีกว่า FILTER ใน simple filtering scenarios เพราะ DAX engine สามารถใช้ cardinality estimation และ optimization techniques ได้ดีกว่า
.
ส่วน FILTER เหมาะกับ complex row-by-row conditions ที่ต้องการ row context เช่น เงื่อนไขที่อ้างอิง measure (FILTER(Products, [Total Sales] > 10000)) หรือการคำนวณที่ซับซ้อนแบบทีละแถว
.
ส่วนตัวผมแนะนำให้ใช้ CALCULATETABLE เป็น first choice และเปลี่ยนไปใช้ FILTER เฉพาะเมื่อต้องการ row context จริงๆ ครับ 💡
ALLSELECTED คืนค่า filter context ที่ “มองเห็นได้” ใน visual (visual-level context) โดยลบ filter ที่เกิดจาก row/column context ภายใน visual แต่ยังคง filter จาก slicers, page filters, และ report filters ไว้
.
เมื่อใช้กับ CALCULATETABLE จะได้ table ที่ถูกกรองตาม visual-level filters เหมาะสำหรับการคำนวณเปอร์เซ็นต์ของยอดรวม (percentage of total) ใน matrix หรือ table visual
.
ตัวอย่างเช่น CALCULATETABLE(Sales, ALLSELECTED(Sales)) ใช้ใน visual ที่มี slicer Year = 2024 จะได้ Sales table ที่ถูก filter ด้วย Year = 2024 แต่ไม่รับผลจาก row context ภายใน visual Pattern นี้ใช้บ่อยมากใน visual-level calculations ครับ 😎
Boolean Filter เช่น Sales[Channel] = “Online” จะถูกแปลงเป็น FILTER(ALL(Sales[Channel]), Sales[Channel] = “Online”) โดยอัตโนมัติ ทำให้เกิดพฤติกรรม override (เขียนทับ filter เดิมเสมอ) ข้อจำกัดคือต้อง reference column จากตารางเดียวเท่านั้น (ไม่สามารถใช้ Sales[Channel] = “Online” && Product[Category] = “Electronics” ได้)
.
ส่วน Table Expression เช่น FILTER(Sales, Sales[Amount] > 1000) ยืดหยุ่นกว่า สามารถใช้เงื่อนไขซับซ้อน reference หลายตารางพร้อมกัน (FILTER(Sales, Sales[Amount] > 1000 && RELATED(Product[Category]) = “Electronics”)) และควบคุมพฤติกรรม override/intersect ได้อย่างละเอียด
.
แนะนำให้ใช้ Boolean Filter สำหรับเงื่อนไขง่ายๆ และ Table Expression สำหรับเงื่อนไขซับซ้อนครับ 💡
ใช่ CALCULATETABLE ทำ context transition เหมือนกับ CALCULATE ทุกประการ เมื่อถูกเรียกใช้ภายใน row context (เช่นใน calculated column หรือภายใน iterator function เช่น SUMX) row context จะถูกแปลงเป็น filter context โดยอัตโนมัติก่อนที่จะ evaluate table expression
.
ลำดับการทำงานภายในก็เหมือนกัน: (1) Evaluate filter arguments ใน original context ก่อน (2) ทำ context transition (3) Apply filter modifiers (4) Apply filters (5) Evaluate table expression ภายใต้ filter context ใหม่
.
การเข้าใจ context transition เป็นสิ่งสำคัญมากสำหรับการเขียน DAX ที่ถูกต้อง เพราะมันส่งผลต่อพฤติกรรมของ aggregation functions และ filter propagation ครับ 😎
ใน VertiPaq engine (DAX engine รุ่นใหม่ที่ใช้ใน Power BI และ Analysis Services) CALCULATETABLE มักจะมี performance ดีกว่า FILTER สำหรับ simple Boolean conditions เพราะ engine สามารถใช้ cardinality estimation (ประมาณจำนวน rows ที่จะผ่าน filter) และ optimization techniques (เช่น bitmap filtering) ได้ดีกว่า
.
อย่างไรก็ตาม สำหรับ complex row-by-row conditions ที่ต้องการ row context การใช้ FILTER อาจจะเหมาะสมกว่าและในบางกรณีอาจจะเร็วกว่าด้วยซ้ำ
.
โดยทั่วไปแนะนำให้ใช้ CALCULATETABLE เป็น first choice สำหรับ table filtering และเปลี่ยนไปใช้ FILTER เฉพาะเมื่อ logic ต้องการ row context จริงๆ หรือเมื่อ performance testing แสดงว่า FILTER เร็วกว่าใน specific scenario นั้นครับ 💡
USERELATIONSHIP ใช้เมื่อ data model มี multiple relationships ระหว่างสองตาราง (เช่น Sales table มี OrderDate, ShipDate, และ DueDate ที่เชื่อมกับ Date table เดียวกัน) โดยปกติจะมี active relationship เพียง 1 relationship (เช่น OrderDate → Date) แต่บางครั้งต้องการใช้ inactive relationship (เช่น ShipDate → Date) แทน
.
USERELATIONSHIP เปิดใช้งาน inactive relationship ชั่วคราวสำหรับการ evaluate table expression ทำให้สามารถสลับการใช้ relationships ได้ตามต้องการ
.
ตัวอย่าง: CALCULATETABLE(Sales, USERELATIONSHIP(Sales[ShipDate], Date[Date]), Date[Year] = 2024) จะกรอง Sales ตาม ShipDate แทน OrderDate Pattern นี่เรียกว่า role-playing dimensions และใช้บ่อยมากใน real-world scenarios เช่น การวิเคราะห์ยอดขายตาม order date vs ship date vs payment date ครับ 😎
Override behavior (default) หมายความว่า filter ใหม่จะเขียนทับ filter เดิมที่กรอง column เดียวกัน ตัวอย่าง: ถ้า slicer เลือก Channel = “Retail” และใช้ CALCULATETABLE(Sales, Sales[Channel] = “Online”) filter ใหม่ (Online) จะเขียนทับ filter เดิม (Retail) ทำให้ได้ Online sales เสมอ
.
ส่วน Intersect behavior (ใช้ KEEPFILTERS) หมายความว่า filter ใหม่และ filter เดิมต้องเป็นจริงพร้อมกัน (AND logic) ตัวอย่าง: CALCULATETABLE(Sales, KEEPFILTERS(Sales[Channel] = “Online”)) จะทำให้ filter context มี Retail (จาก slicer) AND Online (จาก KEEPFILTERS) ซึ่งเป็นไปไม่ได้ จึงได้ผลลัพธ์ 0 rows
.
ใช้ KEEPFILTERS เมื่อต้องการให้ measure รับผลจาก user selections เสมอและไม่ต้องการให้ filter ใน DAX code เขียนทับ filter จาก slicers หรือ visual context ครับ 💡
CALCULATETABLE ใช้สำหรับกรองตารางด้วยเงื่อนไขที่ต้องการ แล้วคืนค่าเป็นตารางที่กรองแล้ว ซึ่งสามารถนำไปใช้กับฟังก์ชันอื่นต่อได้ทันที
.
ที่เจ๋งคือมันแตกต่างจาก CALCULATE ตรงที่ CALCULATE คืนค่าเป็นตัวเลขเดียว ส่วน CALCULATETABLE คืนค่าเป็นตารางทั้งตาราง
.
ส่วนตัวผมใช้บ่อยมากเลยครับ โดยเฉพาะเวลากรองตารางแล้วส่งต่อให้ SUMX, AVERAGEX คำนวณต่อ 😎
แม้ว่าฟังก์ชัน CALCULATETABLE และ CALCULATE จะมีพฤติกรรมในการจัดการบริบทของตัวกรองเหมือนกันทุกประการ แต่มีความแตกต่างที่สำคัญมากในประเภทของค่าที่คืนกลับมา ซึ่งส่งผลต่อการเลือกใช้งานในสถานการณ์ต่างๆ อย่างมีนัยสำคัญ:
พฤติกรรมที่เหมือนกันทั้งหมด: ทั้งสองฟังก์ชันมีพฤติกรรมการทำงานเหมือนกันในหลายประการ ได้แก่ การทำ context transition หรือการเปลี่ยนบริบทของแถวเป็นบริบทของตัวกรองโดยอัตโนมัติเมื่อถูกเรียกใช้ภายในบริบทของแถว รองรับฟังก์ชันปรับแต่งตัวกรองเหมือนกันทุกตัวเช่น REMOVEFILTERS สำหรับลบตัวกรอง ALL และ ALLEXCEPT สำหรับลบตัวกรองแบบเลือกสรร KEEPFILTERS สำหรับเพิ่มตัวกรองแบบ intersect USERELATIONSHIP สำหรับเปิดใช้ความสัมพันธ์ที่ไม่ได้ active และมีลำดับการประเมินค่า filter arguments เหมือนกันคือประเมินค่าใน original context ก่อนที่จะทำการเปลี่ยน context ใดๆ ทั้งสิ้น
ทั้งสองฟังก์ชัน CALCULATETABLE และ FILTER คืนค่าผลลัพธ์เป็นตารางเหมือนกัน แต่มีพฤติกรรมการทำงานและกรณีการใช้งานที่แตกต่างกันอย่างชัดเจน ซึ่งการเข้าใจความแตกต่างนี้จะช่วยให้คุณเลือกใช้ฟังก์ชันที่เหมาะสมกับสถานการณ์ได้อย่างถูกต้อง:
การพิจารณาด้านประสิทธิภาพ: ใน VertiPaq engine ซึ่งเป็น DAX engine รุ่นใหม่ที่ใช้ใน Power BI และ Analysis Services ฟังก์ชัน CALCULATETABLE มักจะทำงานเร็วกว่าฟังก์ชัน FILTER อย่างเห็นได้ชัดสำหรับเงื่อนไข Boolean แบบธรรมดา เพราะ engine สามารถใช้เทคนิคการเพิ่มประสิทธิภาพต่างๆ ได้ดีกว่า ดังนั้นแนะนำให้เลือกใช้ CALCULATETABLE เป็นตัวเลือกแรกเสมอ และเปลี่ยนไปใช้ FILTER เฉพาะเมื่อต้องการบริบทของแถวจริงๆ
ฟังก์ชัน CALCULATETABLE รองรับ filter arguments หรืออาร์กิวเมนต์สำหรับการกรองข้อมูลหลากหลายรูปแบบ โดยแบ่งออกเป็น 3 รูปแบบหลักที่มีพฤติกรรมและข้อจำกัดแตกต่างกัน การเข้าใจรูปแบบต่างๆ เหล่านี้จะช่วยให้คุณสามารถเลือกใช้ได้อย่างเหมาะสมตามสถานการณ์:
Sales[Channel] = "Online" ซึ่งระบบ DAX จะแปลงโดยอัตโนมัติเป็น FILTER(ALL(Sales[Channel]), Sales[Channel] = "Online") ทำให้เกิดพฤติกรรมแบบ override คือจะเขียนทับตัวกรองเดิมของคอลัมน์นั้นทั้งหมด ข้อจำกัดที่สำคัญของรูปแบบนี้คือต้องอ้างอิงคอลัมน์จากตารางเดียวกันเท่านั้น ไม่สามารถอ้างอิงคอลัมน์จากหลายตารางในเงื่อนไขเดียวกันได้FILTER(Sales, Sales[Amount] > 1000) หรือ VALUES(Product[Category]) ให้ความยืดหยุ่นมากกว่ารูปแบบ Boolean Expression สามารถใช้เงื่อนไขที่ซับซ้อนได้ อ้างอิงคอลัมน์จากหลายตารางพร้อมกันได้ และสามารถควบคุมพฤติกรรมแบบ override หรือ intersect ได้อย่างละเอียดตามต้องการREMOVEFILTERS(column) สำหรับลบตัวกรองออกจากคอลัมน์ที่ระบุ KEEPFILTERS(filter) สำหรับเพิ่มตัวกรองใหม่แบบ intersect แทนที่จะเป็น override และ USERELATIONSHIP(col1, col2) สำหรับเปิดใช้งานความสัมพันธ์ที่ไม่ได้ active อยู่ชั่วคราวพฤติกรรมแบบ Override กับ Intersect: โดยค่าเริ่มต้นถ้ามีตัวกรองหลายตัวที่กรองคอลัมน์เดียวกัน ตัวกรองใหม่จะทำงานแบบ override หรือเขียนทับตัวกรองเดิมทั้งหมด แต่ถ้าใช้ฟังก์ชัน KEEPFILTERS พฤติกรรมจะเปลี่ยนเป็นแบบ intersect ซึ่งใช้ AND logic ทำให้ตัวกรองใหม่และตัวกรองเดิมต้องเป็นจริงพร้อมกันทั้งคู่
เช่นเดียวกับ CALCULATE ฟังก์ชัน CALCULATETABLE จะทำ context transition โดยอัตโนมัติเมื่อถูกเรียกใช้ภายใน row context (เช่น ใน calculated column หรือภายใน iterator function เช่น SUMX) กลไกนี้จะแปลง row context เป็น filter context ก่อนที่จะ evaluate table expression
ลำดับการ Evaluate ภายใน CALCULATETABLE (สำคัญมาก):
Pattern ที่นิยมใช้มากและมีประโยชน์อย่างยิ่งคือการใช้ CALCULATETABLE ร่วมกับ ALLSELECTED เพื่อสร้าง visual-level totals ที่เคารพ filter จาก slicers และ filters ภายนอก visual แต่ไม่รับผลกระทบจาก row/column context ภายใน visual เอง (เช่น บริบทของแถวใน matrix หรือ table visual)
ALLSELECTED คืนค่า filter context ที่ “มองเห็นได้” ใน visual (visible context) โดยลบ filter ที่เกิดจาก row/column context ภายใน visual แต่ยังคง filter จาก slicers, page filters, และ report filters ไว้ ทำให้เหมาะสำหรับการคำนวณเปอร์เซ็นต์ของยอดรวม (percentage of total) ที่ต้องการให้เคารพ user selections แต่ไม่รับผลจาก row-level context
เมื่อไหร่ควรใช้ CALCULATETABLE:
Best Practices: