ข้ามไปยังเนื้อหาหลัก

SQL RANK(): จัดลำดับแถวด้วยตัวอย่างใช้งาน

เรียนรู้การใช้ฟังก์ชัน SQL RANK() เพื่อกำหนดอันดับให้แถว จัดการกรณีเสมอ และเปรียบเทียบกับ DENSE_RANK() และ ROW_NUMBER()
อัปเดตแล้ว 4 พ.ค. 2569  · 6 นาที อ่าน

เมื่อทำงานกับ SQL การจัดเรียงข้อมูลทำได้ไม่ยากเพราะสามารถใช้ ORDER BY เพื่อเรียงแถวได้อย่างง่ายดาย อย่างไรก็ตาม การเรียงผลลัพธ์เพียงอย่างเดียวไม่ได้บอกตำแหน่งของแต่ละแถวภายในลำดับนั้น ซึ่งตรงนี้เองที่การจัดอันดับช่วยได้ แทนที่จะดูข้อมูลที่ถูกเรียงเฉย ๆ อาจต้องการกำหนดตำแหน่งอย่างที่ 1 ที่ 2 หรือที่ 3 ให้แต่ละแถวตามเกณฑ์ที่กำหนด

ฟังก์ชัน RANK() แก้ปัญหานี้โดยกำหนดลำดับเชิงตัวเลขให้แต่ละแถวตามลำดับที่กำหนดไว้ RANK() เป็นส่วนหนึ่งของฟังก์ชันหน้าต่าง (window functions) ของ SQL ที่ช่วยให้คำนวณผ่านชุดของแถวพร้อมทั้งยังคืนผลลัพธ์เป็นรายแถวได้

ในบทแนะนำนี้ ฉจะแสดงไวยากรณ์ของ RANK() ตัวอย่างการใช้งานจริง อธิบายวิธีจัดการกรณีคะแนนเท่ากัน และเปรียบเทียบกับฟังก์ชันที่คล้ายกันอย่าง DENSE_RANK() และ ROW_NUMBER()

หากเป็นมือใหม่ใน SQL เริ่มจากคอร์ส Introduction to SQL หรือคอร์ส Intermediate SQL หากมีประสบการณ์มาบ้างแล้ว

ฟังก์ชัน SQL RANK() คืออะไร?

ฟังก์ชัน SQL RANK() เป็น window function ที่กำหนดอันดับให้แต่ละแถวตามลำดับที่ระบุ การจัดอันดับถูกกำหนดโดย ORDER BY ภายในฟังก์ชันหน้าต่างโดยสมบูรณ์ ดังนั้นจึงให้ตำแหน่ง 1, 2, 3 เป็นต้น แก่แต่ละแถวตามเงื่อนไข ORDER BY

ควรสังเกตว่าเมื่อใช้ RANK():

  • แถวที่มีค่าเท่ากัน (เสมอกัน) จะได้รับอันดับเดียวกัน
  • เมื่อเกิดการเสมอ จะมีช่องว่างในลำดับอันดับ เช่น หากมีสองแถวอยู่อันดับ 2 อันดับถัดไปจะเป็น 4 ไม่ใช่ 3

ไวยากรณ์ของ SQL RANK()

ไวยากรณ์พื้นฐานของฟังก์ชัน RANK() คือ:

RANK() OVER (ORDER BY column)

โดย:

  • OVER: กำหนดหน้าต่าง (ชุดของแถว) ที่ฟังก์ชันจะทำงาน

  • ORDER BY: กำหนดวิธีการจัดอันดับ เช่น จากมากไปน้อย

  • PARTITION BY (ไม่บังคับ): แบ่งข้อมูลออกเป็นกลุ่ม ๆ และจัดอันดับแยกกันในแต่ละกลุ่ม

ด้านล่างเป็นไวยากรณ์ของฟังก์ชัน RANK() ที่ใช้ร่วมกับ PARTITION BY:

