---
title: WINDOW – ดึงช่วงแถวภายในพาร์ทิชัน
url: https://www.thepexcel.com/functions/dax/filter/window-dax/
type: function-explainer
program: DAX
syntax: "WINDOW(<From>[, <FromType>], <To>[, <ToType>][, <Relation>][, <OrderBy>][, <Blanks>][, <PartitionBy>][, <MatchBy>][, <Reset>])"
date: 2025-12-13
updated: 2025-12-25
scores:
  popularity: 4
  difficulty: 6
  usefulness: 5
---

# WINDOW – ดึงช่วงแถวภายในพาร์ทิชัน

> WINDOW ดึงช่วงแถวภายในพาร์ทิชัน คืนค่าเป็นตาราง เหมาะกับการคำนวณแบบช่วง เช่น moving average, running

## คำอธิบาย

WINDOW ดึงช่วงแถวภายในพาร์ทิชัน คืนค่าเป็นตาราง เหมาะกับการคำนวณแบบช่วง เช่น moving average, running sum, หรือ lead/lag analysis

## Syntax

```excel
WINDOW(&lt;From&gt;[, &lt;FromType&gt;], &lt;To&gt;[, &lt;ToType&gt;][, &lt;Relation&gt;][, &lt;OrderBy&gt;][, &lt;Blanks&gt;][, &lt;PartitionBy&gt;][, &lt;MatchBy&gt;][, &lt;Reset&gt;])
```

**Variant**

```excel
WINDOW(&lt;From&gt;, &lt;To&gt;)
```

ระบุขอบเขตเริ่ม/จบของช่วงแถวแบบสั้น (ใช้ค่าตั้งต้นของชนิดการอ้างอิง/การเรียงตามบริบท)

**Variant**

```excel
WINDOW(&lt;From&gt;, &lt;FromType&gt;, &lt;To&gt;, &lt;ToType&gt;, &lt;Relation&gt;, &lt;OrderBy&gt;, &lt;Blanks&gt;, &lt;PartitionBy&gt;, &lt;MatchBy&gt;, &lt;Reset&gt;)
```

ระบุพารามิเตอร์ครบเพื่อคุมชนิดการอ้างอิง ลำดับ พาร์ทิชัน และการจับคู่

## Arguments

| Name | Required | Type | Default | Description |
| --- | --- | --- | --- | --- |
| From | Yes | integer |  | ตำแหน่งเริ่มของช่วง นิยมเป็นค่าลบ (แถวก่อนหน้า) เช่น -2 หมายถึง 2 แถวก่อนแถวปัจจุบัน |
| FromType | No | enumeration |  | ชนิดการตีความ From: REL (relative, ค่าตั้งต้น) หรือ ABS (absolute) - REL = offset จากแถวปัจจุบัน, ABS = ตำแหน่งแน่นอนจากจุดเริ่มพาร์ทิชัน |
| To | Yes | integer |  | ตำแหน่งสิ้นสุดของช่วง มักเป็น 0 (แถวปัจจุบัน) หรือค่าบวก (แถวข้างหน้า) |
| ToType | No | enumeration |  | ชนิดการตีความ To: REL หรือ ABS (ค่าตั้งต้น REL) |
| Relation | No | table |  | ตาราง/ความสัมพันธ์ที่จะดึงช่วงแถวมา ถ้าไม่ระบุจะใช้ relation ของ OrderBy/PartitionBy |
| OrderBy | No | expression |  | นิพจน์กำหนดลำดับการเรียงสำหรับการสร้างช่วงแถว เช่น ORDERBY('DimDate'[Date]) |
| Blanks | No | enumeration |  | วิธีจัดการค่าว่างในการเรียงลำดับ: SKIP (ข้ามค่าว่าง) หรือ KEEP (เก็บค่าว่าง) |
| PartitionBy | No | expression |  | นิพจน์กำหนดการแบ่งพาร์ทิชัน เช่น PARTITIONBY(Sales[CustomerID]) - ช่วงแถวจะสร้างแยกในแต่ละพาร์ทิชัน |
| MatchBy | No | expression |  | นิพจน์กำหนดการจับคู่แถว เมื่อหลายแถวมีค่าเดียวกันในลำดับ ช่วยกำหนดแถวไหนเป็นแถวปัจจุบัน |
| Reset | No | boolean |  | ใช้ในการคำนวณภาพ (visual calculations) เท่านั้น กำหนดว่าจะ reset การคำนวณที่ลำดับชั้นหรือไม่ |

## เคสการใช้งาน

### ดึงช่วงแถวรอบแถวปัจจุบัน

