ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน
กำหนดหมายเลขแถวที่แน่นอนภายในแต่ละพาร์ทิชัน
ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
สิ่งที่ ROW_NUMBER รับประกัน
ROW_NUMBER() กำหนดจำนวนเต็มที่ไม่ซ้ำและไม่มีช่องว่างให้แต่ละแถวภายในพาร์ทิชัน โดยเริ่มที่ 1 และเป็นไปตาม ORDER BY ของหน้าต่าง จะไม่มีแถวสองแถวใดใช้หมายเลขเดียวกัน แม้ค่าที่ใช้จัดลำดับจะเหมือนกัน
ความไม่ซ้ำกันนี้เป็นเหตุผลที่ผู้สัมภาษณ์มักเลือกใช้ฟังก์ชันนี้เพื่อแก้โจทย์ "เลือกหนึ่งแถวต่อกลุ่ม" และโจทย์การขจัดข้อมูลซ้ำ ส่วนฟังก์ชันจัดอันดับอื่น ๆ (RANK, DENSE_RANK) ไม่ได้รับประกันความไม่ซ้ำกันเมื่อค่ากัน
คิวรี ROW_NUMBER ขั้นพื้นฐาน
รูปแบบที่ง่ายที่สุดจะกำหนดหมายเลขให้ชุดผลลัพธ์ทั้งหมดตามลำดับที่เลือก ROW_NUMBER จำเป็นต้องมี ORDER BY ภายใน OVER เสมอ หากไม่มี การกำหนดหมายเลขจะไม่แน่นอน และระบบฐานข้อมูลส่วนใหญ่จะปฏิเสธหรือแสดงคำเตือน
ในที่นี้ หากเรียงตามวันที่จ้างจากใหม่ไปเก่า พนักงานที่เข้าทำงานล่าสุดจะเป็นแถวที่ 1
SELECT
name,
hire_date,
ROW_NUMBER() OVER (ORDER BY hire_date DESC) AS rn
FROM employees;การกำหนดหมายเลขภายในพาร์ทิชัน
เพิ่ม PARTITION BY เพื่อกำหนดหมายเลขแถวแยกกันภายในแต่ละกลุ่ม ตัวนับจะเริ่มที่ 1 ใหม่เมื่อพบค่าพาร์ทิชันใหม่แต่ละค่า
ในตัวอย่างนี้ แต่ละแผนกจะมีลำดับ 1, 2, 3 ของตัวเอง โดยเรียงตามเงินเดือน ผู้มีรายได้สูงสุดในแต่ละแผนกจะได้หมายเลข 1 ซึ่งเป็นจุดเริ่มต้นของรูปแบบโจทย์เลือก N อันดับแรกต่อกลุ่ม
SELECT
department,
name,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS dept_rn
FROM employees;ROW_NUMBER และค่าที่เท่ากัน: ไม่มีอันดับเสมอกัน
ประเด็นสำคัญในการสัมภาษณ์คือ เมื่อสองแถวมีค่าที่ใช้จัดลำดับเท่ากัน ROW_NUMBER ก็ยังคงกำหนดหมายเลขที่แตกต่างกันให้ทั้งสองแถว หมายเลขใดจะต่ำกว่านั้น ไม่แน่นอน เว้นแต่จะเพิ่มคอลัมน์สำหรับตัดสินกรณีเสมอ
RANKจะกำหนดอันดับเดียวกันให้แถวที่มีค่าเท่ากันROW_NUMBERจะเลือกลำดับระหว่างแถวเหล่านั้นโดยไม่แน่นอน
เพื่อให้ได้ผลลัพธ์ที่ทำซ้ำแล้วเหมือนเดิม ควรเพิ่มตัวตัดสินกรณีเสมอที่ไม่ซ้ำกันลงใน ORDER BY เสมอ
SELECT
name,
salary,
ROW_NUMBER() OVER (
ORDER BY salary DESC, employee_id -- employee_id breaks ties deterministically
) AS rn
FROM employees;กฎตัวตัดสินกรณีเสมอที่แน่นอน
หาก ORDER BY ของคุณไม่ใช่การจัดลำดับที่ชัดเจน กล่าวคือไม่มีการรวมคอลัมน์ใดที่มีค่าไม่ซ้ำกัน การกำหนดหมายเลขแถวอาจเปลี่ยนไปในแต่ละครั้งที่เรียกใช้ แม้จะเป็นข้อมูลชุดเดียวกันก็ตาม ผู้สัมภาษณ์มักใส่จุดหลอกนี้ในโจทย์การแบ่งหน้าและโจทย์ "ระเบียนล่าสุด"
หลักทั่วไปคือ เพิ่มคีย์หลักหรือคอลัมน์อื่นที่มีค่าไม่ซ้ำกัน เป็นคีย์จัดเรียงสุดท้ายทุกครั้งที่ผลลัพธ์ต้องคงที่
-- Unstable: many rows can share the same created_at
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC)
-- Stable: id guarantees a single deterministic winner
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC, id DESC)ตัวอย่างการทำงาน: คำสั่งซื้อล่าสุดของลูกค้าแต่ละราย
คำถามยอดนิยมคือ: "แสดงคำสั่งซื้อล่าสุดของลูกค้าแต่ละราย" กำหนดหมายเลขคำสั่งซื้อของลูกค้าแต่ละรายตามวันที่จากใหม่ไปเก่า จากนั้นเก็บเฉพาะ rn = 1 ในคิวรีชั้นนอก
เนื่องจาก ROW_NUMBER รับประกันว่าจะมีแถวที่มีหมายเลข 1 เพียงหนึ่งแถวต่อพาร์ทิชัน จึงได้แถวของลูกค้าแต่ละรายพอดีหนึ่งแถว ไม่มีข้อมูลซ้ำแม้ว่าคำสั่งซื้อสองรายการจะมีการประทับเวลาเดียวกัน เพราะตัวตัดสินกรณีเสมอจะแก้ปัญหานี้
SELECT customer_id, order_id, order_date, amount
FROM (
SELECT
customer_id, order_id, order_date, amount,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC, order_id DESC
) AS rn
FROM orders
) t
WHERE rn = 1;ตัวอย่างการทำงาน: การขจัดแถวซ้ำ
ROW_NUMBER เป็นเครื่องมือที่ตรงไปตรงมาที่สุดสำหรับการขจัดข้อมูลซ้ำ ให้แบ่งพาร์ทิชันตามคอลัมน์ที่ใช้ระบุว่าเป็นข้อมูลซ้ำ เรียงตามเกณฑ์การเลือก จากนั้นเก็บเฉพาะ rn = 1
ในที่นี้ เราถือว่าแถวที่มีอีเมลเดียวกันเป็นข้อมูลซ้ำ และเก็บแถวที่สร้างขึ้นก่อนสุด ทุกแถวที่มี rn > 1 เป็นข้อมูลซ้ำที่สามารถลบหรือไม่สนใจได้
SELECT id, email, created_at
FROM (
SELECT
id, email, created_at,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY created_at ASC, id ASC
) AS rn
FROM users
) t
WHERE rn = 1;ROW_NUMBER สำหรับการแบ่งหน้า
ก่อนที่ OFFSET/FETCH จะใช้งานได้ทั่วไป ROW_NUMBER ถูกใช้ขับเคลื่อนการแบ่งหน้า และยังคงใช้เช่นนั้นใน SQL Server และงาน ETL จำนวนมาก ให้กำหนดหมายเลขแถวตามลำดับที่คงที่ จากนั้นกรองช่วงหมายเลขในคิวรีชั้นนอก
ข้อควรระวังในการสัมภาษณ์คือ การแบ่งหน้าจะถูกต้องก็ต่อเมื่อลำดับมีความแน่นอน มิฉะนั้นแถวเดียวกันอาจปรากฏอยู่ในสองหน้า หรือถูกข้ามไปทั้งหมด
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY created_at, id) AS rn
FROM articles
) t
WHERE rn BETWEEN 21 AND 40; -- page 2, 20 per pageการกำหนดลำดับเพื่อจัดข้อมูลใหม่
บางครั้งคุณอาจต้องการเพียงดัชนีเรียงต่อเนื่อง เช่น กำหนดหมายเลขแถวใหม่หลังการเรียงลำดับ สร้างป้ายกำกับตั้งแต่ 1 ถึง N หรือจับคู่แถวกับลำดับที่สร้างขึ้น การใช้ ROW_NUMBER ตามลำดับที่ต้องการจะสร้างลำดับต่อเนื่องที่ไม่มีช่องว่าง
วิธีนี้ยังใช้กำหนดตำแหน่งที่คงที่ให้ชุดข้อมูลที่ไม่มีลำดับแน่นอน เพื่อเชื่อมข้อมูลในภายหลังได้อีกด้วย
SELECT
ROW_NUMBER() OVER (ORDER BY score DESC, player_id) AS leaderboard_position,
player_id,
score
FROM scores;ROW_NUMBER เทียบกับ COUNT สำหรับ 'แถวลำดับที่ n'
เมื่อถูกถามถึง "คำสั่งซื้อที่ใหม่เป็นอันดับ 3" หรือ "แถวลำดับที่ 2" ให้เลือกใช้ ROW_NUMBER แล้วกรองตามค่าที่ตรงกันในคิวรีชั้นนอก เนื่องจากหมายเลขไม่ซ้ำกัน rn = 3 จึงคืนค่าได้เพียงหนึ่งแถว
เปรียบเทียบกับ RANK: หากต้องการค่าที่แตกต่างกันเป็นอันดับ 2 เช่น เงินเดือนสูงเป็นอันดับสองโดยนับค่าที่เท่ากันเป็นค่าเดียว ROW_NUMBER ไม่ใช่เครื่องมือที่เหมาะสม กรณีนี้ต้องใช้ DENSE_RANK ซึ่งจะกล่าวถึงในบทเรียนถัดไป
SELECT order_id, order_date
FROM (
SELECT order_id, order_date,
ROW_NUMBER() OVER (ORDER BY order_date DESC, order_id DESC) AS rn
FROM orders
) t
WHERE rn = 3; -- exactly the 3rd most recent orderทบทวนจุดที่มักพลาด
จดจำประเด็นเหล่านี้ให้แม่นยำภายใต้ความกดดันในการสัมภาษณ์:
ROW_NUMBERจะไม่ซ้ำกันและไม่มีช่องว่างภายในพาร์ทิชันเสมอ- จำเป็นต้องมี
ORDER BYในOVERหากไม่มีตัวตัดสินกรณีเสมอที่ไม่ซ้ำกัน ผลลัพธ์เมื่อค่ากันจะไม่แน่นอน - ไม่สามารถกรองใน
WHEREได้ ต้องห่อไว้ในซับคิวรี/CTE - ใช้สำหรับการเลือกหนึ่งแถวต่อกลุ่ม การขจัดข้อมูลซ้ำ และการแบ่งหน้า ส่วนกรณีที่ค่ากันต้องใช้หมายเลขเดียวกัน ให้ใช้
DENSE_RANK
ตรวจสอบความเข้าใจ
ROW_NUMBER จัดการกับแถวที่มีค่าใน ORDER BY เท่ากันอย่างไร
ทบทวน: การกำหนดลำดับที่แน่นอน
ROW_NUMBER คือเครื่องมือสำหรับกำหนดหมายเลขที่ไม่ซ้ำและไม่มีช่องว่างภายในพาร์ทิชัน คุณได้เรียนรู้ที่จะ:
- กำหนดหมายเลขให้ชุดข้อมูลทั้งหมดและกลุ่มที่แบ่งตามพาร์ทิชัน
- เพิ่มตัวตัดสินกรณีเสมอที่ไม่ซ้ำกัน เพื่อให้ได้ผลลัพธ์ที่แน่นอนและทำซ้ำได้เหมือนเดิม
- แก้โจทย์แถวล่าสุดต่อคีย์ การขจัดข้อมูลซ้ำ การแบ่งหน้า และการเลือกแถวลำดับที่ N ด้วยการกรอง
rnในคิวรีชั้นนอก
ถัดไป คุณจะเห็นว่า RANK และ DENSE_RANK ตั้งใจให้ค่าที่เท่ากันใช้หมายเลขเดียวกันอย่างไร และการเว้นช่องว่างของทั้งสองฟังก์ชันแตกต่างกันอย่างไร
คำถามที่พบบ่อย
บทเรียน “ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน”
กำหนดหมายเลขแถวที่แน่นอนภายในแต่ละพาร์ทิชัน คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Coding Interview Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Coding Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Coding Interview Prep นี้ได้ไหม
ได้ บทเรียน Coding Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- OVER, PARTITION BY และ ORDER BY
- ROW_NUMBER สำหรับลำดับที่ไม่ซ้ำกัน
- RANK เทียบกับ DENSE_RANK เมื่อค่าซ้ำกัน
- กรองจากผลลัพธ์ของฟังก์ชันวินโดว์