0Pricing
SQL Interview Prep · درس

معالجة التعادلات في Top-N

متى تستخدم RANK أو DENSE_RANK لتضمين جميع الصفوف المتعادلة

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

السؤال اللاحق عن التعادل

بعد أن تتقن حل أعلى N باستخدام ROW_NUMBER، يطرح المحاور سؤالًا أكثر تعقيدًا: "ماذا لو كان لدى موظفين راتب متطابق تمامًا عند الحد الفاصل؟ هل ينبغي تضمينهما معًا؟"

يميز هذا السؤال بين المرشحين الذين حفظوا استعلامًا واحدًا والمرشحين الذين يفهمون دلالات الترتيب. وتعتمد الإجابة على الاختيار بين ROW_NUMBER وRANK وDENSE_RANK. يوضح هذا الدرس وظيفة كل دالة وفق المقصود من متطلبات العمل.

ROW_NUMBER يخفي حالات التعادل

تعيّن ROW_NUMBER عددًا صحيحًا فريدًا تمامًا لكل صف. وحتى عندما يتعادل صفان في العمود المستخدم للترتيب، يحصل أحدهما على 2 والآخر على 3 بترتيب اعتباطي.

والنتيجة هي أن عامل التصفية WHERE rn <= 3 يعيد 3 صفوف بالضبط، وقد يحذف بصمت صفًا متعادلًا كان يستحق الإدراج. وهذا مناسب عندما تريد فعلًا عددًا ثابتًا من الصفوف، لكنه غير صحيح عندما ينبغي قبول جميع الصفوف المتعادلة.

-- Salaries: 100, 90, 90, 80
-- ROW_NUMBER -> 1, 2, 3, 4  (the two 90s get 2 and 3 arbitrarily)
ROW_NUMBER() OVER (ORDER BY salary DESC)

RANK يترك فجوات

تعطي RANK الصفوف المتعادلة الترتيب نفسه، ثم تتجاوز القيم التالية لتعويض حالات التعادل. فإذا تعادل صفان في الترتيب 2، حصلا كلاهما على 2، وقفز الصف التالي إلى الترتيب 4، لا 3.

استخدم RANK عندما تريد "أعلى 3 مراكز" ويمكن أن يشغل المركز الواحد عدة أشخاص، على غرار الترتيب في المسابقات الحقيقية حيث يعني وجود فائزين بالميدالية الفضية عدم وجود ميدالية برونزية.

-- Salaries: 100, 90, 90, 80
-- RANK -> 1, 2, 2, 4   (rank 3 is skipped)
RANK() OVER (ORDER BY salary DESC)

DENSE_RANK بلا فجوات

تعطي DENSE_RANK الصفوف المتعادلة الترتيب نفسه أيضًا، لكنها لا تتجاوز القيمة التالية. فإذا تعادل صفان في الترتيب 2، حصلا كلاهما على 2، وكانت القيمة المميزة التالية هي 3.

استخدم DENSE_RANK عندما يتعلق السؤال بالقيم المميزة، مثل "أعلى 3 مستويات رواتب مميزة" أو "أعلى 3 فئات سعرية". فهي تعد القيم الفريدة، لا الصفوف.

-- Salaries: 100, 90, 90, 80
-- DENSE_RANK -> 1, 2, 2, 3   (no gap)
DENSE_RANK() OVER (ORDER BY salary DESC)

مقارنة جنبًا إلى جنب

بالنسبة إلى قائمة الرواتب 100 و90 و90 و80، تنتج الدوال الثلاث:

  • ROW_NUMBER: 1، 2، 3، 4
  • RANK: 1، 2، 2، 4
  • DENSE_RANK: 1، 2، 2، 3

يجدر بك حفظ هذا الجدول عن ظهر قلب. فقد يطلب منك المحاور ببساطة إكماله لقائمة معينة، ويكون إتقان سلوك الفجوات هو الغرض الأساسي من السؤال.

SELECT salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn,
  RANK()       OVER (ORDER BY salary DESC) AS rnk,
  DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
FROM employees;

تضمين جميع الصفوف المتعادلة باستخدام RANK

للإجابة عن سؤال "أعلى 3، مع تضمين جميع المتعادلين عند الحد الفاصل"، استخدم عامل التصفية RANK() <= 3. فإذا تشارك شخصان الترتيب 3، فسيظهر كلاهما، ولذلك قد تحتوي النتيجة على أكثر من 3 صفوف.

هذا هو المقصود من الأسئلة التي تستخدم عبارة "أعلى 3 مراكز" بدلًا من "أي 3 صفوف". اذكر صراحةً أن عدد الصفوف قد يتجاوز N عند حدوث التعادل.

WITH ranked AS (
  SELECT name, department, salary,
         RANK() OVER (
           PARTITION BY department ORDER BY salary DESC
         ) AS rnk
  FROM employees
)
SELECT name, department, salary, rnk
FROM ranked
WHERE rnk <= 3
ORDER BY department, rnk;

أعلى 3 مستويات مميزة باستخدام DENSE_RANK

