GENERATE วนทีละแถวใน Table1 แล้วประเมิน Table2 ในบริบทของแถวนั้น (row context) จากนั้นรวมผลทั้งหมดเป็นตารางเดียว ถ้า Table2 ว่างเปล่าในรอบไหน แถวนั้นจาก Table1 จะถูกตัดออก (ต่างจาก GENERATEALL)
| อาร์กิวเมนต์ | ชนิด | คำอธิบาย |
|---|---|---|
| Table1 | table | ตารางหลักที่ใช้วนทีละแถว ทุกค่าในแถวปัจจุบันจะกลายเป็น row context เพื่อใช้อ้างอิงใน Table2 |
| Table2 | table | นิพจน์ตารางที่ถูกประเมินในบริบท (row context) ของแต่ละแถวใน Table1 แล้วนำผลมารวมกัน ถ้าผลว่างเปล่าในรอบไหน แถวจากนั้นจาก Table1 จะถูกตัดออก |
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 หรือขยายแถวตามเงื่อนไข พลังจริง ๆ เลย
เช่น สร้างแถวรายละเอียดตามแต่ละรายการในตารางหลัก
เหมาะกับการสร้างตารางคำนวณที่ต้องประกอบจากหลายส่วน
GENERATE วนแต่ละ StartDate แล้วสร้าง 11 แถว (offset 0–10) ผลลัพธ์คือ N×11 แถว
วนหมวดหมู่แต่ละหมวด แล้วดึงผลิตภัณฑ์ที่ตรงกับหมวดนั้น EARLIER() ใช้อ้างอิงค่า row context
GENERATE ≈ SQL CROSS APPLY (ลบแถวที่ไม่มีข้อมูลในเงื่อนไข) | GENERATEALL ≈ SQL OUTER APPLY (คงไว้)
เพราะว่า 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 จัดกลุ่มตามหมวด · ชี้ที่ชื่อใดชื่อหนึ่ง แล้วฟังก์ชันที่ใช้คู่กันจะมีจุดทอง
ADDCOLUMNS เป็นฟังก์ชัน table transformation ที่ใช้สำหรับเพิ่มคอลัมน์ใหม่ (Calculated Columns) เข้าไปในตารางที่มีอยู่เดิม โดยคำนวณค่าในแต่ละแถวผ่าน Row Context และส่งคืนตารางเดิมพร้อมคอลัมน์ใหม่ต่อท้าย
CROSSJOIN สร้างตารางใหม่โดยการรวมแถวทั้งหมดจากตารางที่ระบุ โดยสร้างทุก Combination ที่เป็นไปได้ ผลลัพธ์คือตารางที่มีจำนวนแถวเท่ากับผลคูณของจำนวนแถวของแต่ละตาราง
GENERATEALL วนแถวของตาราง 1 แล้วสร้าง Cartesian product กับผลลัพธ์ของตาราง 2 โดยคงแถวที่ไม่มีข้อมูลย่อย ต่างจาก GENERATE ตรงที่ไม่ตัดแถวหลักออก
GENERATESERIES สร้างตารางคอลัมน์เดียวที่เป็นลำดับตัวเลขจาก StartValue ถึง EndValue ด้วย increment ที่กำหนดได้ เหมาะกับตารางช่วย parameter table หรือสร้างชุดตัวเลขสำหรับ what-if analysis
SUMMARIZE สร้างตารางสรุปโดยจัดกลุ่มข้อมูลตามคอลัมน์ที่กำหนด คล้าย GROUP BY ใน SQL หรือ Pivot Table ใน Excel คืนค่าตารางที่มีหนึ่งแถวต่อหนึ่ง unique combination ของคอลัมน์ที่เลือก สามารถอ้างถึงคอลัมน์จาก related table ได้โดยตรงโดยไม่ต้องใช้ RELATED มักใช้สร้าง virtual table ใน measure เพื่อทำ intermediate calculations ก่อนใช้ iterator functions อย่าง SUMX, AVERAGEX คำนวณต่อ ⚠️ Best Practice: ใช้ ADDCOLUMNS ครอบ SUMMARIZE แทนการใส่ extension columns ตรงๆ เพื่อ performance และ filter context control ที่ดีกว่า สำหรับ calculated table แนะนำใช้ SUMMARIZECOLUMNS แทนเนื่องจากมี performance ดีกว่าอย่างมาก
VALUES ดึงค่าที่ไม่ซ้ำจากคอลัมน์ หรือดึงแถวทั้งหมดจากตาราง โดยรวมแถว BLANK ที่เกิดจากข้อผิดพลาดของความสัมพันธ์ (Referential Integrity Violations) ส่วน DISTINCT จะไม่รวมแถว BLANK นี้
EARLIER คืนค่าของคอลัมน์ใน Row Context ชั้นนอก (Outer Row Context) เพื่อให้คอลัมน์คำนวณสามารถอ้างอิงค่า “ของแถวปัจจุบัน” ระหว่างการวนซ้อน (เช่น FILTER ภายใน Calculated Column) ได้
FILTER ใช้กรองแถวในตารางตามเงื่อนไขที่ซับซ้อน โดยวนลูปทุกแถวและประเมินเงื่อนไข เหมาะกับการกรองด้วย Measure หรือ Expression ซึ่ง Boolean Expression ทำไม่ได้ แต่ต้องระวังเรื่อง Performance เพราะเป็น Iterator Function ที่ช้ากว่า Boolean Expression ดังนั้นควรใช้เฉพาะเมื่อจำเป็น และอย่าใช้ FILTER กับ RELATED เพื่อกรองข้ามตาราง ให้กรองที่ Dimension Table โดยตรงแทน
ยังไม่มีบทความที่เกี่ยวข้องกับฟังก์ชันนี้
Comments
อีเมลของคุณจะไม่ถูกเผยแพร่