0Pricing
SQL Interview Prep · درس

القيمة الأعلى رقم N باستخدام DENSE_RANK

تعميم الحل للوصول إلى القيمة المميزة رقم N ومعالجة التكرارات

القيمة الأعلى رقم N باستخدام DENSE_RANK درس مجاني في SQL Interview Prep على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في SQL Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة SQL Interview Prep 4 دروس في المجموع.

التعميم إلى الراتب ذي الترتيب N من الأعلى

بمجرد أن تتمكن من إيجاد ثاني أعلى راتب، سيدفعك المحاورون فورًا إلى السؤال التالي: «والآن أعطني الراتب رقم N من الأعلى». تستخدم الإجابة الأنظف والأكثر قابلية للدفاع عنها DENSE_RANK.

النمط واحد دائمًا: رتّب الرواتب غير المكررة ترتيبًا تنازليًا، ثم رشّح الصف الذي يساوي ترتيبه N. وبما أن المنطق لا يتغير بتغير N، فإن هذا الأسلوب الواحد يجيب عن مجموعة الأسئلة كلها.

سننشئ الحل تدريجيًا، ونتعامل مع حالات التعادل والتكرار، ونناقش سبب كون DENSE_RANK دالة الترتيب المناسبة لدلالات «القيمة غير المكررة».

القالب الأساسي

إليك قالبًا قابلًا لإعادة الاستخدام لإيجاد الراتب رقم N من الأعلى. استبدل الثابت بأي قيمة لـ N يطلبها المحاور.

تحسب DENSE_RANK في استعلام داخلي، إذ لا يمكن استخدام دالة النافذة داخل WHERE، ثم تُرشّح النتائج خارجيًا باستخدام rnk = N. ولإيجاد ثالث أعلى راتب، اضبط المرشح على rnk = 3.

SELECT salary AS nth_highest
FROM (
  SELECT salary,
         DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
  FROM employee
) ranked
WHERE rnk = 3;

كيف ترقّم DENSE_RANK القيم غير المكررة

تُسند DENSE_RANK الترتيب نفسه إلى القيم المتساوية، ولا تترك بعدها أي فجوة. وهذا يطابق تمامًا تعريف «القيمة غير المكررة رقم N» الذي يقصده المحاورون.

بالنسبة إلى الرواتب 800، 800، 600، 600، 400:

  • 800 ← الترتيب 1
  • 600 ← الترتيب 2
  • 400 ← الترتيب 3

إذن الراتب الثالث من الأعلى هو 400، رغم وجود خمسة صفوف. تُدمج القيم المكررة تلقائيًا في ترتيب واحد.

لماذا تعطي RANK إجابة خاطئة

استبدلها بـ RANK وستصبح الإجابة خاطئة. إذ تترك RANK فجوات تتناسب مع عدد القيم المتعادلة.

بالنسبة إلى 800، 800، 600، 600، 400:

  • 800، 800 ← الترتيب 1 (صفان)
  • 600، 600 ← الترتيب 3 (فجوة، ولا يوجد ترتيب 2)
  • 400 ← الترتيب 5

تعيد التصفية باستخدام rnk = 3 القيمة 600، بينما لا يعيد rnk = 2 أي نتيجة. ما لم يطلب المحاور تحديدًا ترتيبًا على نمط المنافسة، فإن DENSE_RANK هو الصحيح لإيجاد «الراتب غير المكرر رقم N».

لماذا تكون ROW_NUMBER خاطئة هنا أيضًا

تُسند ROW_NUMBER رقمًا فريدًا إلى كل صف، وتتجاهل التعادلات تمامًا. وبالنسبة إلى 800، 800، 600، 600، 400، فإنها تنتج 1، 2، 3، 4، 5.

لذلك يعيد rn = 3 القيمة 600، لكن rn = 2 يعيد القيمة المكررة 800، وليس قيمة ثانية غير مكررة. تجيب ROW_NUMBER عن سؤال «ما الصف رقم N؟» لا عن سؤال «ما القيمة غير المكررة رقم N؟»

استخدم ROW_NUMBER فقط عندما يكون المطلوب فعلًا صفًا محددًا، مثل إزالة التكرار أو اختيار أفضل N لكل مجموعة مع الاحتفاظ بصف واحد بالضبط.

SELECT salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn
FROM employee;

تمرير N بأمان

في الشيفرة الفعلية، لن تكتب الترتيب بشكل ثابت. مرّر N كمعامل وقارنه به. ويظل تعريف النافذة كما هو؛ أما الجزء الوحيد الذي يُمرر كمعامل فهو المرشح الخارجي.

وهنا يمكنك أيضًا إرجاع كل الرواتب المتعادلة عند الترتيب N: لأن DENSE_RANK تشارك الترتيب بين القيم المتعادلة، فقد يعيد WHERE rnk = N عدة صفوف إذا اشترك عدة موظفين في الراتب غير المكرر رقم N، وغالبًا ما يكون هذا هو السلوك المطلوب.

SELECT id, salary
FROM (
  SELECT id, salary,
         DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
  FROM employee
) ranked
WHERE rnk = :n;

تعميم العد المترابط

يمكن أيضًا تعميم الأسلوب السابق على دوال النوافذ: يكون الراتب هو الراتب رقم N من الأعلى وغير المكرر عندما يكون عدد الرواتب غير المكررة الأكبر منه تمامًا يساوي N - 1.

