RANKX เป็น iterator function ที่ iterate ทุกแถวใน table เพื่อประเมิน expression แล้วคืนอันดับของค่าใน current context เมื่อเทียบกับค่าทั้งหมด สามารถกำหนดทิศทางการเรียง (ASC/DESC) และวิธีจัดการอันดับเสมอ (Skip/Dense) ใช้บ่อยกับ ALL/ALLSELECTED เพื่อควบคุมชุดข้อมูลที่เปรียบเทียบ เหมาะสำหรับการจัดอันดับสินค้า ลูกค้า ภูมิภาค และ Top/Bottom analysis
=RANKX(<table>, <expression>[, <value>[, <order>[, <ties>]]])
=RANKX(<table>, <expression>[, <value>[, <order>[, <ties>]]])
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| table | table | Yes | ตารางที่ใช้ iterate เพื่อประเมิน expression – RANKX จะวนทุกแถวในตารางนี้ มักใช้ร่วมกับ ALL, ALLSELECTED, ALLEXCEPT เพื่อควบคุม filter context ให้เห็นรายการครบตามต้องการ | |
| expression | expression | Yes | นิพจน์หรือ measure ที่ใช้เป็นค่าในการจัดอันดับ – จะถูกประเมินในแต่ละ row ของ table ค่า BLANK ถือเป็น 0 (ถ้าเป็นตัวเลข) หรือ empty text (ถ้าเป็นข้อความ) | |
| value | any | Optional | ใช้ค่าจาก expression ใน current context | ค่าที่ต้องการหาอันดับแบบระบุชัด – ถ้าไม่ระบุจะใช้ค่าของ expression ใน current context แทน ใช้เมื่อต้องการหาอันดับของค่าที่กำหนดเองโดยไม่ขึ้นกับบริบทปัจจุบัน |
| order | number | Optional | 0 (DESC – มากไปน้อย) | ทิศทางการเรียงลำดับ: 0 หรือ FALSE = จากมากไปน้อย (DESC, ค่าสูงสุดได้อันดับ 1) / 1 หรือ TRUE = จากน้อยไปมาก (ASC, ค่าต่ำสุดได้อันดับ 1) |
| ties | enum | Optional | Skip | วิธีจัดการอันดับเสมอ: Skip = ข้ามลำดับเมื่อเสมอ (1, 2, 2, 2, 5) / Dense = ไม่ข้ามลำดับ (1, 2, 2, 2, 3) |
สร้าง calculated column หรือ measure เพื่อแสดงอันดับของสินค้า ลูกค้า หรือภูมิภาคตามยอดขาย ใช้ ALL เพื่อให้เห็นรายการทั้งหมด
จัดอันดับสินค้าภายในหมวดหมู่เดียวกัน หรือพนักงานภายในแผนกเดียวกัน ใช้ ALLEXCEPT เพื่อคงตัวกรองของกลุ่มไว้
หา Top 10 สินค้าขายดี หรือ Bottom 5 สาขาขายแย่ ใช้ร่วมกับ TOPN หรือ filter ตาม rank <= N
จัดอันดับนักเรียนตามคะแนนสอบแบบ Dense (ไม่ข้ามเลข) เหมาะกับระบบคะแนนที่ต้องการให้อันดับต่อเนื่องกัน
Product Rank = RANKX( ALL(Products[ProductKey]), [Total Sales] )Product Rank =
RANKX(
ALL(Products[ProductKey]),
[Total Sales]
)
อันดับ 1, 2, 3, ... ตามยอดขายจากมากไปน้อย
Product Dense Rank = RANKX( ALL(Products[ProductKey]), [Total Sales], , DESC, Dense )Product Dense Rank =
RANKX(
ALL(Products[ProductKey]),
[Total Sales],
,
DESC,
Dense
)
อันดับต่อเนื่อง 1, 2, 2, 3 แทนที่จะเป็น 1, 2, 2, 4
Category Rank = RANKX( ALLEXCEPT( Products, Products[Category] ), [Total Sales] )Category Rank =
RANKX(
ALLEXCEPT(
Products,
Products[Category]
),
[Total Sales]
)
อันดับของสินค้าภายในหมวดหมู่เดียวกัน (แต่ละหมวดมีอันดับ 1, 2, 3, ...)
Customer Low Rank = RANKX( ALL(Customers[CustomerKey]), [Total Sales], , ASC )Customer Low Rank =
RANKX(
ALL(Customers[CustomerKey]),
[Total Sales],
,
ASC
)
อันดับ 1 สำหรับลูกค้าที่ซื้อน้อยที่สุด
Sales Rank With Context = VAR CurrentSales = [Total Sales] VAR AllProducts = ALL(Products) VAR ProductRank = RANKX( AllProducts, CALCULATE([Total Sales]), Curre…Sales Rank With Context =
VAR CurrentSales = [Total Sales]
VAR AllProducts = ALL(Products)
VAR ProductRank =
RANKX(
AllProducts,
CALCULATE([Total Sales]),
CurrentSales,
DESC,
Dense
)
RETURN
ProductRank
อันดับที่คำนวณด้วยค่า sales ปัจจุบัน
Global Product Rank = RANKX( ALLSELECTED(Products[ProductKey]), [Total Sales] )Global Product Rank =
RANKX(
ALLSELECTED(Products[ProductKey]),
[Total Sales]
)
อันดับสินค้าตาม filter ที่ user เลือกใน slicer/filter
นี่เป็นปัญหาที่เจอบ่อยมากครับ 😅 สาเหตุคือ table argument ที่ส่งให้ RANKX ถูก filter context จำกัดมากเกินไป ทำให้แต่ละแถวเห็นแค่ตัวเองในตาราง จึงได้อันดับ 1 ทุกแถว
.
แก้ไขโดยใช้ ALL, ALLSELECTED หรือ ALLEXCEPT เพื่อให้ RANKX เห็นรายการครบตามต้องการ ส่วนตัวผมแนะนำให้ใช้ ALL เป็นจุดเริ่มต้นครับ
Skip (default) จะข้ามเลขอันดับเมื่อมีค่าเสมอ เช่น 1, 2, 2, 2, 5 (ข้าม 3 และ 4)
.
ส่วน Dense จะไม่ข้ามเลข เช่น 1, 2, 2, 2, 3 (ต่อเนื่องกัน)
.
ส่วนตัวผมจะเลือกตาม use case ครับ ถ้าเป็น leaderboard หรือการแข่งขัน ใช้ Skip จะดูเป็นธรรมชาติกว่า แต่ถ้าเป็นระบบคะแนนหรือเกรด Dense จะดูเข้าใจง่ายกว่า 💡
RANKX มีความ flexible มากกว่าครับ เพราะสามารถใช้ expression ที่ซับซ้อนได้ และควบคุม table context ด้วย ALL/ALLEXCEPT ได้ด้วย
.
ส่วนตัวผมใช้ RANKX เกือบทุกครั้ง เพราะ powerful กว่าและควบคุมได้ง่าย
.
แต่ระวังปัญหา Decimal data type นะครับ ถ้าใช้กับคอลัมน์ Decimal Number ควรใช้ ROUND function หรือเปลี่ยนเป็น Fixed Decimal Number ก่อน มิฉะนั้นอาจได้ผลลัพธ์แปลกๆ 😅
RANKX ใช้คำนวณอันดับของทุกรายการ ส่วน TOPN ใช้กรองเฉพาะ N รายการอันดับบนสุด
.
มักใช้ร่วมกันโดย RANKX คำนวณอันดับก่อน แล้ว filter ด้วยเงื่อนไข RANKX <= 10 หรือใช้ TOPN โดยตรงถ้าต้องการแค่รายการบนสุดเท่านั้น
.
Tip: ถ้าแค่ต้องการ Top 10 ใช้ TOPN เลยจะเร็วกว่าครับ แต่ถ้าต้องการแสดงอันดับด้วย ต้องใช้ RANKX 💡
BLANK values ถูกแปลงเป็น 0 (สำหรับตัวเลข) หรือ empty text (สำหรับข้อความ) ก่อนจัดอันดับ
.
ดังนั้น BLANK จะได้อันดับต่ำสุดใน DESC order หรืออันดับสูงสุดใน ASC order
.
ถ้าไม่อยากให้ BLANK ถูกจัดอันดับ ต้องใช้ FILTER เอาออกก่อนครับ หรือใช้ IF statement ในการแสดงผล 📝
นี่เป็นปัญหาเทคนิคที่น้อยคนรู้แต่สำคัญมากครับ 😅 Decimal Number ใช้ floating-point representation (IEEE 754) ซึ่งมีปัญหาความแม่นยำในการเปรียบเทียบค่าเท่ากัน (==)
.
ทำให้ RANKX อาจให้ผลลัพธ์ไม่คาดคิดกับค่าที่ดูเหมือนเท่ากัน เช่นอาจได้อันดับ 1, 2, 3 แทนที่จะเป็น 1, 1, 3
.
แก้ไขโดยใช้ Fixed Decimal Number data type หรือใช้ ROUND function ก่อนส่งเข้า RANKX ส่วนตัวผมแนะนำให้ใช้ ROUND เลยครับ ปลอดภัยกว่า 💡
RANKX เป็นฟังก์ชัน iterator function ที่ใช้จัดอันดับรายการในตารางตามค่าที่คำนวณจาก expression โดยจะ iterate แต่ละ row ใน table แล้วประเมิน expression สำหรับทุกแถว จากนั้นเปรียบเทียบค่าใน current context กับค่าทั้งหมดที่คำนวณได้ เพื่อคืนอันดับของแถว/รายการนั้น
.
สิ่งสำคัญที่ต้องเข้าใจ: RANKX ต้องการ table ที่กว้างพอเพื่อให้เห็นรายการทั้งหมดสำหรับเปรียบเทียบ มักใช้ร่วมกับ ALL, ALLSELECTED หรือ ALLEXCEPT มิฉะนั้น RANKX อาจเห็นแค่รายการในบริบทปัจจุบันและให้อันดับ 1 เกือบทุกแถว 😅
.
Iterator Pattern ใน RANKX: RANKX ทำงานใน row context โดย iterate ทุกแถวใน table argument และประเมิน expression ที่แต่ละแถว จึงสามารถใช้คอลัมน์ได้โดยตรง (เช่น Sales[Amount]) หรือ measure ที่มี context transition ผลลัพธ์คือชุดค่าทั้งหมดที่นำมาจัดอันดับ
.
การจัดการอันดับเสมอ (Ties): RANKX รองรับ 2 วิธีจัดการอันดับเสมอครับ
.
Skip (default) จะข้ามลำดับเมื่อมีอันดับเสมอ เช่น 1, 2, 2, 2, 5 ส่วน Dense จะไม่ข้ามลำดับ เช่น 1, 2, 2, 2, 3
.
⚠️ ข้อควรระวัง: RANKX อาจให้ผลลัพธ์ไม่คาดคิดกับ Decimal Number data type เนื่องจากปัญหาความแม่นยำของ floating-point (IEEE 754) แนะนำให้ใช้ Fixed Decimal Number แทน หรือใช้ ROUND function ก่อนคำนวณอันดับครับ 💡