Thep Excel

GROUPBY – จัดกลุ่มและคำนวณแบบละเอียด

GROUPBY สร้างตารางสรุปโดยจัดกลุ่มตามคอลัมน์ที่กำหนด และเพิ่มคอลัมน์คำนวณแบบกลุ่มต่อกลุ่มได้ โดยใช้ CURRENTGROUP() เข้าถึงแถวภายในกลุ่ม เหมาะกับการคำนวณซ้อนหรือคำนวณจากคอลัมน์ชั่วคราว (local columns)

=GROUPBY(<Table>, [<GroupBy_ColumnName>], [<Name>], [<Expression>])

By ThepExcel AI Agent
13 December 2025

Function Metrics


Popularity
6/10

Difficulty
6/10

Usefulness
6/10

Syntax & Arguments

=GROUPBY(<Table>, [<GroupBy_ColumnName>], [<Name>], [<Expression>])

Argument Type Required Default Description
Table Table Yes ตารางต้นทางที่ต้องการจัดกลุ่ม (อาจเป็นตารางจาก model หรือตารางชั่วคราวจาก DAX ก็ได้)
GroupBy_ColumnName Column Optional ไม่มี คอลัมน์ที่ใช้จัดกลุ่ม (สามารถระบุหลายคอลัมน์ได้ตามต้องการ) – ถ้าไม่ระบุเลยจะได้ตารางแถวเดียว
Name String Optional ไม่มี ชื่อคอลัมน์ใหม่ที่ต้องการเพิ่มเข้าตารางผลลัพธ์ (เป็น String ต้องใส่ใน “…”)
Expression Expression Optional ไม่มี นิพจน์ที่ใช้คำนวณค่าสำหรับคอลัมน์ใหม่ (ควรใช้ CURRENTGROUP() ร่วมกับ iterator เช่น SUMX, MAXX, COUNTROWS)

How it works

สรุปยอดหรือจำนวนต่อกลุ่ม

เช่น ยอดรวมต่อ CustomerID หรือจำนวนแถวต่อกลุ่ม

คำนวณค่าต่อกลุ่มด้วย iterator

เช่น MAXX/MINX/SUMX ภายในกลุ่มผ่าน CURRENTGROUP

Examples

ตัวอย่างที่ 1: จัดกลุ่มพื้นฐาน – ยอดรวมต่อลูกค้า
Sales By Customer = GROUPBY( Sales, Sales[CustomerID], "Total Sales", SUMX(CURRENTGROUP(), Sales[Amount]) )
GROUPBY จัดกลุ่มตาราง Sales ตาม CustomerID แล้วใช้ SUMX ร่วมกับ CURRENTGROUP() เพื่อรวมยอด Amount ของทุกแถวในกลุ่มนั้น โดย CURRENTGROUP() คืนค่าเป็นตารางย่อยของแถวในกลุ่ม

Context: Sales มีคอลัมน์ CustomerID และ Amount

DAX Formula:

Sales By Customer =
GROUPBY(
    Sales,
    Sales[CustomerID],
    "Total Sales", SUMX(CURRENTGROUP(), Sales[Amount])
)

Result:

ตารางที่มี CustomerID และ Total Sales (ยอดรวมต่อลูกค้า)

ตัวอย่างที่ 2: จัดกลุ่มหลายคอลัมน์ – นับจำนวนธุรกรรม
Transaction Count = GROUPBY( Sales, Sales[CustomerID], Sales[ProductID], "Transaction Count", COUNTROWS(CURRENTGROUP()) )
จัดกลุ่มตามสองคอลัมน์พร้อมกัน (CustomerID และ ProductID) แล้วใช้ COUNTROWS(CURRENTGROUP()) นับจำนวนแถวในแต่ละกลุ่ม ผลลัพธ์จะบอกว่าลูกค้าแต่ละคนซื้อสินค้าแต่ละชนิดกี่ครั้ง

Context: Sales มีคอลัมน์ CustomerID, ProductID

DAX Formula:

Transaction Count =
GROUPBY(
    Sales,
    Sales[CustomerID],
    Sales[ProductID],
    "Transaction Count", COUNTROWS(CURRENTGROUP())
)

Result:

ตารางแสดงจำนวนธุรกรรมแยกตาม CustomerID และ ProductID

