Thep Excel

Table.ExpandTableColumnแตกข้อมูลจากคอลัมน์ตารางที่ซ้อนกัน

Table.ExpandTableColumn ใช้แตกข้อมูลจากคอลัมน์ที่เป็น nested table ออกมาเป็นคอลัมน์และแถวปกติในตารางหลัก โดยรักษาข้อมูลคอลัมน์อื่นไว้ และทำซ้ำแถวหลักสำหรับแต่ละแถวในตารางซ้อน มักใช้คู่กับ Table.NestedJoin หลัง join ตาราง หรือใช้ขยายข้อมูลจากแหล่งที่มีโครงสร้างแบบ hierarchical เช่น JSON หรือ API

fx
=Table.ExpandTableColumn(table, column, columnNames, [newColumnNames]) as table

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

อัปเดต 18 December 2025

Syntax & Arguments

อาร์กิวเมนต์ ชนิด ค่าเริ่มต้น คำอธิบาย
table table ตารางต้นทางที่มีคอลัมน์ซึ่งเก็บค่าเป็น table (nested table column)
column text ชื่อคอลัมน์ที่ต้องการแตกข้อมูล ซึ่งคอลัมน์นี้ต้องมีค่าเป็น table
columnNames list list ของชื่อคอลัมน์ในตารางซ้อนที่ต้องการดึงออกมาแสดง เช่น {“Name”, “Price”, “Quantity”}
[newColumnNames]ไม่บังคับ nullable list null list ของชื่อคอลัมน์ใหม่ที่จะใช้แทนชื่อเดิม เพื่อป้องกันปัญหาชื่อคอลัมน์ซ้ำกับตารางหลัก แนะนำให้ระบุเสมอเมื่อมีโอกาสชื่อซ้ำ

[ ] = อาร์กิวเมนต์ที่ไม่บังคับ

Additional Notes

Table.ExpandTableColumn เป็นฟังก์ชันสำคัญใน Power Query ที่ใช้แตกข้อมูลจากคอลัมน์ที่มีค่าเป็น Table (Nested Table หรือตารางซ้อน) ให้กลายเป็นคอลัมน์ปกติในตารางหลัก ซึ่งแต่ละแถวในตารางย่อยจะกลายเป็นแถวใหม่ในตารางผลลัพธ์ครับ

.

ฟังก์ชันนี้มักใช้คู่กับ Table.NestedJoin เมื่อทำการ join ตารางแล้วต้องการดึงข้อมูลจากตารางที่ join มาแสดง หรือใช้หลังจากทำ Table.Group เพื่อแตกข้อมูลจากผลลัพธ์ที่จัดกลุ่มไว้

.

นอกจากนี้ยังใช้ขยายข้อมูลที่ได้จากแหล่งข้อมูลภายนอกเช่น Web API, ฐานข้อมูล หรือไฟล์ที่มีโครงสร้างแบบ nested structure ซึ่งเจอบ่อยมากเวลาทำงานกับ JSON หรือ API response 😎

.

การทำงานของ Table.ExpandTableColumn คือการรักษาคอลัมน์อื่นๆ ในตารางหลักไว้ แล้วดึงคอลัมน์ที่ต้องการจากตารางซ้อนมาเพิ่มเป็นคอลัมน์ใหม่

.

โดยแต่ละแถวในตารางย่อยจะถูก “ทำซ้ำ” พร้อมกับข้อมูลจากแถวหลัก ทำให้ได้โครงสร้างข้อมูลแบบ flat table ที่สามารถวิเคราะห์และใช้งานได้ง่ายครับ 💡

How it works

ขยายผลลัพธ์จาก Table.NestedJoin

หลังจากใช้ Table.NestedJoin เพื่อ join ตารางสองตารางเข้าด้วยกัน ผลลัพธ์จะมีคอลัมน์ที่เก็บตารางที่ join มา จำเป็นต้องใช้ Table.ExpandTableColumn เพื่อดึงคอลัมน์จากตารางที่ join มาแสดงในตารางหลัก

แตกข้อมูลหลังการจัดกลุ่ม (Table.Group)

เมื่อใช้ Table.Group เพื่อจัดกลุ่มข้อมูลโดยไม่ใช้ aggregation function ผลลัพธ์จะได้ตารางซ้อนที่เก็บแถวทั้งหมดในแต่ละกลุ่ม ต้องใช้ Table.ExpandTableColumn เพื่อแตกกลับมาเป็นแถวปกติ

ประมวลผลข้อมูล hierarchical จาก API หรือ JSON

ข้อมูลจาก Web API หรือไฟล์ JSON มักมีโครงสร้างแบบ nested tables (เช่น orders ที่มี order_items ซ้อนอยู่) ต้องใช้ Table.ExpandTableColumn เพื่อ flatten ข้อมูลให้อยู่ในรูป relational table

แตกข้อมูลจากฐานข้อมูลที่มีความสัมพันธ์

