---
title: การใช้ Power Query M Code จัดการข้อมูลที่อยู่ในตำแหน่งไม่แน่นอน
url: https://www.thepexcel.com/power-query-mcode-dynamic-position/
type: post
date: 2023-10-29
updated: 2025-12-22
author: Sira Ekabut
categories: [Power Query]
tags: [power query, Table.FindText, m code, Table.FirstN, List, Table.Group, List.FirstN, Table.RowCount, List.PositionOf, Table.SelectRows, List.Sum, Table.Skip, Record.FieldNames, Table.Transpose, Record.FieldValues, Table.AddColumn, Table.AddIndexColumn, Table.DemoteHeaders]
---

# การใช้ Power Query M Code จัดการข้อมูลที่อยู่ในตำแหน่งไม่แน่นอน

หลายๆ คนน่าจะได้ลองใช้ Power Query ผ่านเครื่องมือบน User Interface ปกติไปจนเป็นแล้ว และหลายคนก็จะเริ่มรู้แล้วว่าเครื่องมือ User Interface ปกตินั้นมันไม่สามารถตอบโจทย์ในงานบางอย่างได้ **เรียกได้ว่าเครื่องมือ Power Query ปกตินั้นสามารถตอบโจทย์งานทั่วไป 80% ได้แหละ แต่งานอีก 20% จะต้องมีการยุ่งกับ M Code ถึงจะสามารถทำได้สำเร็จ**

 

