0Pricing
SQL Interview Prep · บทเรียน

ผู้มีรายได้สูงสุดประจำแผนก

ผสานการแบ่งพาร์ทิชันกับการจัดอันดับสำหรับโจทย์เงินเดือน N อันดับแรกในแต่ละกลุ่ม

ผู้มีรายได้สูงสุดประจำแผนก เป็นบทเรียน SQL Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

จากการจัดอันดับทั้งตารางสู่การจัดอันดับรายกลุ่ม

คำถามต่อยอดถัดไปคือ "ค้นหาพนักงานที่ได้เงินเดือนสูงสุดในแต่ละแผนก" นี่เป็นการผสานการจัดอันดับเข้ากับการจัดกลุ่ม และเป็นคำถามระดับกลางที่มักใช้ประเมินผู้สมัคร

สมมติว่ามีตาราง employee ซึ่งมี id, name, department_id และ salary เราต้องการพนักงานที่มีเงินเดือนสูงสุดหนึ่งคนต่อแผนก หรือมากกว่าหนึ่งคนหากเงินเดือนเท่ากัน ไม่ใช่เพียงค่าสูงสุดของทั้งตาราง

เครื่องมือใหม่ที่สำคัญคือ PARTITION BY ซึ่งเริ่มการจัดอันดับใหม่ภายในแต่ละแผนก

CREATE TABLE employee (
  id            INT PRIMARY KEY,
  name          VARCHAR(100),
  department_id INT,
  salary        INT
);

PARTITION BY เริ่มการจัดอันดับใหม่

การเพิ่ม PARTITION BY department_id ให้กับฟังก์ชันหน้าต่างจะบอกฐานข้อมูลให้คำนวณการจัดอันดับแยกกันภายในแต่ละแผนก

ทุกแผนกจะเริ่มอันดับ 1 ของตนเอง ดังนั้นพนักงานที่ได้เงินเดือนสูงสุดในแผนก 1 และพนักงานที่ได้เงินเดือนสูงสุดในแผนก 5 ต่างก็ได้อันดับ 1 หากไม่แบ่งกลุ่ม จะมีเพียงค่าสูงสุดของทั้งตารางเท่านั้นที่ได้อันดับ 1

SELECT name, department_id, salary,
       DENSE_RANK() OVER (
         PARTITION BY department_id
         ORDER BY salary DESC
       ) AS rnk
FROM employee;

การกรองให้เหลืออันดับ 1

หากต้องการเก็บไว้เฉพาะพนักงานที่มีเงินเดือนสูงสุด ให้ครอบคิวรีที่จัดอันดับแล้วกรองหาอันดับ 1 เช่นเดิม ฟังก์ชันหน้าต่างต้องคำนวณในคิวรีย่อยหรือ CTE ก่อน จึงจะสามารถกรองด้วยฟังก์ชันนั้นได้

การใช้ DENSE_RANK หรือ RANK ในกรณีนี้หมายความว่า หากพนักงานสองคนมีเงินเดือนสูงสุดเท่ากันในแผนกหนึ่ง ระบบจะส่งคืนทั้งสองคน ซึ่งโดยทั่วไปเป็นการตีความที่ถูกต้องของคำว่า "พนักงานที่มีเงินเดือนสูงสุด"

SELECT name, department_id, salary
FROM (
  SELECT name, department_id, salary,
         DENSE_RANK() OVER (
           PARTITION BY department_id
           ORDER BY salary DESC
         ) AS rnk
  FROM employee
) t
WHERE rnk = 1;

ROW_NUMBER เมื่อคุณต้องการเพียงหนึ่งแถว

บางครั้งผู้สัมภาษณ์ต้องการแถว เพียงหนึ่งแถวเท่านั้น ต่อแผนก แม้ว่าจะมีเงินเดือนเท่ากันหลายคน ในกรณีนี้ให้ใช้ ROW_NUMBER และเพิ่มตัวตัดสินกรณีเสมอที่กำหนดผลได้แน่นอน เช่น รหัสที่ต่ำที่สุด

หากไม่มีตัวตัดสินกรณีเสมอ แถวที่เงินเดือนเท่ากันจะถูกตัดสินแบบสุ่ม และผลลัพธ์จะไม่แน่นอน การเพิ่ม , id ASC ทำให้เลือกซ้ำได้ผลเดิม