เช่น เอาแถวก่อนหน้าและถัดไปเพื่อทำการสรุปแบบช่วง

_เหมาะกับ:_ neighbor-window

### ทำการคำนวณแบบ rolling

เช่น สรุปยอดในช่วงแถวล่าสุดตามลำดับที่กำหนด

_เหมาะกับ:_ rolling-window

## ตัวอย่าง

### 1. ตัวอย่างที่ 1: Moving Average 3 วัน (ช่วงแถวสัมพัทธ์)

```excel
Moving Avg 3Day = 
AVERAGEX(
    WINDOW(
        -2, REL, 0, REL,
        ORDERBY(Sales[OrderDate])
    ),
    Sales[Amount]
)

-- หรือ ใช้ VAR ให้ชัด:
Moving Avg = 
VAR _window = WINDOW(
    -2, REL,           -- เอา 2 แถวก่อน
    0, REL,            -- ถึง แถวปัจจุบัน (รวม 3 แถว)
    ORDERBY(Sales[OrderDate])
)
RETURN AVERAGEX(_window, Sales[Amount])
```

**ผลลัพธ์:** `ได้ค่าเฉลี่ยของ 3 วัน (วันก่อนหน้า 2 วัน + วันปัจจุบัน)`

REL = relative position (offset) จาก current row, -2 หมายถึง 2 แถวก่อน, 0 หมายถึง แถวปัจจุบัน สำคัญคือต้องใช้ AVERAGEX (iterator) เพราะ WINDOW คืนตาราง ไม่ใช่ค่าเดียว

### 2. ตัวอย่างที่ 2: Running Sum (คะแนนรวมสะสม) ด้วยตำแหน่งสัมบูรณ์

```excel
Running Sum Year = 
VAR _window = WINDOW(
    1, ABS,                    -- เริ่มจาก แถวแรกของปี (position 1)
    0, REL,                    -- ถึง แถวปัจจุบัน
    ALLSELECTED(Sales),
    ORDERBY(Sales[MonthNumber]),
    PARTITIONBY(Sales[Year])
)
RETURN SUMX(_window, Sales[Amount])
```

**ผลลัพธ์:** `ได้ยอดรวมสะสมตั้งแต่จุดเริ่มต้นของแต่ละปีจนถึงเดือนปัจจุบัน`

ABS = absolute position (ตำแหน่งแน่นอน), 1 = แถวแรก (1-indexed), 0 REL = แถวปัจจุบัน, PARTITIONBY(Sales[Year]) = แบ่งพาร์ทิชันแยกต่อปี

### 3. ตัวอย่างที่ 3: ดึงแถวต่าง ๆ ภายในกลุ่มลูกค้า (Partition by Customer)

```excel
Customer Window Rows = 
VAR _window = WINDOW(
    -3, REL,                      -- 3 แถวก่อนหน้า
    1, REL,                       -- 1 แถวข้างหน้า
    ORDERBY(Sales[OrderDate]),
    PARTITIONBY(Sales[CustomerID])
)
RETURN CONCATENATEX(
    _window,
    FORMAT(Sales[OrderDate], "dd/mm") & ": " & Sales[Amount],
    " | "
)
```

**ผลลัพธ์:** `ได้ลำดับคำสั่งของลูกค้า 3 วันก่อน + วันปัจจุบัน + วันข้างหน้า ต่อวันปัจจุบัน`

PARTITIONBY ทำให้ช่วงแถวหยุดไม่ไปไกลกว่าพาร์ทิชัน มันจะ reset เมื่อ CustomerID เปลี่ยน

### 4. ตัวอย่างที่ 4: ดึงแถวเฉพาะจำนวนตามเงื่อนไข (KEEP blanks)

```excel
Count Recent Orders = 
VAR _window = WINDOW(
    -7, REL,                   -- ย้อนหลัง 7 วัน
    0, REL,                    -- ถึงวันปัจจุบัน
    ORDERBY(Sales[OrderDate]),
    KEEP                       -- Keep blanks ที่อาจเกิด
)
RETURN COUNTROWS(_window)
```

**ผลลัพธ์:** `ได้จำนวนคำสั่งในช่วง 7 วัน (ถ้า SKIP จะข้ามวันที่ไม่มีคำสั่ง)`

KEEP = เก็บค่าว่าง ใช้เมื่อวันบางวันอาจไม่มีข้อมูล, SKIP = ข้ามค่าว่างเพื่อดึง record ถัดไป

## หมายเหตุเพิ่มเติม

- ผมแนะนำให้เริ่มจาก REL (relative) ก่อนเพราะ intuitive กว่า ABS - ลองทำ -2 ถึง 0 เพื่อได้ 3 แถว (วานพึ่ง 2 + วันนี้)