RANK() OVER (PARTITION BY column1 ORDER BY column2)

ฟังก์ชัน SQL RANK() รองรับอย่างกว้างขวางในฐานข้อมูลหลัก ๆ ได้แก่ PostgreSQL, MySQL (8.0+), Microsoft SQL Server และ Oracle Database ไวยากรณ์ส่วนใหญ่สอดคล้องกันระหว่างระบบเหล่านี้ เนื่องจากเป็นส่วนหนึ่งของมาตรฐาน ANSI SQL

ตัวอย่างพื้นฐานของ SQL RANK()

เมื่อเข้าใจไวยากรณ์ของ RANK() แล้ว มาดูตัวอย่างง่าย ๆ ของการทำงานกัน

สมมติว่ามีตาราง employees ที่เก็บข้อมูลเงินเดือนของแต่ละพนักงาน

ตารางพนักงาน

สามารถใช้คิวรีด้านล่างเพื่อจัดอันดับพนักงานตามเงินเดือนได้

-- Rank employees by salary
SELECT 
    name,
    salary,
    RANK() OVER (ORDER BY salary DESC) AS rank_position
FROM employees;

ในคิวรีข้างต้น แถวถูกเรียงตามเงินเดือนจากมากไปน้อย ดังนั้นเงินเดือนสูงสุดจะได้อันดับ 1 เมื่อสองแถวมีเงินเดือนเท่ากัน ทั้งคู่จะได้รับอันดับเดียวกัน

การใช้ฟังก์ชัน RANK() ใน SQL

จะสังเกตได้ว่าหากสองแถวมีค่าเท่ากัน จะได้รับอันดับเดียวกัน

จากนั้นอันดับถัดไปจะถูกข้าม SQL จะนับกรณีเสมอโดยข้ามค่าอันดับถัดไป

ขอแนะนำคอร์ส Introduction to SQL Server เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการจัดกลุ่มและการรวมข้อมูล

SQL RANK() ร่วมกับ PARTITION BY

ดังที่ได้เรียนรู้ไปแล้ว PARTITION BY ทำให้สามารถจัดอันดับภายในกลุ่ม แทนที่จะจัดอันดับทั่วทั้งชุดข้อมูล

ในตัวอย่างด้านล่าง พนักงานถูกจัดกลุ่มตาม department และการจัดอันดับจะเริ่มใหม่ภายในแต่ละแผนก ดังนั้นแต่ละกลุ่มจะมีลำดับอันดับเป็นของตนเอง

-- Rank employees within each department
SELECT 
    name,
    department,
    salary,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees;

การใช้ SQL RANK() กับ PARTITION BY

จากผลลัพธ์ด้านบนจะเห็นว่าใน “Sales” ทั้ง Emily Johnson และ Michael Brown มีอันดับ 1 ร่วมกัน ขณะที่ใน “HR” William Miller และ Olivia Wilson ก็มีอันดับ 1 ร่วมกันเช่นกัน

SQL RANK() vs. DENSE_RANK() vs. ROW_NUMBER()

เมื่อต้องจัดอันดับข้อมูลใน SQL สามารถเลือกใช้ RANK(), DENSE_RANK() หรือ ROW_NUMBER() ฟังก์ชันเหล่านี้ดูคล้ายกันแต่มีพฤติกรรมดังนี้:

  • RANK(): กรณีเสมอจะใช้อันดับเดียวกัน ดังนั้นจะเกิดช่องว่างหลังการเสมอ

  • DENSE_RANK(): กรณีเสมอใช้อันดับเดียวกัน และไม่มีช่องว่างในลำดับอันดับ

  • ROW_NUMBER(): ทุกแถวจะได้หมายเลขไม่ซ้ำกันเสมอ แม้ว่าค่าจะเท่ากัน

เพื่อให้เข้าใจความแตกต่างเหล่านี้มากขึ้น มาลองเปรียบเทียบแบบเคียงข้างกันด้วยคิวรีด้านล่าง:

-- Compare RANK() vs DENSE_RANK() vs ROW_NUMBER()
SELECT 
    name,
    salary,

    RANK() OVER (ORDER BY salary DESC) AS rank_val,          -- allows gaps after ties

    DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank1,  -- no gaps, consecutive ranks

    ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num      -- always unique sequence

FROM employees;

SQL RANK() เทียบกับ DENSE_RANK() และ ROW_NUMBER()

จากผลลัพธ์ข้างต้น อาจเลือกได้ว่า:

  • ใช้ RANK() เมื่อตำแหน่งมีความสำคัญ และยอมรับการมีช่องว่างได้

  • ใช้ DENSE_RANK() เมื่ออยากได้ลำดับที่ต่อเนื่องไม่ขาดช่วง

  • ใช้ ROW_NUMBER() เมื่อทุกแต้ต้องมีหมายเลขเฉพาะ เช่น การแบ่งหน้า (pagination) ของข้อมูล

ควรใช้ SQL RANK() เมื่อใด

ฟังก์ชัน SQL RANK() มีประโยชน์มากเมื่ออยากจัดเรียงข้อมูลพร้อมจัดการกรณีเสมออย่างเป็นธรรมชาติ นอกจากนี้ยังสำคัญสำหรับกรณีใช้งานต่อไปนี้:

  • ตารางจัดอันดับ (Leaderboards): เมื่อต้องการจัดอันดับผู้เล่นหรือผู้ใช้งานตามคะแนน โดยอนุญาตให้มีการเสมอเมื่อผลงานเท่ากัน
  • การจัดอันดับผลงานขาย: หากต้องการระบุพนักงานหรือภูมิภาคที่ทำผลงานยอดเยี่ยมตามรายได้ แม้ว่าผลลัพธ์จะเท่ากัน
  • การหา Top-N: มีประโยชน์สำหรับคิวรีอย่าง “เงินเดือนสูงสุด 3 อันดับแรก” โดยเฉพาะเมื่อควรรวมกรณีเสมอด้วย

ข้อผิดพลาดที่พบบ่อยกับ SQL RANK()

นี่คือข้อผิดพลาดที่เคยพบเมื่อใช้ฟังก์ชัน SQL RANK() และวิธีหลีกเลี่ยง:

  • ลืมใส่ ORDER BY: หากไม่มี ORDER BY การจัดอันดับจะไม่มีตรรกะที่ชัดเจนและอาจให้ผลลัพธ์ที่ไม่คาดคิด

  • เข้าใจพฤติกรรมกรณีเสมอผิด: สำหรับผู้เริ่มต้นอาจคาดหวัง 1, 2, 2, 3 แต่ RANK() จะมีช่องว่าง (1, 2, 2, 4) ในอันดับ

  • ใช้ RANK() แทน ROW_NUMBER() ที่จำเป็น: หากต้องการหมายเลขลำดับที่ไม่ซ้ำกัน ROW_NUMBER() จะเหมาะสมกว่า

  • ไม่ใช้ PARTITION BY เมื่อควรใช้: หากไม่แบ่งพาร์ทิชัน การจัดอันดับจะถูกนำไปใช้ในภาพรวมทั้งชุดข้อมูล แทนที่จะเป็นภายในแต่ละกลุ่ม

แนวทางปฏิบัติที่ดีในการใช้ SQL RANK()