SELECT name, department_id, salary
FROM (
  SELECT name, department_id, salary,
         ROW_NUMBER() OVER (
           PARTITION BY department_id
           ORDER BY salary DESC, id ASC
         ) AS rn
  FROM employee
) t
WHERE rn = 1;

DENSE_RANK เทียบกับ ROW_NUMBER และ RANK ในกรณีนี้

ให้เลือกตามถ้อยคำของโจทย์อย่างแม่นยำ:

  • DENSE_RANK = 1: พนักงานทั้งหมดที่มีเงินเดือนสูงสุดเท่ากันในแต่ละแผนก
  • RANK = 1: ให้ผลเหมือนกับ DENSE_RANK สำหรับอันดับสูงสุด ช่องว่างของอันดับจะมีผลเฉพาะอันดับถัดจากอันดับ 1 ลงไป
  • ROW_NUMBER = 1: พนักงานเพียงหนึ่งคนต่อแผนก โดยใช้ ORDER BY ของคุณตัดสินกรณีเสมอ

การบอกว่าเลือกแบบใดและเพราะเหตุใดคือส่วนที่ผู้สัมภาษณ์ใช้ให้คะแนน

แนวทางคำสั่งย่อยแบบสัมพันธ์ก่อนมีฟังก์ชันหน้าต่าง

ก่อนจะมีฟังก์ชันหน้าต่าง วิธีมาตรฐานคือใช้คำสั่งย่อยแบบสัมพันธ์ โดยเก็บแถวไว้เฉพาะเมื่อไม่มีใครในแผนกเดียวกันได้เงินเดือนสูงกว่า

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

SELECT e.name, e.department_id, e.salary
FROM employee e
WHERE e.salary = (
  SELECT MAX(e2.salary)
  FROM employee e2
  WHERE e2.department_id = e.department_id
);

แนวทางการเชื่อมตารางด้วย GROUP BY

อีกรูปแบบหนึ่งที่ใช้ได้กับระบบต่าง ๆ คือคำนวณเงินเดือนสูงสุดต่อแผนกด้วย GROUP BY แล้วเชื่อมกลับเพื่อดึงพนักงานที่ตรงกัน

วิธีนี้มีประสิทธิภาพและเข้าใจง่าย การเชื่อมตารางจะนำพนักงานทุกคนที่มีเงินเดือนเท่ากับค่าสูงสุดของแผนกกลับมา ดังนั้นจึงยังคงผู้ที่เสมอกันไว้

SELECT e.name, e.department_id, e.salary
FROM employee e
JOIN (
  SELECT department_id, MAX(salary) AS max_sal
  FROM employee
  GROUP BY department_id
) m
  ON e.department_id = m.department_id
 AND e.salary = m.max_sal;

N อันดับสูงสุดต่อแผนก

รูปแบบนี้ขยายไปสู่โจทย์ "ผู้มีเงินเดือนสูงสุด 3 อันดับแรกต่อแผนก" ได้โดยไม่ต้องมีแนวคิดใหม่ เพียงเปลี่ยนตัวกรองให้เป็นช่วง

เมื่อใช้ DENSE_RANK ค่า rnk <= 3 จะคืนระดับเงินเดือนแบบ DISTINCT สามอันดับแรก ซึ่งอาจมีมากกว่าสามแถวหากมีผู้ที่เสมอกัน ส่วน ROW_NUMBER กับค่า rn <= 3 จะคืนสามแถวพอดีต่อแผนก

SELECT name, department_id, salary
FROM (
  SELECT name, department_id, salary,
         DENSE_RANK() OVER (
           PARTITION BY department_id
           ORDER BY salary DESC
         ) AS rnk
  FROM employee
) t
WHERE rnk <= 3;

ตัวอย่างที่ทำให้ดู

แผนก 1: Ana 120, Bob 120, Cara 90 แผนก 2: Dan 200, Eve 150

  • DENSE_RANK = 1: Ana (120), Bob (120) จากแผนก 1 และ Dan (200) จากแผนก 2 รวมสามแถว
  • ROW_NUMBER = 1 พร้อมใช้รหัสเป็นตัวตัดสินกรณีเสมอ: เลือก Ana หรือ Bob คนใดคนหนึ่ง โดยเลือกคนที่มีรหัสต่ำกว่า และเลือก Dan รวมสองแถว

