GENERATE วนทีละแถวใน Table1 แล้วประเมิน Table2 ในบริบทของแถวนั้น (row context) จากนั้นรวมผลทั้งหมดเป็นตารางเดียว ถ้า Table2 ว่างเปล่าในรอบไหน แถวนั้นจาก Table1 จะถูกตัดออก (ต่างจาก GENERATEALL)
=GENERATE(<Table1>, <Table2>)
=GENERATE(<Table1>, <Table2>)
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| Table1 | table | Yes | ตารางหลักที่ใช้วนทีละแถว ทุกค่าในแถวปัจจุบันจะกลายเป็น row context เพื่อใช้อ้างอิงใน Table2 | |
| Table2 | table | Yes | นิพจน์ตารางที่ถูกประเมินในบริบท (row context) ของแต่ละแถวใน Table1 แล้วนำผลมารวมกัน ถ้าผลว่างเปล่าในรอบไหน แถวจากนั้นจาก Table1 จะถูกตัดออก |
เช่น สร้างแถวรายละเอียดตามแต่ละรายการในตารางหลัก
เหมาะกับการสร้างตารางคำนวณที่ต้องประกอบจากหลายส่วน
DateList = GENERATE( VALUES(DateRange[StartDate]), ADDCOLUMNS( GENERATESERIES([Value], [Value] + 10), "DayOffset", [Value] ) )DateList =
GENERATE(
VALUES(DateRange[StartDate]),
ADDCOLUMNS(
GENERATESERIES([Value], [Value] + 10),
"DayOffset", [Value]
)
)
ตารางที่มี StartDate ของแต่ละแถว พร้อมคอลัมน์ DayOffset 0–10 ต่อแต่ละ StartDate
CategoryWithProducts = GENERATE( VALUES(Product[Category]), FILTER( Product, Product[Category] = EARLIER(Product[Category]) ) )CategoryWithProducts =
GENERATE(
VALUES(Product[Category]),
FILTER(
Product,
Product[Category] = EARLIER(Product[Category])
)
)
ตารางแสดงแต่ละหมวดหมู่พร้อมรายชื่อผลิตภัณฑ์ของหมวดนั้น
Without Empty = GENERATE(...) With Empty = GENERATEALL(...)Without Empty = GENERATE(...)
With Empty = GENERATEALL(...)
ถ้า Table2 คืนค่าว่าง: GENERATE ตัดแถวออก | GENERATEALL เก็บแถว (NULL ในคอลัมน์ Table2)
เพราะว่า GENERATE ส่งผ่าน row context จากแต่ละแถวของ Table1 ลงไปใน Table2 ถ้าคุณใช้ [Column] โดยตรง DAX อาจสับสน ว่าหมายถึง Table1 หรือ Table2 ดังนั้น EARLIER([Column]) ช่วยบอก “หมายถึงค่าบริบทนอก (outer context) นั่น”
CROSSJOIN = ผลคูณคาร์ทีเซียน (ทั้งหมด ×ทั้งหมด) | GENERATE = คูณเฉพาะส่วนที่ Table2 คืนมา ให้บริบทจาก Table1 จึงยืดหยุ่นกว่า
ใช้ได้บ้างนี่: ✓ Measures | ✓ Visual calculations | ✗ Calculated columns / RLS rules ใน DirectQuery mode
ระวังปริมาณแถว: ถ้า Table1 มี 1,000 แถว และ Table2 ได้ 100 แถวต่อแถว ผลลัพธ์คือ 100,000 แถว อย่าลืมชั่งปริมาณ
GENERATE เป็นฟังก์ชันแบบ table iterator ที่ใช้ row context: มันวนทีละแถวใน Table1 แล้วประเมิน Table2 ในบริบทของแถวนั้น แล้วรวมผลลัพธ์ทั้งหมด
จุดสำคัญ: Row Context คืออะไร? ตอนที่ GENERATE วนแถวที่ 1 ของ Table1 ค่าทั้งหมดของแถวนั้นก็จะ “เข้าสู่บริบท” ทำให้ Table2 สามารถอ้างอิง [Column] ของแถวนั้นได้โดยตรง เช่น
GENERATE(
DateRange,
ADDCOLUMNS(
GENERATESERIES(EARLIER([StartDate]), EARLIER([EndDate])),
“Day”, [Value]
)
)
ในตัวอย่างนี้ EARLIER([StartDate]) เป็นการอ้างอิงค่าแถวปัจจุบันของ DateRange โดยหลีกเลี่ยง context ของ GENERATESERIES
ส่วนตัวผม GENERATE เป็นเหมือน SQL CROSS APPLY กล่าวคือ “วนแต่ละแถว แล้วเฉพาะค่ายอดนิยมต่อแถวนั้น” เหมาะมากเมื่องานต้อง unpivot หรือขยายแถวตามเงื่อนไข พลังจริง ๆ เลย