Table.Group จัดกลุ่มข้อมูลตามคอลัมน์ที่กำหนดและสรุปผลในแต่ละกลุ่มด้วย aggregation functions เช่น List.Sum, List.Count, List.Average คล้ายกับ GROUP BY ใน SQL แต่ทรงพลังกว่าเพราะสามารถจัดกลุ่มหลายคอลัมน์พร้อมกันและสร้างคอลัมน์สรุปผลหลายคอลัมน์ในคำสั่งเดียว รองรับ GroupKind.Local เพื่อเพิ่มประสิทธิภาพเมื่อข้อมูลเรียงลำดับแล้ว
=Table.Group(table as table, key as any, aggregatedColumns as list, optional groupKind as nullable number, optional comparer as nullable function) as table
=Table.Group(table as table, key as any, aggregatedColumns as list, optional groupKind as nullable number, optional comparer as nullable function) as table
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| table | table | Yes | ตารางข้อมูลต้นทางที่ต้องการจัดกลุ่ม | |
| key | any | Yes | ชื่อคอลัมน์ที่ใช้จัดกลุ่ม สามารถเป็น text เดี่ยว (เช่น “Category”) หรือ list ของชื่อคอลัมน์ (เช่น {“Region”, “Category”}) สำหรับจัดกลุ่มหลายระดับ | |
| aggregatedColumns | list | Yes | รายการของคอลัมน์ที่ต้องการสร้างจากการสรุปผล แต่ละรายการเป็น list ที่มี 3 ส่วน: {“ชื่อคอลัมน์ใหม่”, each ฟังก์ชันสรุปผล, type ชนิดข้อมูล} เช่น {{“TotalSales”, each List.Sum([Sales]), type number}} | |
| groupKind | nullable number | Optional | GroupKind.Global | ประเภทการจัดกลุ่ม ใช้ GroupKind.Local ถ้าข้อมูลเรียงลำดับตาม key columns แล้วเพื่อเพิ่มประสิทธิภาพ (Local group = กลุ่มที่เกิดจาก row ติดกัน, Global group = กลุ่มที่รวมทุก row ที่มี key เดียวกัน) ค่าเริ่มต้นคือ GroupKind.Global |
| comparer | nullable function | Optional | null | ฟังก์ชันสำหรับเปรียบเทียบค่า key ที่กำหนดเอง ถ้า comparer ถือว่า key ที่ต่างกันเป็นค่าเดียวกัน row นั้นอาจถูกจัดเข้ากลุ่มที่มีค่า key แตกต่างกัน |
จัดกลุ่มข้อมูลการขายตามสาขาและหาผลรวมยอดขาย ค่าเฉลี่ยต่อรายการ และจำนวนรายการในแต่ละสาขา
นับจำนวนคำสั่งซื้อต่อลูกค้า หามูลค่ารวมและค่าเฉลี่ยต่อคำสั่งซื้อเพื่อวิเคราะห์พฤติกรรมการซื้อ
จัดกลุ่มข้อมูลตามหลายมิติพร้อมกัน เช่น หมวดหมู่สินค้าและเดือน เพื่อสร้างรายงานยอดขายแบบสรุป
คำนวณค่าสูงสุด ต่ำสุด ค่าเฉลี่ย และส่วนเบี่ยงเบนมาตรฐานของข้อมูลในแต่ละกลุ่ม
let Sales = Table.FromRecords({ [Category = "Electronics", Amount = 500], [Category = "Electronics", Amount = 800], [Category = "Furniture", Amount = 1200], [Ca…let
Sales = Table.FromRecords({
[Category = "Electronics", Amount = 500],
[Category = "Electronics", Amount = 800],
[Category = "Furniture", Amount = 1200],
[Category = "Furniture", Amount = 600]
}),
GroupedSales = Table.Group(
Sales,
"Category",
{{"TotalAmount", each List.Sum([Amount]), type number}}
)
in
GroupedSales
Table with 2 rows:
- [Category="Electronics", TotalAmount=1300]
- [Category="Furniture", TotalAmount=1800]
let Orders = Table.FromRecords({ [CustomerID = 1, OrderValue = 100], [CustomerID = 1, OrderValue = 150], [CustomerID = 2, OrderValue = 200], [CustomerID = 2, Or…let
Orders = Table.FromRecords({
[CustomerID = 1, OrderValue = 100],
[CustomerID = 1, OrderValue = 150],
[CustomerID = 2, OrderValue = 200],
[CustomerID = 2, OrderValue = 300],
[CustomerID = 2, OrderValue = 100]
}),
CustomerSummary = Table.Group(
Orders,
"CustomerID",
{
{"TotalOrders", each Table.RowCount(_), Int64.Type},
{"TotalValue", each List.Sum([OrderValue]), type number},
{"AverageValue", each List.Average([OrderValue]), type number},
{"MaxValue", each List.Max([OrderValue]), type number}
}
)
in
CustomerSummary
Table with 2 rows:
- [CustomerID=1, TotalOrders=2, TotalValue=250, AverageValue=125, MaxValue=150]
- [CustomerID=2, TotalOrders=3, TotalValue=600, AverageValue=200, MaxValue=300]
let RegionalSales = Table.FromRecords({ [Region = "North", Product = "A", Sales = 100], [Region = "North", Product = "A", Sales = 200], [Region = "North", Produ…let
RegionalSales = Table.FromRecords({
[Region = "North", Product = "A", Sales = 100],
[Region = "North", Product = "A", Sales = 200],
[Region = "North", Product = "B", Sales = 150],
[Region = "South", Product = "A", Sales = 300],
[Region = "South", Product = "B", Sales = 250]
}),
GroupedByRegionProduct = Table.Group(
RegionalSales,
{"Region", "Product"},
{
{"TotalSales", each List.Sum([Sales]), type number},
{"TransactionCount", each List.Count([Sales]), Int64.Type}
}
)
in
GroupedByRegionProduct
Table with 3 rows:
- [Region="North", Product="A", TotalSales=300, TransactionCount=2]
- [Region="North", Product="B", TotalSales=150, TransactionCount=1]
- [Region="South", Product="A", TotalSales=300, TransactionCount=1]
let SortedData = Table.FromRecords({ [Status = "Active", Value = 100], [Status = "Active", Value = 200], [Status = "Active", Value = 150], [Status = "Inactive",…let
SortedData = Table.FromRecords({
[Status = "Active", Value = 100],
[Status = "Active", Value = 200],
[Status = "Active", Value = 150],
[Status = "Inactive", Value = 50],
[Status = "Inactive", Value = 75]
}),
// ข้อมูลเรียงลำดับตาม Status แล้ว (Active ติดกันหมด, Inactive ติดกันหมด)
GroupedWithLocal = Table.Group(
SortedData,
"Status",
{{"Total", each List.Sum([Value]), type number}},
GroupKind.Local // ระบุว่าข้อมูลเรียงลำดับแล้ว
)
in
GroupedWithLocal
Table with 2 rows:
- [Status="Active", Total=450]
- [Status="Inactive", Total=125]
let TransactionData = Table.FromRecords({ [Date = #date(2024, 1, 15), Category = "A", Amount = 100], [Date = #date(2024, 1, 20), Category = "A", Amount = 200],…let
TransactionData = Table.FromRecords({
[Date = #date(2024, 1, 15), Category = "A", Amount = 100],
[Date = #date(2024, 1, 20), Category = "A", Amount = 200],
[Date = #date(2024, 2, 10), Category = "B", Amount = 150],
[Date = #date(2024, 2, 25), Category = "B", Amount = 300]
}),
// ขั้นตอน 1: กรองเฉพาะเดือนมกราคม
JanuaryOnly = Table.SelectRows(
TransactionData,
each Date.Month([Date]) = 1
),
// ขั้นตอน 2: จัดกลุ่มและสรุปผล
GroupedByCategory = Table.Group(
JanuaryOnly,
"Category",
{
{"TotalAmount", each List.Sum([Amount]), type number},
{"RunningTotal", each List.Accumulate([Amount], 0, (state, current) => state + current), type number}
}
)
in
GroupedByCategory
Table with 1 row:
- [Category="A", TotalAmount=300, RunningTotal=300]
คำถามนี้เจอบ่อยมากครับ เพราะทั้งสองตัวดูคล้ายกัน 😅
.
Table.Group ใช้สำหรับจัดกลุ่มข้อมูลจาก flat table และสร้างคอลัมน์สรุปผลใหม่ในขั้นตอนเดียว
.
ส่วน Table.AggregateTableColumn ใช้เมื่อมีคอลัมน์ที่เป็น nested table อยู่แล้ว และต้องการ aggregate ข้อมูลจาก nested table นั้น
.
พูดง่ายๆ คือ Table.Group สร้างการจัดกลุ่มขึ้นมาใหม่ ขณะที่ Table.AggregateTableColumn ทำงานกับโครงสร้างที่มีอยู่แล้ว
นี่เป็นจุดที่หลายคนงงกันครับ 😅
.
เพราะ Table.RowCount รับ table เป็น argument ไม่ใช่ list ดังนั้น _ จึงหมายถึง table ของกลุ่มนั้นทั้งหมด
.
ส่วน [ColumnName] จะให้ list ของค่าในคอลัมน์นั้น ถ้าใช้ List.Count([ColumnName]) จะนับจำนวน element ใน list ขณะที่ Table.RowCount(_) จะนับจำนวน row ทั้งหมดใน table ของกลุ่มนั้น
.
ง่ายๆ คือ _ = table, [ColumnName] = list ครับ
ใช้ GroupKind.Local เมื่อข้อมูลเรียงลำดับตาม key columns แล้ว (row ที่มี key เดียวกันอยู่ติดกัน) จะช่วยเพิ่มประสิทธิภาพได้มากเพราะ Power Query ไม่ต้องสแกนทั้ง table
.
แต่ถ้าข้อมูลยังไม่เรียงลำดับ ต้องใช้ค่าเริ่มต้น (GroupKind.Global) หรือเรียงลำดับด้วย Table.Sort ก่อนครับ
.
ส่วนตัวผมจะเช็คก่อนเสมอว่าข้อมูลเรียงอยู่แล้วหรือเปล่า ถ้าเรียงแล้วก็ใส่ GroupKind.Local เลย เพราะช่วยได้เยอะถ้าข้อมูลเยอะ 💡
ได้สิครับ นี่แหละที่ทำให้ Table.Group ทรงพลัง! 😎
.
คุณสามารถเขียน custom function ภายใน each ได้ เช่น:
– each List.Sum(List.Select([Amount], each _ > 100)) → หาผลรวมเฉพาะค่าที่มากกว่า 100
– each List.Accumulate(…) → คำนวณ running total หรือผลคูณสะสม
– each List.Max([Price]) – List.Min([Price]) → หาช่วงของราคา
.
เทคนิคนี้ทำให้เราวิเคราะห์ข้อมูลได้แบบ custom ตามที่ต้องการเลยครับ
เคยเจอมั้ยครับที่ group แล้วลำดับมันไม่เป็นที่? 😅
.
ตาม Microsoft Learn ระบุไว้ว่า Table.Group ไม่รับประกันว่าผลลัพธ์จะเรียงลำดับแบบใดแบบหนึ่ง
.
ถ้าต้องการให้ผลลัพธ์เรียงลำดับ ต้องใช้ Table.Sort หลังจาก Table.Group เสมอ เช่น:
Table.Sort(GroupedTable, “Category”)
.
ผมแนะนำให้ทำเป็นนิสัยเลยครับ group แล้วก็ sort ตาม เพราะไม่งั้นลำดับมันอาจไม่เป็นที่คาดหวัง
ได้ครับ แต่ต้องระวังเรื่อง null นิดนึง 💡
.
Aggregation functions บางตัวจัดการ null แตกต่างกัน:
– List.Sum และ List.Average จะข้าม null values โดยอัตโนมัติ
– List.Count นับทุกค่า รวม null ด้วย
– List.NonNullCount นับเฉพาะค่าที่ไม่ใช่ null
.
ถ้าไม่แน่ใจว่า null จะส่งผลมั้ย แนะนำให้ใช้ List.Select กรอง null ออกก่อนทำการคำนวณจะปลอดภัยกว่าครับ
Table.Group เป็นฟังก์ชันที่ผมใช้บ่อยที่สุดใน Power Query เลยครับ เพราะมันทรงพลังมากกก 😎
ฟังก์ชันนี้ใช้จัดกลุ่มข้อมูลตามคอลัมน์ที่กำหนด แล้วทำการสรุปผล (Aggregation) ในแต่ละกลุ่มได้พร้อมกันเลย เช่น หาผลรวมยอดขาย นับจำนวนรายการ หาค่าเฉลี่ย หรือหาค่าสูงสุด/ต่ำสุด
.
ถ้าเคยใช้ SQL ก็คล้ายๆ กับ GROUP BY นั่นแหละ แต่ที่เจ๋งกว่าคือ… Table.Group สามารถสร้างคอลัมน์สรุปผลหลายคอลัมน์ในคำสั่งเดียวได้เลย ไม่ต้องมาทำทีละ step 💡
.
วิธีทำงานก็คือ มันจะจัดกลุ่ม row ที่มีค่าเหมือนกันในคอลัมน์ที่กำหนดเข้าด้วยกัน จากนั้นสร้าง record ใหม่สำหรับแต่ละกลุ่มที่ประกอบด้วยค่าของ key columns และคอลัมน์สรุปผลที่คำนวณจากข้อมูลในกลุ่มนั้น
.
สามารถใช้ร่วมกับฟังก์ชัน aggregation อื่นๆ ได้สารพัด:
.
ที่สำคัญอีกอย่างคือ… ถ้าข้อมูลเรียงลำดับตาม key columns อยู่แล้ว สามารถระบุ GroupKind.Local เพื่อเพิ่มประสิทธิภาพได้เลย ส่วนตัวผมใช้เทคนิคนี้กับข้อมูลขนาดใหญ่แล้วช่วยได้เยอะครับ ⚡