Thep Excel

GENERATEวนแถวตารางแรก สร้างตารางเพิ่มเติมในแต่ละรอบ แล้วรวมผลทั้งหมด

GENERATE วนทีละแถวใน Table1 แล้วประเมิน Table2 ในบริบทของแถวนั้น (row context) จากนั้นรวมผลทั้งหมดเป็นตารางเดียว ถ้า Table2 ว่างเปล่าในรอบไหน แถวนั้นจาก Table1 จะถูกตัดออก (ต่างจาก GENERATEALL)

fx
=GENERATE(<Table1>, <Table2>)

ความนิยม5/10
ความยาก6/10
ประโยชน์5/10

อัปเดต 13 December 2025

Syntax & Arguments

อาร์กิวเมนต์ ชนิด คำอธิบาย
Table1 table ตารางหลักที่ใช้วนทีละแถว ทุกค่าในแถวปัจจุบันจะกลายเป็น row context เพื่อใช้อ้างอิงใน Table2
Table2 table นิพจน์ตารางที่ถูกประเมินในบริบท (row context) ของแต่ละแถวใน Table1 แล้วนำผลมารวมกัน ถ้าผลว่างเปล่าในรอบไหน แถวจากนั้นจาก Table1 จะถูกตัดออก

Additional Notes

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 หรือขยายแถวตามเงื่อนไข พลังจริง ๆ เลย

How it works

ขยายตารางแม่ให้มีแถวย่อยตามเงื่อนไข

เช่น สร้างแถวรายละเอียดตามแต่ละรายการในตารางหลัก

สร้างตารางจากการวนแถวและคืนตารางย่อย

เหมาะกับการสร้างตารางคำนวณที่ต้องประกอบจากหลายส่วน

Examples

ตัวอย่างที่ 1: ขยายช่วงวันเป็นแถวเดี่ยวDateList = GENERATE( VALUES(DateRange[StartDate]), ADDCOLUMNS( GENERATESERIES([Value], [Value] + 10), "DayOffset", [Value] ) )

GENERATE วนแต่ละ StartDate แล้วสร้าง 11 แถว (offset 0–10) ผลลัพธ์คือ N×11 แถว

fx
DateList =
GENERATE(
VALUES(DateRange[StartDate]),
ADDCOLUMNS(
GENERATESERIES([Value], [Value] + 10),
"DayOffset", [Value]
)
)

ผลลัพธ์ตารางที่มี StartDate ของแต่ละแถว พร้อมคอลัมน์ DayOffset 0–10 ต่อแต่ละ StartDate
ตัวอย่างที่ 2: ดึงแถวลูกต่อแต่ละหมวดหมู่ (Unpivot Pattern)CategoryWithProducts = GENERATE( VALUES(Product[Category]), FILTER( Product, Product[Category] = EARLIER(Product[Category]) ) )

วนหมวดหมู่แต่ละหมวด แล้วดึงผลิตภัณฑ์ที่ตรงกับหมวดนั้น EARLIER() ใช้อ้างอิงค่า row context

fx
CategoryWithProducts =
GENERATE(
VALUES(Product[Category]),
FILTER(
Product,
Product[Category] = EARLIER(Product[Category])
)
)

ผลลัพธ์ตารางแสดงแต่ละหมวดหมู่พร้อมรายชื่อผลิตภัณฑ์ของหมวดนั้น
ตัวอย่างที่ 3: เปรียบเทียบ GENERATE กับ GENERATEALLWithout Empty = GENERATE(…) With Empty = GENERATEALL(…)

GENERATE ≈ SQL CROSS APPLY (ลบแถวที่ไม่มีข้อมูลในเงื่อนไข) | GENERATEALL ≈ SQL OUTER APPLY (คงไว้)

fx
Without Empty = GENERATE(…)
With Empty = GENERATEALL(…)

ผลลัพธ์ถ้า Table2 คืนค่าว่าง: GENERATE ตัดแถวออก | GENERATEALL เก็บแถว (NULL ในคอลัมน์ Table2)

FAQs

ทำไม EARLIER() ถึงสำคัญใน GENERATE?+

เพราะว่า GENERATE ส่งผ่าน row context จากแต่ละแถวของ Table1 ลงไปใน Table2 ถ้าคุณใช้ [Column] โดยตรง DAX อาจสับสน ว่าหมายถึง Table1 หรือ Table2 ดังนั้น EARLIER([Column]) ช่วยบอก "หมายถึงค่าบริบทนอก (outer context) นั่น"