- ส่วนตัวผมเอา WINDOW มาใช้มากสำหรับ moving average/rolling sum เพราะมันให้ control เต็มเหมี่ยมในการกำหนดช่วง ไม่เหมือน EARLIER ที่ค่อยลำบากอยู่บ้าง

- เมื่อใช้ WINDOW ใน visual calculation (Power BI matrix) อย่าลืม PARTITIONBY หรือกำหนด axis โดยชัดเจน ถ้าไม่ partition ถูก มันอาจข้ามหลายระดับลำดับชั้นไป

- ลองใช้ VAR เก็บผลลัพธ์ของ WINDOW ไว้ก่อน แล้วค่อย iterate - มันจะ debug ได้ง่ายกว่าเขียน AVERAGEX(WINDOW(...)) แบบ nested

- ระวัง KEEP vs SKIP ในการจัดการ blanks - ถ้าข้อมูลมีวันที่ว่าง SKIP อาจให้ผลลัพธ์ที่ไม่คาดหวังเพราะมันจะ skip row แต่ยังนับใน offset

## คำถามที่พบบ่อย

**Q: WINDOW คืนค่าเป็นตัวเลขหรือตาราง?**

WINDOW คืนค่าเป็นตาราง (ชุดแถว) ไม่ใช่ค่าเดียว จึงต้องนำไปสรุปต่อด้วย iterator เช่น SUMX, AVERAGEX, COUNTROWS, CONCATENATEX ถ้าต้อง scalar value นั่นคือส่วนหนึ่งของ DAX ที่สำคัญ - เข้าใจ row context vs filter context ผม

**Q: REL กับ ABS ต่างกันอย่างไร พอให้ตัวอย่างหน่อยไหม?**

REL (relative) = offset จากแถวปัจจุบัน, -2 หมายถึง 2 แถวก่อน, 1 หมายถึง 1 แถวข้างหน้า, 0 = แถวปัจจุบัน

ABS (absolute) = ตำแหน่งแน่นอนจากจุดเริ่มต้นของพาร์ทิชัน, 1 = แถวแรก, 2 = แถวที่สอง, -1 = แถวสุดท้าย

กรณี partition มี 10 แถวและอยู่ที่แถวที่ 5:
WINDOW(-2, REL, 0, REL) = แถว 3 ถึง 5
WINDOW(1, ABS, 0, REL) = แถว 1 ถึง 5 (position 1 ไปถึง current row)

**Q: PARTITIONBY ทำอะไร?**

PARTITIONBY แบ่งพาร์ทิชัน (group) ก่อนสร้างช่วงแถว ช่วงแถวจะไม่ข้ามพาร์ทิชัน เช่น PARTITIONBY(Sales[CustomerID]) ช่วงแถวจะเริ่มใหม่สำหรับลูกค้าแต่ละคน ไม่ผสมลูกค้าคนที่แล้วกับคนใหม่

**Q: ผมจะรู้ว่า window boundaries ถูกตัดเพราะลงท้ายพาร์ทิชันได้ไง?**

ที่จริง WINDOW จะตัด boundary โดยอัตโนมัติเมื่อชนพาร์ทิชัน มันจะส่งคืนตารางของแถวที่เหลือ ถ้าอยากรู้ตัวเลขจริงของแถวในช่วง ลองใช้ COUNTROWS() บนผลลัพธ์จาก WINDOW ดู

**Q: ทำไม OrderBy ต้องระบุตลอด ไม่ได้ข้ามไหม?**

OrderBy กำหนดลำดับการเรียง ซึ่งเป็นหลักในการสร้างช่วงแถว ถ้าข้าม WINDOW จะ error หรือได้ผลลัพธ์ที่คาดไม่ได้ ลำดับที่ชัดเจนมีความสำคัญเท่า partition ผมแนะนำให้ระบุเสมอ

## ฟังก์ชันที่เกี่ยวข้อง

- orderby
- partitionby
- matchby
- offset-dax
- [INDEX – ดึงแถวตามตำแหน่งภายในเพาร์ติชัน](https://www.thepexcel.com/functions/dax/filter/index-dax/)
- sumx
- countrows

## แหล่งข้อมูลเพิ่มเติม

- [DAX Guide: WINDOW](https://dax.guide/window/) _(guide)_
- [Microsoft Learn: WINDOW Function](https://learn.microsoft.com/en-us/dax/window-function-dax) _(official)_

---

_Source: [https://www.thepexcel.com/functions/dax/filter/window-dax/](https://www.thepexcel.com/functions/dax/filter/window-dax/)_