บาง database connector คืนผลลัพธ์แบบ nested structure เช่น query ที่มี subquery หรือข้อมูลจากหลาย table ต้องใช้ Table.ExpandTableColumn เพื่อแปลงเป็น flat table

Examples

ตัวอย่างที่ 1: การแตกคอลัมน์ตารางพื้นฐานlet // สร้างตารางต้นทางที่มีคอลัมน์ ProductID และคอลัมน์ Details ที่เป็น table Source = Table.FromRecords({ [ ProductID = 1, Details = Table.FromRecords({ [Colo…

นี่คือตัวอย่างพื้นฐานของการแตก nested table ครับ

สังเกตว่า ProductID=1 มี Details 2 แถว จึงกลายเป็น 2 แถวในผลลัพธ์ ส่วน ProductID=2 มี Details 1 แถว จึงได้ 1 แถว

คอลัมน์ ProductID ถูก "ทำซ้ำ" ให้ตรงกับจำนวนแถวใน nested table แต่ละแถว นี่คือ concept สำคัญของ ExpandTableColumn เลยครับ 💡

fx
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

ตัวอย่างที่ 2: ใช้ newColumnNames เพื่อหลีกเลี่ยงชื่อซ้ำlet // สร้างตารางที่มีคอลัมน์ OrderID, Amount และ Items (table) ที่มีคอลัมน์ Amount ซ้ำชื่อ Source = Table.FromRecords({ [ OrderID = 100, Amount = 5000, Items =…

ตัวอย่างนี้แสดงการใช้ argument ที่ 4 (newColumnNames) ซึ่งสำคัญมากครับ 💡

สังเกตว่าตารางหลักมีคอลัมน์ Amount (ยอดรวมของ order) และตารางซ้อนก็มี Amount (ราคาสินค้าแต่ละชิ้น) ถ้าไม่เปลี่ยนชื่อจะเกิด error ชื่อซ้ำทันที 😅

เลยต้องระบุ newColumnNames เพื่อเปลี่ยนชื่อให้ชัดเจน เช่น Amount → ItemAmount และ Product → ProductName

ส่วนตัวผมแนะนำให้ระบุ newColumnNames เสมอ แม้ชื่อจะไม่ซ้ำก็ตาม เพราะทำให้โค้ดอ่านง่ายและป้องกันปัญหาในอนาคต

fx
=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)

ตัวอย่างที่ 3: ใช้ร่วมกับ Table.NestedJoin (ขยายข้อมูลจาก join)let // ตารางลูกค้า Customers = Table.FromRecords({ [CustomerID = 1, CustomerName = "Alice"], [CustomerID = 2, CustomerName = "Bob"] }), // ตารางคำสั่งซื้อ Order…

นี่คือ use case ที่เจอบ่อยที่สุดเลยครับ 😎

เราใช้ Table.NestedJoin เพื่อ join ตารางแบบ one-to-many (1 ลูกค้ามีหลาย orders) โดยเก็บตารางย่อยไว้ในคอลัมน์ CustomerOrders ก่อน

จากนั้นใช้ Table.ExpandTableColumn เพื่อแตกคอลัมน์ CustomerOrders ออกมา ผลลัพธ์คือแต่ละแถวของลูกค้าจะถูก "ทำซ้ำ" ตามจำนวน orders ที่มี

ส่วนตัวผมชอบ pattern นี้มากกว่า Table.Join ตรงๆ เพราะควบคุม join behavior ได้ละเอียดกว่า และเห็นภาพข้อมูลชัดเจนกว่า

fx
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

ตัวอย่างที่ 4: เลือกแตกเฉพาะบางคอลัมน์จากตารางซ้อนlet // สร้างตารางที่มีข้อมูลพนักงานและประวัติการทำงาน Source = Table.FromRecords({ [ EmployeeID = "E001", EmployeeName = "John Doe", Department = "Sales", WorkH…

ตัวอย่างนี้แสดงเทคนิคที่สำคัญมากครับ ไม่จำเป็นต้องแตกทุกคอลัมน์จากตารางซ้อน 💡

สังเกตว่าตาราง WorkHistory มี 5 คอลัมน์ แต่เราเลือกแตกแค่ 3 คอลัมน์ที่สนใจ (Company, Position, Years) ไม่เอา Salary และ StartDate

วิธีนี้ช่วยลดขนาดข้อมูล ทำให้ query เร็วขึ้น และตารางอ่านง่ายขึ้นด้วย

ส่วนตัวผมมักใช้เทคนิคนี้เพื่อเลือกเฉพาะข้อมูลที่จำเป็นจริงๆ และเปลี่ยนชื่อให้มีความหมายชัดเจน เช่น Company → PreviousCompany เพื่อให้รู้ว่านี่คือข้อมูลในอดีต

fx
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 ไม่ถูกดึงออกมา

FAQs