เมื่อไหร่ใช้ GENERATE เมื่อไหร่ใช้ CROSSJOIN?+

CROSSJOIN = ผลคูณคาร์ทีเซียน (ทั้งหมด ×ทั้งหมด) | GENERATE = คูณเฉพาะส่วนที่ Table2 คืนมา ให้บริบทจาก Table1 จึงยืดหยุ่นกว่า

GENERATE ใช้ได้กับ DirectQuery ไหม?+

ใช้ได้บ้างนี่: ✓ Measures | ✓ Visual calculations | ✗ Calculated columns / RLS rules ใน DirectQuery mode

ประสิทธิภาพของ GENERATE เป็นไงบ้าง?+

ระวังปริมาณแถว: ถ้า Table1 มี 1,000 แถว และ Table2 ได้ 100 แถวต่อแถว ผลลัพธ์คือ 100,000 แถว อย่าลืมชั่งปริมาณ

Resources & Related

ฟังก์ชันที่ผู้เขียนโยงไว้กับ GENERATE จัดกลุ่มตามหมวด · ชี้ที่ชื่อใดชื่อหนึ่ง แล้วฟังก์ชันที่ใช้คู่กันจะมีจุดทอง

ฟังก์ชันนี้GENERATETable manipulation
Table manipulation (6)
ADDCOLUMNS

ADDCOLUMNS เป็นฟังก์ชัน table transformation ที่ใช้สำหรับเพิ่มคอลัมน์ใหม่ (Calculated Columns) เข้าไปในตารางที่มีอยู่เดิม โดยคำนวณค่าในแต่ละแถวผ่าน Row Context และส่งคืนตารางเดิมพร้อมคอลัมน์ใหม่ต่อท้าย

CROSSJOIN

CROSSJOIN สร้างตารางใหม่โดยการรวมแถวทั้งหมดจากตารางที่ระบุ โดยสร้างทุก Combination ที่เป็นไปได้ ผลลัพธ์คือตารางที่มีจำนวนแถวเท่ากับผลคูณของจำนวนแถวของแต่ละตาราง

GENERATEALL

GENERATEALL วนแถวของตาราง 1 แล้วสร้าง Cartesian product กับผลลัพธ์ของตาราง 2 โดยคงแถวที่ไม่มีข้อมูลย่อย ต่างจาก GENERATE ตรงที่ไม่ตัดแถวหลักออก

GENERATESERIES

GENERATESERIES สร้างตารางคอลัมน์เดียวที่เป็นลำดับตัวเลขจาก StartValue ถึง EndValue ด้วย increment ที่กำหนดได้ เหมาะกับตารางช่วย parameter table หรือสร้างชุดตัวเลขสำหรับ what-if analysis

SUMMARIZE

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

VALUES ดึงค่าที่ไม่ซ้ำจากคอลัมน์ หรือดึงแถวทั้งหมดจากตาราง โดยรวมแถว BLANK ที่เกิดจากข้อผิดพลาดของความสัมพันธ์ (Referential Integrity Violations) ส่วน DISTINCT จะไม่รวมแถว BLANK นี้

Other (1)
EARLIER

EARLIER คืนค่าของคอลัมน์ใน Row Context ชั้นนอก (Outer Row Context) เพื่อให้คอลัมน์คำนวณสามารถอ้างอิงค่า “ของแถวปัจจุบัน” ระหว่างการวนซ้อน (เช่น FILTER ภายใน Calculated Column) ได้

Filter (1)
FILTER

FILTER ใช้กรองแถวในตารางตามเงื่อนไขที่ซับซ้อน โดยวนลูปทุกแถวและประเมินเงื่อนไข เหมาะกับการกรองด้วย Measure หรือ Expression ซึ่ง Boolean Expression ทำไม่ได้ แต่ต้องระวังเรื่อง Performance เพราะเป็น Iterator Function ที่ช้ากว่า Boolean Expression ดังนั้นควรใช้เฉพาะเมื่อจำเป็น และอย่าใช้ FILTER กับ RELATED เพื่อกรองข้ามตาราง ให้กรองที่ Dimension Table โดยตรงแทน

Comments

อีเมลของคุณจะไม่ถูกเผยแพร่