عندما يكون المطلوب هو "أعلى 3 مستويات رواتب مميزة" وتريد كل موظف في تلك المستويات الثلاثة، استخدم DENSE_RANK() <= 3.

قد يعيد هذا عددًا كبيرًا من الصفوف: فجميع الموظفين في أعلى ثلاث درجات أجور سيظهرون، مهما كان عددهم في كل درجة. والفكرة الأساسية هي أن DENSE_RANK تعد القيم المميزة، ولذلك يختار عامل التصفية مستويات القيم بدلًا من عدد ثابت من الصفوف.

WITH ranked AS (
  SELECT name, salary,
         DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
  FROM employees
)
SELECT name, salary, drnk
FROM ranked
WHERE drnk <= 3
ORDER BY drnk;

دليل اتخاذ القرار

طابق صياغة السؤال مع الدالة:

  • "عدد N من الصفوف بالضبط" أو التصفح على صفحات → ROW_NUMBER (مع إضافة عامل كسر تعادل).
  • "أعلى N من المراكز، مع مشاركة المتعادلين للمركز" → RANK.
  • "أعلى N من القيم أو المستويات أو الفئات المميزة" → DENSE_RANK.

عندما تكون المواصفات غامضة، اسأل: "إذا حدث تعادل عند الحد الفاصل، فهل ينبغي أن أضمّن جميع الصفوف المتعادلة أم أقيّد النتيجة بـ N؟" فهذا السؤال التوضيحي بحد ذاته يكسبك نقاطًا.

لا تزال عوامل كسر التعادل مهمة

حتى مع RANK أو DENSE_RANK، تؤدي إضافة مفتاح ثانوي إلى ORDER BY إلى التحكم في ترتيب العرض للصفوف المتعادلة والحفاظ على ثبات الناتج. وهي لا تغيّر الصفوف المؤهلة، لكنها تجعل النتائج قابلة لإعادة الإنتاج.

أما مع ROW_NUMBER، فعامل كسر التعادل ضروري لأنه يحدد أي صف متعادل سيبقى أصلًا بعد تطبيق حد rn.

RANK() OVER (
  PARTITION BY department
  ORDER BY salary DESC, name ASC
) AS rnk

مثال عملي: أصحاب أعلى النتائج

يحتوي جدول game_scores على player وscore. ويريد المحاور "جميع اللاعبين الموجودين ضمن أعلى مركزين من حيث النتيجة". ويعني التعادل في المركز الأول وجود لاعبين في المركز 1، ثم يكون المركز التالي هو المركز 2 لأعلى نتيجة مميزة تالية.

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

WITH r AS (
  SELECT player, score,
         DENSE_RANK() OVER (ORDER BY score DESC) AS pos
  FROM game_scores
)
SELECT player, score, pos
FROM r
WHERE pos <= 2
ORDER BY pos, player;

أخطاء شائعة ينبغي تجنبها

الأخطاء التي يراقبها المحاورون:

  • استخدام ROW_NUMBER عندما يتطلب السؤال تضمين المتعادلين، مما يؤدي إلى حذف صف مؤهل بصمت.
  • الخلط بين سلوك الفجوات في RANK وDENSE_RANK.
  • نسيان أن عوامل تصفية RANK/DENSE_RANK قد تعيد أكثر من N صفوف، ثم الادعاء بأن النتيجة خاطئة.
  • حذف PARTITION BY عندما يكون المطلوب أعلى N لكل مجموعة، مما يؤدي إلى ترتيب الجدول بأكمله بدلًا من ذلك.

اختبار سريع

اختر دالة الترتيب المناسبة لسلوك التعادُل الموضَّح.

مراجعة: التعامل مع حالات التعادل

ثلاث دوال، وثلاثة سلوكيات للتعادُل:

  • ROW_NUMBER: قيم فريدة دائمًا، وعدد الصفوف يساوي N تمامًا، مع كسر التعادل بطريقة عشوائية.
  • RANK: تتشارك الصفوف المتعادلة المرتبة نفسها، ثم تظهر فجوات في الترتيب.
  • DENSE_RANK: تتشارك الصفوف المتعادلة المرتبة نفسها، من دون فجوات، ويُحصي القيم المميزة.

اختر الدالة وفقًا لصياغة السؤال، واطرح سؤالًا توضيحيًا عند الغموض، وتذكّر أن عوامل التصفية باستخدام RANK/DENSE_RANK قد تُرجع أكثر من N صفوف عن قصد.

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

هل درس «معالجة التعادلات في Top-N» مجاني؟

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

ماذا ستتعلم في «معالجة التعادلات في Top-N»؟

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

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

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

كم من الوقت يستغرق درس «معالجة التعادلات في Top-N»؟

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

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

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

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

  1. صفوف Top-N لكل مجموعة باستخدام ROW_NUMBER
  2. معالجة التعادلات في Top-N
  3. إزالة تكرار الصفوف بأمان
  4. الاحتفاظ بأحدث صف لكل مفتاح
← العودة إلى SQL Interview Prep