لإيجاد ثالث أعلى راتب، اشترط وجود راتبين غير مكررين أعلى منه بالضبط. يعمل هذا الأسلوب في المحركات القديمة التي لا تدعم دوال النوافذ، لكنه يتوسع بشكل ضعيف لأن عملية العد الداخلية تُعاد لكل صف خارجي.

SELECT DISTINCT salary AS nth_highest
FROM employee e
WHERE (
  SELECT COUNT(DISTINCT e2.salary)
  FROM employee e2
  WHERE e2.salary > e.salary
) = 2;

صيغة دالة MySQL التي يطلبها المحاورون

غالبًا ما تطلب مسألة «Nth highest salary» بأسلوب LeetCode دالةً مخزنة تُرجع قيمة واحدة. وجسم الدالة ليس إلا قالب DENSE_RANK بعد تغليفه لإرجاع راتب واحد.

لا تحتاج إلى حفظ الصياغة الدقيقة للدالة في المقابلة، لكن من المفيد معرفة أن LIMIT N-1, 1 هو الأسلوب الاصطلاحي المختصر في MySQL عند التعامل مع الرواتب غير المكررة.

SELECT DISTINCT salary
FROM employee
ORDER BY salary DESC
LIMIT 1 OFFSET 2;  -- N = 3, so OFFSET N-1

مثال تطبيقي: رابع أعلى راتب

الرواتب: 1000، 900، 900، 700، 500، 500، 300.

ترتيب القيم غير المكررة تنازليًا باستخدام DENSE_RANK:

  • 1000 ← 1
  • 900 ← 2
  • 700 ← 3
  • 500 ← 4
  • 300 ← 5

رابع أعلى راتب هو 500. لاحظ أن صفّي 500 يشتركان في الترتيب 4، لذلك ستعيد التصفية باستخدام rnk = 4 الموظفين اللذين يتقاضيان 500 إذا اخترت معرّفاتهما أيضًا.

ملاحظات حول الأداء

كيف تتباين الأساليب عند التعامل مع نطاق واسع؟

  • DENSE_RANK: عملية ترتيب واحدة للبيانات، ثم تصفية. وهو فعال، ويمكن لمخطط الاستعلام استخدام فهرس على salary للترتيب.
  • Correlated count: قد يصل تعقيده إلى O(n²)، لأن التجميع الداخلي يُنفذ لكل صف. تجنّبه في الجداول الكبيرة.
  • LIMIT/OFFSET: سريع عند استخدام N صغيرًا، لكنه لا يزال يحتاج إلى الترتيب، كما أن الإزاحات الكبيرة تقرأ عددًا كبيرًا من الصفوف ثم تستبعدها.

ابدأ بـ DENSE_RANK، ونادرًا ما ستخطئ.

حالات حدية ينبغي ذكرها

يبادر المرشحون الأقوياء إلى ذكر الحالات الحدية قبل أن يُطلب منهم ذلك:

  • كون N أكبر من عدد الرواتب غير المكررة: لن يطابق المرشح أي صف، وستكون النتيجة فارغة. يشرح الدرس 4 كيفية إجبار الاستعلام على إرجاع NULL واحد.
  • التعادلات عند الترتيب N: تعيد DENSE_RANK كل الموظفين المتعادلين؛ لذلك حدّد ما إذا كان هذا هو السلوك المطلوب.
  • N = 1: يظل القالب صالحًا ويعيد القيمة العظمى.

تحقق سريع

طبّق قالب الراتب رقم N من الأعلى.

الخلاصة

للراتب رقم N من الأعلى إجابة أساسية واحدة: رتّب الرواتب غير المكررة باستخدام DENSE_RANK() OVER (ORDER BY salary DESC) في استعلام فرعي، ثم رشّح باستخدام WHERE rnk = N.

  • DENSE_RANK تعني «القيمة غير المكررة رقم N»، مع منح القيم المتعادلة الترتيب نفسه ومن دون فجوات.
  • تُدخل RANK فجوات، بينما تعدّ ROW_NUMBER الصفوف لا القيم.
  • تعمّم حيلة correlated count = N-1 الفكرة نفسها من دون دوال نوافذ، لكنها تتوسع بشكل ضعيف.

اذكر دائمًا الحالة الحدية التي يتجاوز فيها N عدد القيم المتاحة؛ وسنحلها بعد ذلك.

الأسئلة الشائعة

هل درس «القيمة الأعلى رقم N باستخدام DENSE_RANK» مجاني؟

نعم — نص درس «القيمة الأعلى رقم N باستخدام DENSE_RANK» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة SQL Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة SQL Interview Prep 4 دروس في المجموع.

ماذا ستتعلم في «القيمة الأعلى رقم N باستخدام DENSE_RANK»؟

تعميم الحل للوصول إلى القيمة المميزة رقم N ومعالجة التكرارات تتمرن على SQL Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ SQL Interview Prep؟

لا تُشترط خبرة سابقة. SQL Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «القيمة الأعلى رقم N باستخدام DENSE_RANK»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس SQL Interview Prep هذا؟

نعم. كل درس في SQL Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ثاني أعلى راتب بخمس طرق
  2. القيمة الأعلى رقم N باستخدام DENSE_RANK
  3. أعلى دخل في كل قسم
  4. إرجاع NULL عند عدم وجود قيمة رقم N
← العودة إلى SQL Interview Prep