เพื่อให้คิวรีสะอาดและได้ผลลัพธ์ตามคาด แนะนำให้ปฏิบัติตามแนวทางต่อไปนี้เมื่อใช้ฟังก์ชัน SQL RANK():

  • กำหนดการเรียงอย่างชัดเจนเสมอ: ระบุ ORDER BY ให้ชัด เช่น DESC เพื่อเลี่ยงการจัดอันดับที่คลุมเครือ

  • เลือกฟังก์ชันจัดอันดับให้ถูกต้อง: ใช้ RANK(), DENSE_RANK() หรือ ROW_NUMBER() ตามวิธีที่ต้องการจัดการกรณีเสมอ

  • ทดสอบกรณีเสมอ: ก่อนขึ้นโปรดักชัน ให้ตรวจสอบว่าข้อมูลทำงานอย่างไรเมื่อมีค่าที่ซ้ำกัน

  • ใช้ร่วมกับการกรองผลลัพธ์: เนื่องจากไม่สามารถใช้ RANK() ใน WHERE ได้โดยตรง จึงต้องครอบคิวรีจัดอันดับไว้ใน Subquery หรือ CTE เมื่ออยากกรอง “Top N”

สรุป

RANK() เป็นเครื่องมือที่มีประโยชน์สำหรับการเปรียบเทียบแบบมีลำดับใน SQL โดยเฉพาะเมื่อจำเป็นต้องสะท้อนสถานการณ์จริงอย่างค่าที่เท่ากัน การเข้าใจวิธีจัดการกรณีเสมอ และเหตุผลที่อันดับอาจซ้ำและข้ามตัวเลขได้ เป็นสิ่งสำคัญต่อการวิเคราะห์ที่แม่นยำ เมื่อเชี่ยวชาญพฤติกรรมนี้แล้ว จะรู้ว่าเมื่อใดควรเลือกใช้ควบคู่กับทางเลือกอย่าง DENSE_RANK() และ ROW_NUMBER() ตามกรณีใช้งานที่เหมาะสม

เมื่อเรียนรู้วิธีจัดอันดับข้อมูลใน SQL แล้ว แนะนำให้ดู เส้นทางอาชีพ Associate Data Analyst in SQL หากสนใจพัฒนาสู่การเป็นนักวิเคราะห์ข้อมูลมืออาชีพเพื่อเรียนรู้ทักษะที่จำเป็น และคอร์ส Reporting in SQL ก็เหมาะสำหรับการเรียนรู้การสร้างแดชบอร์ดระดับมืออาชีพด้วย SQL

SQL RANK() คำถามที่พบบ่อย

RANK() แตกต่างจาก ORDER BY อย่างไร?

ORDER BY เพียงจัดเรียงแถว ขณะที่ RANK() จะกำหนดตำแหน่งเชิงตัวเลขให้แต่ละแถวหลังการจัดเรียง

เหตุใดผลลัพธ์ของ RANK() จึงมีช่องว่าง?

การเกิดช่องว่างในผลลัพธ์ของ RANK() มาจากที่หลายแถวมีอันดับเดียวกันเมื่อมีการเสมอ ทำให้อันดับถัดไปถูกเลื่อนไปข้างหน้า

ความแตกต่างระหว่าง RANK() กับ DENSE_RANK() คืออะไร?

RANK() สร้างช่องว่างหลังกรณีเสมอ ขณะที่ DENSE_RANK() กำหนดอันดับต่อเนื่องโดยไม่มีช่องว่าง

ความแตกต่างระหว่าง RANK() กับ ROW_NUMBER() คืออะไร?

RANK() อนุญาตให้เสมอกัน แต่ ROW_NUMBER() จะกำหนดหมายเลขไม่ซ้ำให้ทุกแถวโดยไม่คำนึงถึงค่าที่ซ้ำ

RANK() รองรับในฐานข้อมูลทั้งหมดหรือไม่?

ฐานข้อมูลสมัยใหม่ส่วนใหญ่รองรับ RANK() รวมถึง PostgreSQL, MySQL (8.0+), Microsoft SQL Server และ Oracle Database

หัวข้อ

เรียนรู้ SQL กับ DataCamp

Courses

Data Manipulation in SQL

4 ชม.
319.8K
Master the complex SQL queries necessary to answer a wide variety of data science questions and prepare robust data sets for analysis in PostgreSQL.
ดูรายละเอียดRight Arrow
เริ่มหลักสูตร
ดูเพิ่มเติมRight Arrow