Table.ExpandTableColumn ใช้แตกข้อมูลจากคอลัมน์ที่เป็น nested table ออกมาเป็นคอลัมน์และแถวปกติในตารางหลัก โดยรักษาข้อมูลคอลัมน์อื่นไว้ และทำซ้ำแถวหลักสำหรับแต่ละแถวในตารางซ้อน มักใช้คู่กับ Table.NestedJoin หลัง join ตาราง หรือใช้ขยายข้อมูลจากแหล่งที่มีโครงสร้างแบบ hierarchical เช่น JSON หรือ API
=Table.ExpandTableColumn(table as table, column as text, columnNames as list, optional newColumnNames as nullable list) as table
=Table.ExpandTableColumn(table as table, column as text, columnNames as list, optional newColumnNames as nullable list) as table
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| table | table | Yes | ตารางต้นทางที่มีคอลัมน์ซึ่งเก็บค่าเป็น table (nested table column) | |
| column | text | Yes | ชื่อคอลัมน์ที่ต้องการแตกข้อมูล ซึ่งคอลัมน์นี้ต้องมีค่าเป็น table | |
| columnNames | list | Yes | list ของชื่อคอลัมน์ในตารางซ้อนที่ต้องการดึงออกมาแสดง เช่น {“Name”, “Price”, “Quantity”} | |
| newColumnNames | nullable list | Optional | null | list ของชื่อคอลัมน์ใหม่ที่จะใช้แทนชื่อเดิม เพื่อป้องกันปัญหาชื่อคอลัมน์ซ้ำกับตารางหลัก แนะนำให้ระบุเสมอเมื่อมีโอกาสชื่อซ้ำ |
หลังจากใช้ Table.NestedJoin เพื่อ join ตารางสองตารางเข้าด้วยกัน ผลลัพธ์จะมีคอลัมน์ที่เก็บตารางที่ join มา จำเป็นต้องใช้ Table.ExpandTableColumn เพื่อดึงคอลัมน์จากตารางที่ join มาแสดงในตารางหลัก
เมื่อใช้ Table.Group เพื่อจัดกลุ่มข้อมูลโดยไม่ใช้ aggregation function ผลลัพธ์จะได้ตารางซ้อนที่เก็บแถวทั้งหมดในแต่ละกลุ่ม ต้องใช้ Table.ExpandTableColumn เพื่อแตกกลับมาเป็นแถวปกติ
ข้อมูลจาก Web API หรือไฟล์ JSON มักมีโครงสร้างแบบ nested tables (เช่น orders ที่มี order_items ซ้อนอยู่) ต้องใช้ Table.ExpandTableColumn เพื่อ flatten ข้อมูลให้อยู่ในรูป relational table
บาง database connector คืนผลลัพธ์แบบ nested structure เช่น query ที่มี subquery หรือข้อมูลจากหลาย table ต้องใช้ Table.ExpandTableColumn เพื่อแปลงเป็น flat table
let // สร้างตารางต้นทางที่มีคอลัมน์ ProductID และคอลัมน์ Details ที่เป็น table Source = Table.FromRecords({ [ ProductID = 1, Details = Table.FromRecords({ [Colo…let
// สร้างตารางต้นทางที่มีคอลัมน์ ProductID และคอลัมน์ Details ที่เป็น table
Source = Table.FromRecords({
[
ProductID = 1,
Details = Table.FromRecords({
[Color = "Red", Size = "M"],
[Color = "Blue", Size = "L"]
})
],
[
ProductID = 2,
Details = Table.FromRecords({
[Color = "Green", Size = "S"]
})
]
}),
// แตกคอลัมน์ Details ออกมาเป็นคอลัมน์ Color และ Size
Expanded = Table.ExpandTableColumn(
Source,
"Details",
{"Color", "Size"}
)
in
Expanded
Table ที่มี 3 แถว:
• ProductID=1, Color="Red", Size="M"
• ProductID=1, Color="Blue", Size="L"
• ProductID=2, Color="Green", Size="S"
คอลัมน์ Details ถูกแทนที่ด้วย Color และ Size
let // สร้างตารางที่มีคอลัมน์ OrderID, Amount และ Items (table) ที่มีคอลัมน์ Amount ซ้ำชื่อ Source = Table.FromRecords({ [ OrderID = 100, Amount = 5000, Items =…=let
// สร้างตารางที่มีคอลัมน์ OrderID, Amount และ Items (table) ที่มีคอลัมน์ Amount ซ้ำชื่อ
Source = Table.FromRecords({
[
OrderID = 100,
Amount = 5000,
Items = Table.FromRecords({
[Product = "Laptop", Amount = 2000, Qty = 2],
[Product = "Mouse", Amount = 500, Qty = 2]
})
],
[
OrderID = 101,
Amount = 1500,
Items = Table.FromRecords({
[Product = "Keyboard", Amount = 1500, Qty = 1]
})
]
}),
// แตกคอลัมน์ Items และเปลี่ยนชื่อ Amount เป็น ItemAmount เพื่อป้องกันชื่อซ้ำ
Expanded = Table.ExpandTableColumn(
Source,
"Items",
{"Product", "Amount", "Qty"},
{"ProductName", "ItemAmount", "Quantity"}
)
in
Expanded
Table ที่มี 3 แถว:
• OrderID=100, Amount=5000, ProductName="Laptop", ItemAmount=2000, Quantity=2
• OrderID=100, Amount=5000, ProductName="Mouse", ItemAmount=500, Quantity=2
• OrderID=101, Amount=1500, ProductName="Keyboard", ItemAmount=1500, Quantity=1
ไม่มีปัญหาชื่อคอลัมน์ซ้ำระหว่าง Amount (order) และ ItemAmount (item)
let // ตารางลูกค้า Customers = Table.FromRecords({ [CustomerID = 1, CustomerName = "Alice"], [CustomerID = 2, CustomerName = "Bob"] }), // ตารางคำสั่งซื้อ Order…let
// ตารางลูกค้า
Customers = Table.FromRecords({
[CustomerID = 1, CustomerName = "Alice"],
[CustomerID = 2, CustomerName = "Bob"]
}),
// ตารางคำสั่งซื้อ
Orders = Table.FromRecords({
[OrderID = 101, CustomerID = 1, OrderDate = #date(2024, 1, 15), Total = 2500],
[OrderID = 102, CustomerID = 1, OrderDate = #date(2024, 2, 10), Total = 1200],
[OrderID = 103, CustomerID = 2, OrderDate = #date(2024, 1, 20), Total = 3000]
}),
// Join ตารางโดยเก็บผลลัพธ์ไว้ใน nested table
Joined = Table.NestedJoin(
Customers,
{"CustomerID"},
Orders,
{"CustomerID"},
"CustomerOrders",
JoinKind.LeftOuter
),
// แตกคอลัมน์ CustomerOrders เพื่อดึงข้อมูล OrderDate และ Total
Expanded = Table.ExpandTableColumn(
Joined,
"CustomerOrders",
{"OrderID", "OrderDate", "Total"},
{"OrderID", "OrderDate", "OrderTotal"}
)
in
Expanded
Table ที่มี 3 แถว:
• CustomerID=1, CustomerName="Alice", OrderID=101, OrderDate=2024-01-15, OrderTotal=2500
• CustomerID=1, CustomerName="Alice", OrderID=102, OrderDate=2024-02-10, OrderTotal=1200
• CustomerID=2, CustomerName="Bob", OrderID=103, OrderDate=2024-01-20, OrderTotal=3000
ข้อมูลลูกค้าถูกทำซ้ำสำหรับแต่ละ order
let // สร้างตารางที่มีข้อมูลพนักงานและประวัติการทำงาน Source = Table.FromRecords({ [ EmployeeID = "E001", EmployeeName = "John Doe", Department = "Sales", WorkH…let
// สร้างตารางที่มีข้อมูลพนักงานและประวัติการทำงาน
Source = Table.FromRecords({
[
EmployeeID = "E001",
EmployeeName = "John Doe",
Department = "Sales",
WorkHistory = Table.FromRecords({
[Company = "ABC Corp", Position = "Sales Rep", Years = 3, Salary = 50000, StartDate = #date(2019, 1, 1)],
[Company = "XYZ Ltd", Position = "Sales Manager", Years = 2, Salary = 70000, StartDate = #date(2022, 6, 1)]
})
],
[
EmployeeID = "E002",
EmployeeName = "Jane Smith",
Department = "IT",
WorkHistory = Table.FromRecords({
[Company = "Tech Inc", Position = "Developer", Years = 5, Salary = 80000, StartDate = #date(2018, 3, 15)]
})
]
}),
// แตกเฉพาะคอลัมน์ Company, Position และ Years จาก WorkHistory (ไม่เอา Salary และ StartDate)
Expanded = Table.ExpandTableColumn(
Source,
"WorkHistory",
{"Company", "Position", "Years"},
{"PreviousCompany", "PreviousPosition", "YearsWorked"}
)
in
Expanded
Table ที่มี 3 แถว:
• EmployeeID="E001", EmployeeName="John Doe", Department="Sales", PreviousCompany="ABC Corp", PreviousPosition="Sales Rep", YearsWorked=3
• EmployeeID="E001", EmployeeName="John Doe", Department="Sales", PreviousCompany="XYZ Ltd", PreviousPosition="Sales Manager", YearsWorked=2
• EmployeeID="E002", EmployeeName="Jane Smith", Department="IT", PreviousCompany="Tech Inc", PreviousPosition="Developer", YearsWorked=5
คอลัมน์ Salary และ StartDate ไม่ถูกดึงออกมา
ถ้าไม่ระบุ newColumnNames ฟังก์ชันจะใช้ชื่อเดิมจากคอลัมน์ในตารางซ้อน ซึ่งอาจทำให้เกิดปัญหาชื่อคอลัมน์ซ้ำกับตารางหลักและเกิด error ได้
.
ยกตัวอย่างเช่น ถ้าตารางหลักมีคอลัมน์ “Amount” และตารางซ้อนก็มี “Amount” พอแตกออกมาจะมีชื่อซ้ำกัน Power Query จะ error ทันที 😭
.
ส่วนตัวผมแนะนำให้ระบุ newColumnNames เสมอครับ แม้ว่าชื่อจะไม่ซ้ำก็ตาม เพราะทำให้โค้ดอ่านง่ายและป้องกันปัญหาในอนาคต
ถ้าตารางซ้อนไม่มีแถว (empty table) แถวนั้นจะหายไปจากผลลัพธ์เลยครับ 😭
.
ทำงานเหมือน Inner Join นั่นเอง ยกตัวอย่าง ถ้าใช้ Table.NestedJoin แบบ LeftOuter แล้วบางแถวไม่มีข้อมูล join ได้ (nested table ว่างเปล่า) พอเรา expand ออกมา… แถวนั้นจะหายไป
.
นี่เป็นพฤติกรรมที่ต้องระวังมากครับ ถ้าต้องการรักษาแถวเอาไว้ ต้องตรวจสอบก่อน expand ด้วย Table.RowCount หรือใช้ conditional logic เพื่อจัดการ case นี้
คำถามนี้เจอบ่อยมากครับ เพราะชื่อคล้ายกันมาก 😅
.
**Table.ExpandTableColumn** → แตก nested **table** ซึ่ง 1 แถวอาจกลายเป็นหลายแถว (one-to-many)
.
**Table.ExpandRecordColumn** → แตก **record** ซึ่ง 1 แถวยังคงเป็น 1 แถว (one-to-one) แค่เพิ่มคอลัมน์เข้ามา
.
ใช้ **ExpandTableColumn** เมื่อ: คอลัมน์เป็น table และต้องการ flatten ทุกแถว (เช่น 1 order มีหลาย items)
.
ใช้ **ExpandRecordColumn** เมื่อ: คอลัมน์เป็น record และต้องการดึง field ออกมา (เช่น address record ที่มี street, city, zip)
ไม่ได้โดยตรงครับ Table.ExpandTableColumn แตกได้ทีละ 1 คอลัมน์เท่านั้น
.
ถ้ามีหลายคอลัมน์ที่เป็น table ต้องเรียกฟังก์ชันนี้หลายครั้งต่อเนื่องกัน แบบนี้:
.
“`
ExpandTableColumn(
ExpandTableColumn(Source, “Col1”, …),
“Col2”,
…
)
“`
.
หรือใช้ step แยกกันใน Power Query Editor ซึ่งอ่านง่ายกว่า ส่วนตัวผมชอบแยก step เพราะ debug ง่ายกว่าครับ 😎
นี่เป็นปัญหาใหญ่ที่เจอบ่อยมากครับ 😭 ตารางที่มี 100 แถว ถ้าแต่ละแถวมี nested table 1,000 แถว พอ expand ได้ 100,000 แถวเลย!
.
**วิธีป้องกัน:**
.
1. **ตรวจสอบก่อน expand** ด้วย Table.AddColumn:
“`
Table.AddColumn(Source, “RowCount”, each Table.RowCount([Details]))
“`
.
2. **จำกัดจำนวนแถว** ก่อน expand:
“`
Table.TransformColumns(Source, {{“Details”, each Table.FirstN(_, 10)}})
“`
.
3. **กรองข้อมูล** ที่ไม่จำเป็นออกก่อน:
“`
Table.SelectRows(Source, each Table.RowCount([Details]) <= 100)
“`
.
ส่วนตัวผมแนะนำให้ตรวจสอบก่อนเสมอครับ เพื่อป้องกัน performance issue และ memory overflow
Table.ExpandTableColumn เป็นฟังก์ชันสำคัญใน Power Query ที่ใช้แตกข้อมูลจากคอลัมน์ที่มีค่าเป็น Table (Nested Table หรือตารางซ้อน) ให้กลายเป็นคอลัมน์ปกติในตารางหลัก ซึ่งแต่ละแถวในตารางย่อยจะกลายเป็นแถวใหม่ในตารางผลลัพธ์ครับ
.
ฟังก์ชันนี้มักใช้คู่กับ Table.NestedJoin เมื่อทำการ join ตารางแล้วต้องการดึงข้อมูลจากตารางที่ join มาแสดง หรือใช้หลังจากทำ Table.Group เพื่อแตกข้อมูลจากผลลัพธ์ที่จัดกลุ่มไว้
.
นอกจากนี้ยังใช้ขยายข้อมูลที่ได้จากแหล่งข้อมูลภายนอกเช่น Web API, ฐานข้อมูล หรือไฟล์ที่มีโครงสร้างแบบ nested structure ซึ่งเจอบ่อยมากเวลาทำงานกับ JSON หรือ API response 😎
.
การทำงานของ Table.ExpandTableColumn คือการรักษาคอลัมน์อื่นๆ ในตารางหลักไว้ แล้วดึงคอลัมน์ที่ต้องการจากตารางซ้อนมาเพิ่มเป็นคอลัมน์ใหม่
.
โดยแต่ละแถวในตารางย่อยจะถูก “ทำซ้ำ” พร้อมกับข้อมูลจากแถวหลัก ทำให้ได้โครงสร้างข้อมูลแบบ flat table ที่สามารถวิเคราะห์และใช้งานได้ง่ายครับ 💡