ซึ่งผมได้เคยมีการเขียนบทความเรื่อง [บันได 10 ขั้น เริ่มเรียนรู้ M Code ขุมพลังของ Power Query](https://www.thepexcel.com/study-steps-power-query-mcode/) ซึ่งเป็นแนวทางในการศึกษา M Code ว่ามีประเด็นไหนที่ควรจะต้องศึกษาบ้าง รวมถึงมีการเขียน [บทความรายละเอียดเรื่อง M Code โดยเริ่มจากพื้นฐาน](https://www.thepexcel.com/category/power-query/m-code/) ไปแล้วเช่นกัน

 

แต่ในบทความนี้ผมจะเน้นไปที่ M Code ที่เราจะสามารถนำมาใช้ในงานของเราได้จริงๆ ในกรณีที่พบได้บ่อย เช่น เราสามารถใช้ M Code ใช้แก้ปัญหาเมื่อข้อมูลอยู่ตำแหน่งไม่แน่นอนได้ ทุกคนจะได้เห็นภาพมากขึ้นว่าเราจะเรียนรู้ M Code ไปทำไมกัน??

 

## ปัญหาของ Remove Top Rows แบบปกติ

 

ปกติแล้ว ถ้าเรามีข้อมูลที่ต้องการอยู่ในแถวที่ไม่ใช่แถวแรกสุด เราก็ต้องทำการ Remove Top Rows ก่อน ซึ่งจะต้องระบุจำนวนแถวของข้อมูลด้วย เช่น ตามในรูปต้องเอาออก 3 แถว

 ![1](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-003-1024x491.png) 

**สมมติเราทำให้ MyTable เป็นตัวแปรที่เก็บตารางต้นฉบับก่อนจะตัดบรรทัดไว้ **โปรแกรมก็จะเรียกใช้ฟังก์ชัน Table.Skip ให้

 

```
Table.Skip(MyTable,3)
```

 

แต่วิธีนี้จะ Work ได้ก็ต่อเมื่อ “ข้อมูลที่เราต้องการต้องอยู่แถว 4 อย่างแน่นอน” จริงมั้ยครับ?

 

และจะเกิดอะไรขึ้นถ้าข้อมูลที่เราจะต้องเจอ “มันอาจจะอยู่ที่แถวอื่นก็ได้” แบบนี้เราก็ต้องใช้ M Code มาช่วยแล้วล่ะ

 

> หลักการคิดคือ เราจะต้องหาวิธีที่จะรู้ให้ได้ว่าหัวตารางอยู่ในบรรทัดที่เท่าไหร่?

 

การจะรู้ว่าหัวตารางอยู่บรรทัดที่เท่าไหร่ได้นั้น ก็ขึ้นอยู่กับตัวข้อมูลด้วย ว่าข้อมูลมาแบบไหน ซึ่งผมจะเริ่มจากรณีที่มันง่ายก่อน

 

## หัวตารางอยู่ในคอลัมน์ที่แน่นอน และเป็นคำที่แน่นอน

 

สมมติว่าเรารู้แน่ๆ ว่า หัวตารางเป็นคำว่าผลไม้ และอยู่ใน Column1 เสมอ

 

วิธีการหามีหลายวิธี

 

### วิธีที่ 1 : ใช้ Add Index Column และการ Filter

 

วิธีแรกเป็นวิธีที่ไม่ได้ใช้ M Code อะไรมากมายนอกจากการรวบ Step บางอันเข้าด้วยกัน แนวทางคือ เราใช้การ Add Index Column เริ่มจากเลข 1 เข้าไป

 ![2](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-019-1024x585.png) 

แล้ว Filter Column1 (ที่เรารู้แน่นอน) ให้เป็นคำว่าผลไม้

 ![3](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-018-1024x131.png) 

จากนั้น Drilldown เข้าไปที่ Index ของบรรทัดแรก (เผื่อมีผลไม้หลายบรรทัด) ก็จะรู้แล้วว่าคำว่าผลไม้อยู่บรรทัดที่เท่าไหร่เป็นครั้งแรก

 ![4](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-020.png) 

จากนั้นเอาตัวแปร FruitRow ไปเรียกใช้ใน Table.Skip แต่อย่าลืมลบไปอีก 1 แถว

 

สรุปแล้วเขียน MCode แบบนี้

 

```
let
    Source = ...,
    MyTable = ตารางต้นฉบับที่เตรียมไว้,
    MyTable = #"Replaced Value",
    AddIndex = Table.AddIndexColumn(MyTable, "Index", 1, 1, Int64.Type),
    FilterRows = Table.SelectRows(AddIndex, each ([Column1] = "ผลไม้")),
    FruitRow = FilterRows{0}[Index],
    Result = Table.Skip(MyTable,FruitRow-1)
in
    Result
```

 

ได้ผลลัพธ์แบบนี้

 ![5](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-021.png) 

### วิธีที่ 2 : ใช้ความรู้เรื่อง List มาช่วย

 

แบบนี้เราสามารถทำให้ข้อมูลใน Column1 เป็น List แล้วใช้ List.PositionOf เพื่อหาตำแหน่งของคำที่ต้องการได้ เช่น

 

ทำให้คอลัมน์แรกเป็น List ก่อนด้วยการคลิ๊กขวาที่คอลัมน์แรกแล้วกด Drill Down เพื่อให้อ้างอิงข้อมูลคอลัมน์ให้เป็น List

 

```
= MyTable[Column1]
```

 ![6](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-004.png) 

จากนั้นใช้ List.PositionOf ครอบเข้าไป ก็จะหาตำแหน่งของผลไม้ ออกมาเป็น index ที่ 3

 

```
= List.PositionOf(MyTable[Column1],"ผลไม้")
```

 

แล้วเราก็อาจเก็บค่านี้ไว้ในตัวแปร PositionFruit

 

แล้วเอาไปเรียกใช้ใน Table.Skip ได้เลย เช่น

 

```
= Table.Skip(MyTable,PositionFruit)
```

 

ก็จะได้ผลลัพธ์ที่ต้องการครับ สรุป M Code ทั้งหมดเป็นแบบนี้

 

```
let
    Source = ...,
    MyTable = ตารางต้นฉบับที่เตรียมไว้,
    PositionFruit = List.PositionOf(MyTable[Column1],"ผลไม้"),
    Result = Table.Skip(MyTable,PositionFruit)
in
    Result
```

 

## หัวตารางอยู่ในคอลัมน์ที่ไม่แน่นอน แต่เป็นคำที่แน่นอน

 

สมมติว่าคราวนี้ผมรู้ว่าหัวตารางจะต้องมีคำว่า “เกรด” แต่ไม่รู้ว่ามันจะอยู่ในคอลัมน์ไหน แถวไหนกันแน่ เราจะมีวิธีการหาได้ยังไงมาดูกันครับ

 

เราสามารถใช้ Table.FindText มาช่วยได้ เช่น

 

```
= Table.FindText(MyTable,"เกรด")
```

 

ผลลัพธ์จะได้แบบนี้ (ถ้ามีคำว่าเกรดอยู่หลาย Row มันก็จะออกมาหลายบรรทัดได้)

 ![7](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-008-1024x248.png) 

วิธีที่จะหาว่าคำว่าเกรดอยู่ในคอลัมน์ที่ชื่อว่าอะไรนั้นทำได้หลายวิธี เช่น

 

### วิธีที่1 : ใช้การหา item ใน List

 
- เอา Record แรกออกมาเลยใส่ {0} ต่อท้าย
- จากนั้นเราแปลง Record Value เป็น List ด้วย Record.FieldValues
- แล้วหาตำแหน่งของคำว่า เกรด ใน List ด้วย List.PositionOf

 

สรุปแล้วเขียนแบบนี้

 

```
= List.PositionOf(Record.FieldValues(Custom1),"เกรด")
```

 

จะได้ว่าอยู่ใน index ที่ 1 หรือ เป็น item ลำดับที่ 2 ซึ่งก็คือ Column2 นั่นเอง

 

หรือจะหาชื่อ Field แบบเป๊ะๆ เลยก็ได้ อาจใช้ Record.FieldNames มาช่วย ก็ได้

 

```
= Record.FieldNames(Custom1)
```

 ![8](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-012.png) 

ซึ่งเราเอาเลข Index จาก Custom2 มาใส่ เพื่อเอาชื่อคอลัมน์ออกมาก็ได้

 ![9](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-010.png) 

สรุปว่าเขียนแบบนี้

 

```
    Custom1 = Table.FindText(MyTable,"เกรด"){0},
    Custom2 = List.PositionOf(Record.FieldValues(Custom1),"เกรด"),
    Custom3 = Record.FieldNames(Custom1){Custom2}
```

 

### วิธีที่ 2 : Transpose ตารางแล้ว Filter หา

 

หรือเราจะใช้อีกวิธีนึงคือ Demote Header แล้ว Transpose ตารางให้ออกมาเป็นแบบนี้

 

```
= Table.Transpose(Table.DemoteHeaders( Table.FindText(MyTable,"เกรด")))
```

 ![10](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-011.png) 

แล้ว Filter หาคำว่าเกรดใน Column ขวา (เพื่อให้ได้เกรดแถวแรกที่เจอก่อนที่จะ Transpose)

 

แค่นี้ก็จะรู้ชื่อคอลัมน์ว่าเป็น Column2 นั่นเอง

 

สรุปแล้วเขียนแบบนี้

 

```
    Custom1 = Table.Transpose(Table.DemoteHeaders( Table.FindText(MyTable,"เกรด"))),
    FilterRow = Table.SelectRows(Custom1, each ([Column2] = "เกรด")),
    Column1 = FilterRow{0}[Column1]
```

 

พอได้ชื่อคอลัมน์ที่แน่นอนแบบนี้ เราค่อยเอาไปหาตามเคสแรกอีกทีก็จะจบแล้ว

 

## หัวตารางอยู่ในคอลัมน์ที่แน่นอน แต่เป็นคำที่ไม่แน่นอน

 

สมมติว่าเรารู้ว่าหัวตารางจะอยู่ใน Column1 แน่ๆ แต่ไม่รู้ว่าจะเป็นคำว่าอะไร ซึ่งเราจะต้องมี Logic เพิ่มเติม เช่น มันจะเป็น **คำแรกหลังจากข้อมูลเป็นค่า null ตั้งแต่ 2 ตัวขึ้นไป**

 

แบบนี้ก็สามารถใช้ MCode มาช่วยได้อยู่ แต่จะยากขึ้นกว่าเดิมเล็กน้อย

 

ในเคสนี้ผมจะใช้ Group By มาช่วย

 ![11](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-007-1024x622.png) 

แต่จะทำตรงๆ ไม่ได้เพราะอาจเกิดปัญหาที่มันดันรวบ null ทุกตัวเข้าด้วยกันไปเลยแบบนี้

 ![12](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-005.png) 

เราเลยจะมีการแก้ Parameter เล็กน้อยให้มีการ GroupKind แบบ Local เพื่อให้ Group ขึ้นอยู่กับการเรียงลำดับต่อเนื่องด้วย เช่น

 

```
= Table.Group(MyTable, {"Column1"}, {{"Count", each Table.RowCount(_), Int64.Type}},GroupKind.Local)
```

 ![13](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-006.png) 

จากนั้นเราจะทำ Count สะสมเพิ่มอีกคอลัมน์ เพื่อที่จะได้รู้ว่า null ตัวแรกที่ติดต่อกัน 2 ค่าขึ้นไป มันคือบรรทัดที่เท่าไหร่กันแน่??

 

โดยสร้าง Index Column เพื่อช่วยกำหนดลำดับในการสะสมค่า แล้วเขียน Custom Column ใหม่เพื่อสร้าง Count แบบสะสมด้วยสูตรนี้

 

```
List.Sum(List.FirstN(AddIndex[Count],[Index]))
```

 ![14](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-013.png) 

จากนั้น Filter เลือก Column1 ที่เป็น null และ Column2 >=2

 

```
= Table.SelectRows(AddAccumCount, each [Column1] = null and [Count] >= 2)
```

 ![15](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-015.png) 

แล้วเลือกเอาแถวแรกออกมา จากนั้นเลือกเอา AccumCount จะได้เลข 3 ออกมาแบบนี้

 ![16](https://www.thepexcel.com/wp-content/uploads/2023/10/mcode-apply-016.png) 

สรุปแล้วเขียนแบบนี้

 

```
let
    Source = ...,
    MyTable = ตารางต้นฉบับที่เตรียมไว้,
    GroupTable = Table.Group(MyTable, {"Column1"}, {{"Count", each Table.RowCount(_), Int64.Type}},GroupKind.Local),
    AddIndex = Table.AddIndexColumn(GroupTable, "Index", 1, 1, Int64.Type),
    AddAccumCount = Table.AddColumn(AddIndex, "AccumCount", each List.Sum(List.FirstN(AddIndex[Count],[Index]))),
    FilterRows = Table.SelectRows(AddAccumCount, each [Column1] = null and [Count] >= 2),
    PositionFruit = Table.FirstN(FilterRows,1){0}[AccumCount],
    Result = Table.Skip(MyTable,PositionFruit)
in
    Result
```

 

## นี่เป็นแค่แนวทางที่เป็นไปได้

 

วิธีแก้ปัญหาใน Power Query นั้นสามารถแก้ผัญหาได้หลายวิธี ดังนั้นยังมีความเป็นไปได้อื่นๆ อีกมากมายที่จะช่วยแก้ปัญหาให้เราได้ และถ้าเรารู้ M Code มากขึ้นก็จะช่วยให้มีวิธีแก้ปัญหามากขึ้นไปด้วยนะครับ ดังนั้นอย่าลืมลองสำรวจหาและเรียนรู้ฟังก์ชันที่คุณยังไม่รู้จัด้วยนะครับ เผื่อชีวิตจะสบายขึ้นเยอะ

---

_Source: [https://www.thepexcel.com/power-query-mcode-dynamic-position/](https://www.thepexcel.com/power-query-mcode-dynamic-position/)_