ถ้าไม่ระบุ newColumnNames จะเกิดอะไรขึ้น?+

ถ้าไม่ระบุ newColumnNames ฟังก์ชันจะใช้ชื่อเดิมจากคอลัมน์ในตารางซ้อน ซึ่งอาจทำให้เกิดปัญหาชื่อคอลัมน์ซ้ำกับตารางหลักและเกิด error ได้

ยกตัวอย่างเช่น ถ้าตารางหลักมีคอลัมน์ "Amount" และตารางซ้อนก็มี "Amount" พอแตกออกมาจะมีชื่อซ้ำกัน Power Query จะ error ทันที 😭

ส่วนตัวผมแนะนำให้ระบุ newColumnNames เสมอครับ แม้ว่าชื่อจะไม่ซ้ำก็ตาม เพราะทำให้โค้ดอ่านง่ายและป้องกันปัญหาในอนาคต

ถ้าตารางซ้อนเป็น empty table (ไม่มีแถว) จะเกิดอะไรขึ้น?+

ถ้าตารางซ้อนไม่มีแถว (empty table) แถวนั้นจะหายไปจากผลลัพธ์เลยครับ 😭

ทำงานเหมือน Inner Join นั่นเอง ยกตัวอย่าง ถ้าใช้ Table.NestedJoin แบบ LeftOuter แล้วบางแถวไม่มีข้อมูล join ได้ (nested table ว่างเปล่า) พอเรา expand ออกมา… แถวนั้นจะหายไป

นี่เป็นพฤติกรรมที่ต้องระวังมากครับ ถ้าต้องการรักษาแถวเอาไว้ ต้องตรวจสอบก่อน expand ด้วย Table.RowCount หรือใช้ conditional logic เพื่อจัดการ case นี้

ต่างจาก Table.ExpandRecordColumn อย่างไร?+

คำถามนี้เจอบ่อยมากครับ เพราะชื่อคล้ายกันมาก 😅

**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 ง่ายกว่าครับ 😎

จะป้องกันตารางขยายใหญ่เกินไป (data explosion) ได้อย่างไร?+

นี่เป็นปัญหาใหญ่ที่เจอบ่อยมากครับ 😭 ตารางที่มี 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])

Resources & Related

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

ฟังก์ชันนี้Table.ExpandTableColumnTable functions
Table functions (6)
Table.AddJoinColumn

Table.AddJoinColumn เชื่อมต่อข้อมูลจากสองตารางตามคีย์ที่ตรงกัน โดยเก็บผลลัพธ์ในคอลัมน์ใหม่เป็นตารางแบบ nested แทนการขยายแนวนอน

Table.ExpandListColumn

Table.ExpandListColumn ใช้สำหรับขยายคอลัมน์ที่เก็บข้อมูลแบบ List ให้เป็นแถวแยก โดยแต่ละรายการใน List จะกลายเป็นแถวใหม่ ส่วนข้อมูลในคอลัมน์อื่นจะถูกทำซ้ำตามจำนวน

Table.Group

Table.Group จัดกลุ่มข้อมูลตามคอลัมน์ที่กำหนดและสรุปผลในแต่ละกลุ่มด้วย aggregation functions เช่น List.Sum, List.Count, List.Average คล้ายกับ GROUP BY ใน SQL แต่ทรงพลังกว่าเพราะสามารถจัดกลุ่มหลายคอลัมน์พร้อมกันและสร้างคอลัมน์สรุปผลหลายคอลัมน์ในคำสั่งเดียว รองรับ GroupKind.Local เพื่อเพิ่มประสิทธิภาพเมื่อข้อมูลเรียงลำดับแล้ว

Table.Join

Table.Join ใช้รวมตารางสองตารางโดยจับคู่ค่าในคอลัมน์กำหนด สนับสนุนทุกประเภท join (Inner, Left Outer, Right Outer, Full Outer, Anti, Semi) เหมือน SQL Join

Table.NestedJoin

Table.NestedJoin เชื่อมตารางสองตารางด้วยคีย์ที่กำหนด และสร้างคอลัมน์ใหม่ที่เก็บตารางย่อยของแถวที่จับคู่ได้ เหมาะกับงาน Merge ที่ต้องการเก็บรายละเอียดฝั่งขวาไว้เป็น nested table ก่อนจะ Expand หรือทำขั้นตอนต่อ

Tables.GetRelationships

Tables.GetRelationships ดึงข้อมูลความสัมพันธ์ (Relationships) ระหว่างตารางต่างๆ จาก Navigation Table เพื่อวิเคราะห์โครงสร้างข้อมูล

Accessing data functions (1)
AzureStorage.Blobs

AzureStorage.Blobs ดึงรายชื่อของ blobs (ไฟล์) ที่มีอยู่ในคอนเทนเนอร์ Azure Storage และสร้างตารางนำทางเพื่อเข้าถึงไฟล์เหล่านั้น

Comments

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