ข้อมูลเดียวกันอาจให้จำนวนแถวต่างกันตามฟังก์ชันที่ใช้ ให้เลือกให้ตรงกับคำถาม

รวมแผนกและเชื่อมชื่อ

ผู้สัมภาษณ์มักเพิ่มตาราง department แล้วขอชื่อแผนกด้วย เพียงเชื่อมตารางนี้หลังจากจัดอันดับแล้ว

ให้จัดอันดับบนตาราง employee แล้วค่อยเชื่อมตารางอ้างอิงในตอนท้าย เพื่อให้การแบ่งกลุ่มยังเกิดขึ้นในระดับที่ถูกต้อง

SELECT d.name AS department, t.name AS employee, t.salary
FROM (
  SELECT name, department_id, salary,
         DENSE_RANK() OVER (
           PARTITION BY department_id ORDER BY salary DESC
         ) AS rnk
  FROM employee
) t
JOIN department d ON d.id = t.department_id
WHERE t.rnk = 1;

ข้อผิดพลาดที่ควรหลีกเลี่ยง

ข้อผิดพลาดที่พบบ่อยในการจัดอันดับแยกตามกลุ่ม:

  • ลืม PARTITION BY แล้วจัดอันดับรวมทั้งบริษัท ทำให้คืนเฉพาะผู้มีเงินเดือนสูงสุดของบริษัท
  • ใช้ ROW_NUMBER เมื่อโจทย์สื่อว่าต้องแสดงผู้ที่เสมอกันทั้งหมด ทำให้ผู้มีเงินเดือนสูงสุดที่เสมอกันถูกตัดออกโดยไม่แจ้ง
  • พยายามใส่ฟังก์ชันหน้าต่างไว้ใน WHERE โดยตรง แทนที่จะครอบไว้
  • เชื่อมตารางแผนกก่อนจัดอันดับ ทำให้ระดับความละเอียดของการแบ่งกลุ่มเปลี่ยนไปโดยไม่ตั้งใจ

ตรวจสอบด่วน

เลือกฟังก์ชันจัดอันดับที่เหมาะกับข้อกำหนด

สรุป

การหาผู้มีเงินเดือนสูงสุดต่อแผนกคือรูปแบบการจัดอันดับทั่วทั้งข้อมูล โดยเพิ่ม PARTITION BY department_id:

  • DENSE_RANK = 1 คืนผู้มีเงินเดือนสูงสุดที่เสมอกันทั้งหมดในแต่ละแผนก
  • ROW_NUMBER = 1 เมื่อมีตัวตัดสินกรณีเสมอ จะคืนเพียงหนึ่งคนต่อแผนก
  • ทางเลือกที่ใช้ได้กับระบบต่าง ๆ ได้แก่คำสั่งย่อยแบบสัมพันธ์ที่หา MAX ต่อแผนก หรือค่า MAX จาก GROUP BY แล้วเชื่อมกลับกับตาราง

หากต้องการ N อันดับสูงสุด ให้เปลี่ยน = 1 เป็น <= N และบอกให้ชัดว่าจัดการกรณีเสมออย่างไร

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

บทเรียน “ผู้มีรายได้สูงสุดประจำแผนก” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ผู้มีรายได้สูงสุดประจำแผนก” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ผู้มีรายได้สูงสุดประจำแผนก”

ผสานการแบ่งพาร์ทิชันกับการจัดอันดับสำหรับโจทย์เงินเดือน N อันดับแรกในแต่ละกลุ่ม คุณปฏิบัติ SQL Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Interview Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “ผู้มีรายได้สูงสุดประจำแผนก” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน SQL Interview Prep นี้ได้ไหม

ได้ บทเรียน SQL Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เงินเดือนสูงสุดอันดับสอง ห้าวิธี
  2. ค่าสูงสุดอันดับที่ n ด้วย DENSE_RANK
  3. ผู้มีรายได้สูงสุดประจำแผนก
  4. ส่งคืน NULL เมื่อไม่มีค่าอันดับที่ n
← กลับไปที่ SQL Interview Prep