ตัวอย่างที่ 3: หลายคอลัมน์คำนวณในครั้งเดียว
Sales Summary = GROUPBY( Sales, Sales[CustomerID], "Total Sales", SUMX(CURRENTGROUP(), Sales[Amount]), "Avg Sales", AVERAGEX(CURRENTGROUP(), Sales[Amount]), "Ma…
GROUPBY สามารถเพิ่มหลายคอลัมน์คำนวณในครั้งเดียวได้ โดยแต่ละคอลัมน์ใช้ CURRENTGROUP() อ้างอิงกลุ่มเดียวกัน ซึ่งประหยัดกว่าการเรียก GROUPBY หลายรอบ

Context: Sales มีคอลัมน์ CustomerID, Amount

DAX Formula:

Sales Summary =
GROUPBY(
    Sales,
    Sales[CustomerID],
    "Total Sales", SUMX(CURRENTGROUP(), Sales[Amount]),
    "Avg Sales", AVERAGEX(CURRENTGROUP(), Sales[Amount]),
    "Max Sales", MAXX(CURRENTGROUP(), Sales[Amount])
)

Result:

ตารางสรุปที่มีทั้งยอดรวม, ค่าเฉลี่ย, และค่าสูงสุดต่อลูกค้า

ตัวอย่างที่ 4: Nested Grouping – คำนวณซ้อนชั้น
Max Avg Price By Category = VAR SubcategoryAvg = GROUPBY( Product, Product[Category], Product[Subcategory], "Avg Price", AVERAGEX(CURRENTGROUP(), Product[Price]…
นี่คือกรณีที่ GROUPBY เหนือกว่า SUMMARIZE อย่างชัดเจน! เราจัดกลุ่มสองชั้น:
1. กลุ่มย่อยระดับ Category + Subcategory หาค่าเฉลี่ยราคา (สร้าง local column [Avg Price])
2. จัดกลุ่มใหญ่ระดับ Category หาค่าสูงสุดจาก [Avg Price] ที่คำนวณไว้

ถ้าใช้ SUMMARIZE จะทำไม่ได้ เพราะมันรวบรวม (aggregate) คอลัมน์ชั่วคราวไม่ได้ ต้องใช้ GROUPBY กับ CURRENTGROUP() เท่านั้น

Context: Product มีคอลัมน์ Category, Subcategory, Price

DAX Formula:

Max Avg Price By Category =
VAR SubcategoryAvg =
    GROUPBY(
        Product,
        Product[Category],
        Product[Subcategory],
        "Avg Price", AVERAGEX(CURRENTGROUP(), Product[Price])
    )
VAR MaxByCategory =
    GROUPBY(
        SubcategoryAvg,
        [Category],
        "Max Subcategory Avg", MAXX(CURRENTGROUP(), [Avg Price])
    )
RETURN
    MaxByCategory

Result:

ตารางแสดงค่าเฉลี่ยราคาสูงสุดของ Subcategory ในแต่ละ Category

ตัวอย่างที่ 5: จัดกลุ่มโดยไม่ระบุคอลัมน์ – คำนวณทั้งตาราง
Overall Stats = GROUPBY( Sales, "Total Amount", SUMX(CURRENTGROUP(), Sales[Amount]), "Row Count", COUNTROWS(CURRENTGROUP()) )
ถ้าไม่ระบุ GroupBy_ColumnName เลย GROUPBY จะคำนวณทั้งตาราง (ได้ตารางแถวเดียว) คล้ายการ aggregate ทั้งหมดโดยไม่แบ่งกลุ่ม ใช้ได้เมื่อต้องการคำนวณหลายค่าจากตารางพร้อมกัน

Context: Sales มีคอลัมน์ Amount

DAX Formula:

Overall Stats =
GROUPBY(
    Sales,
    "Total Amount", SUMX(CURRENTGROUP(), Sales[Amount]),
    "Row Count", COUNTROWS(CURRENTGROUP())
)

Result:

ตารางแถวเดียวที่มียอดรวมทั้งหมดและจำนวนแถวทั้งหมด

FAQs

GROUPBY ต่างจาก SUMMARIZE อย่างไร?

ต่างกันทั้งประสิทธิภาพและความสามารถ:
• SUMMARIZE ใช้เทคนิค “clustering” ที่ส่งคำสั่งไปทำที่ storage engine (VertiPaq) เลย จึงเร็วกว่าเมื่อจัดกลุ่มตามคอลัมน์ใน model แต่จัดการคอลัมน์ชั่วคราว (local columns) ได้ไม่ดี และอาจให้ผลลัพธ์ไม่ตรงความตั้งใจในบางกรณี
• GROUPBY ทำงานที่ formula engine หลังจาก materialize ตารางมาแล้ว ช้ากว่าเมื่อจัดกลุ่มตามคอลัมน์ใน model แต่จัดการคอลัมน์ชั่วคราวได้ดี และต้องใช้ CURRENTGROUP() เสมอ

หลักง่ายๆ: ใช้ SUMMARIZE กับคอลัมน์จริง, ใช้ GROUPBY กับคอลัมน์ชั่วคราว

ทำไมต้องใช้ CURRENTGROUP() เสมอใน Expression?

เพราะ GROUPBY ถูกออกแบบมาให้ทำงานกับ CURRENTGROUP() โดยเฉพาะ ถ้าเขียน Expression โดยไม่ใช้ CURRENTGROUP() อาจได้ผลลัพธ์ไม่ตรงตามที่คาดหวัง หรือ error ในบาง DAX version เพราะ Microsoft เปลี่ยนพฤติกรรมของ GROUPBY ให้รองรับเฉพาะ CURRENTGROUP() เท่านั้น

CURRENTGROUP() คือ “ตัวแทน” ของแถวทั้งหมดในกลุ่มนั้นๆ ที่ iterator function (SUMX, MAXX, ฯลฯ) ต้องการใช้

GROUPBY ใช้ CALCULATE ได้ไหม?

ใช้ไม่ได้! เพราะ Expression ใน GROUPBY ทำงานแบบ row-by-row iteration โดยไม่มี context transition ที่ CALCULATE ต้องการ ถ้าพยายามใส่ CALCULATE จะได้ error หรือผลลัพธ์ผิดพลาด

ถ้าต้องการ context transition ให้ใช้ SUMMARIZE หรือ ADDCOLUMNS แทน

Nested Grouping ควรใช้อะไร?

ใช้แบบผสม เพื่อให้ได้ทั้งประสิทธิภาพและความยืดหยุ่น:
1. ใช้ SUMMARIZE จัดกลุ่มชั้นในก่อน (จากตารางใน model) → เร็ว
2. ใช้ GROUPBY จัดกลุ่มชั้นนอก (จากตารางชั่วคราว) → คำนวณคอลัมน์ชั่วคราวได้

ตัวอย่าง:
VAR InnerGroup = SUMMARIZE(Sales, Sales[Category], Sales[Subcategory])
VAR OuterCalc = GROUPBY(InnerGroup, [Category], “Max”, MAXX(CURRENTGROUP(), …))

วิธีนี้หลีกเลี่ยงการ materialize ตารางใหญ่ด้วย GROUPBY ตั้งแต่แรก

ประสิทธิภาพของ GROUPBY เป็นอย่างไร?

GROUPBY ไม่ได้ใช้ VertiPaq storage engine เหมือน SUMMARIZE ทำให้ช้ากว่าเมื่อจัดกลุ่มตารางใหญ่ๆ จาก model เพราะต้อง materialize (โหลดข้อมูลมาเก็บในหน่วยความจำ formula engine) ทั้งหมด

ข้อแนะนำ:
• ใช้ GROUPBY กับตารางที่ผ่านการกรองหรือลดขนาดแล้ว (เล็กลง)
• ไม่ควรใช้ GROUPBY กับตาราง fact ขนาดใหญ่โดยตรง ให้ใช้ SUMMARIZE ลดขนาดก่อน
• เมื่อจำเป็นต้องใช้ GROUPBY ให้เก็บผลลัพธ์ไว้ใน VAR แล้วใช้ซ้ำ (ไม่ต้องคำนวณซ้ำ)

Resources & Related

Additional Notes

GROUPBY(

, , …, , , …)

GROUPBY เป็นฟังก์ชันตาราง (Table Function) ที่ใช้สร้างตารางสรุปโดยการจัดกลุ่มตามคอลัมน์ที่ระบุ และเพิ่มคอลัมน์คำนวณใหม่แบบกลุ่มต่อกลุ่มได้ ซึ่งใน Expression ต้องใช้ CURRENTGROUP() เป็นตัวอ้างอิงแถวภายในกลุ่ม เพื่อให้ iterator function เช่น SUMX, MAXX, AVERAGEX ทำงานกับแถวในกลุ่มนั้นๆ ได้

ที่เจ๋งของ GROUPBY คือ มันออกแบบมาให้จัดการกับ “คอลัมน์ชั่วคราว” (local columns) ที่สร้างขึ้นมาจากนิพจน์อื่นได้ดี เหมาะกับการทำ nested grouping หรือการคำนวณแบบซ้อนชั้น เช่น จัดกลุ่มย่อยก่อน คำนวณค่าเฉลี่ยในกลุ่มย่อย แล้วจัดกลุ่มใหญ่อีกทีเพื่อหาค่าสูงสุดของค่าเฉลี่ยเหล่านั้น

ส่วนตัวผมมองว่า GROUPBY กับ SUMMARIZE เป็นฟังก์ชันที่ผู้เขียน DAX มือใหม่มักสับสนกันบ่อยมาก แต่จริงๆ แล้วมีหลักง่ายๆ คือ:
• ใช้ SUMMARIZE เมื่อจัดกลุ่มตามคอลัมน์ใน model (คอลัมน์จริง) → เร็วกว่า เพราะใช้ VertiPaq storage engine
• ใช้ GROUPBY เมื่อจัดกลุ่มตามคอลัมน์ชั่วคราว (คำนวณมาจาก DAX) → ยืดหยุ่นกว่า แต่ช้ากว่าเพราะ materialize ข้อมูลใน formula engine

และข้อจำกัดสำคัญของ GROUPBY คือ ห้ามใช้ CALCULATE ภายใน Expression เพราะมัน iterate แบบ row-by-row โดยตรง ไม่มี context transition แบบที่ CALCULATE ต้องการ 😎

Leave a Reply

Your email address will not be published. Required fields are marked *

CookieDurationDescription
cookielawinfo-checkbox-analytics11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional11 monthsThe cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy11 monthsThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional
Performance
Analytics
Advertisement
Others