0Pricing
SQL Interview Prep · درس

FIRST_VALUE وLAST_VALUE وحدود الإطار

استخراج قيم الحدود وفهم مشكلة إطار LAST_VALUE

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

استخراج القيم الحدية

قد يسأل القائمون بالمقابلات: «اعرض كل صف إلى جانب أول وآخر قيمة في مجموعته». فكّر في تاريخ تسجيل الدخول الأول لكل مستخدم، أو في أحدث سعر داخل مجموعة، مع عرضه إلى جانب كل صف تفصيلي.

الدالتان هما FIRST_VALUE وLAST_VALUE. تبدوان بسيطتين، لكن LAST_VALUE تخفي أحد أشهر الأخطاء المتعلقة بإطار النافذة في SQL. يجعل هذا الدرس استخدام كلتيهما موثوقًا.

أساسيات FIRST_VALUE

تعيد FIRST_VALUE(col) قيمة col من أول صف في النافذة، وتُرفقها بكل صف. وعند ترتيب الصفوف حسب التاريخ، تمنح كل صف أقدم قيمة في مجموعته.

نظرًا إلى أن الإطار الافتراضي يبدأ من أول صف في المجموعة، تعمل FIRST_VALUE عادةً بالطريقة التي يتوقعها المستخدمون تمامًا.

SELECT
  user_id,
  login_date,
  FIRST_VALUE(login_date) OVER (
    PARTITION BY user_id
    ORDER BY login_date
  ) AS first_login
FROM logins;

إطار النافذة الافتراضي

إليك جوهر المسألة. عند إضافة ORDER BY إلى نافذة، يكون الإطار الافتراضي هو RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.

هذا يعني أن نافذة كل صف تمتد من بداية التقسيم حتى الصف الحالي فقط، وليس حتى النهاية. ولا تتأثر FIRST_VALUE بذلك، لأن الصف الأول يكون دائمًا ضمن النطاق، لكن LAST_VALUE يتأثر بشدة.

فخ LAST_VALUE

عند تشغيل LAST_VALUE باستخدام ORDER BY فقط، يتوقع معظم المترشحين الحصول على القيمة النهائية للتقسيم. لكن بما أن الإطار ينتهي عند الصف الحالي، فإن «آخر قيمة في الإطار» تكون ببساطة قيمة الصف الحالي نفسه.

لذلك يعيد هذا الاستعلام login_date نفسه في كل صف، فيبدو معطلًا. وهذه هي أكثر مشكلة شائعة يُسأل عنها في دوال النوافذ.

SELECT
  user_id,
  login_date,
  LAST_VALUE(login_date) OVER (
    PARTITION BY user_id
    ORDER BY login_date
  ) AS wrong_last_login
FROM logins;

إصلاح LAST_VALUE باستخدام إطار كامل

يكمن الإصلاح في توسيع الإطار ليغطي التقسيم بأكمله: ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.

تمتد النافذة الآن في كل صف عبر التقسيم بأكمله، ولذلك تعيد LAST_VALUE القيمة النهائية الفعلية. اذكر هذا الإصلاح صراحةً في المقابلة؛ فهذا يثبت أنك تفهم الإطارات، لا أسماء الدوال فقط.

SELECT
  user_id,
  login_date,
  LAST_VALUE(login_date) OVER (
    PARTITION BY user_id
    ORDER BY login_date
    ROWS BETWEEN UNBOUNDED PRECEDING
             AND UNBOUNDED FOLLOWING
  ) AS last_login
FROM logins;

بديل أسهل

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

يعيد FIRST_VALUE(login_date) OVER (... ORDER BY login_date DESC) أحدث تاريخ، من دون الحاجة إلى عبارة إطار. إنها حيلة واضحة وسهلة التذكر، ومن المفيد ذكرها.

SELECT
  user_id,
  login_date,
  FIRST_VALUE(login_date) OVER (
    PARTITION BY user_id
    ORDER BY login_date DESC
  ) AS last_login
FROM logins;

ROWS مقابل RANGE في الإطارات

تأتي الإطارات بنوعين. يحسب ROWS الصفوف الفعلية، بينما يجمع RANGE القيم المتساوية في ORDER BY ضمن مجموعة واحدة، وتُسمى هذه الصفوف المتساوية peers.

يستخدم الإطار الافتراضي RANGE، ولذلك تشترك قيم ORDER BY المتساوية في حد الإطار نفسه. ولإصلاحات LAST_VALUE، يُفضَّل استخدام ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING صراحةً لتجنب المفاجآت عند وجود حالات تعادل.

NTH_VALUE للمواقع المختلفة

بعيدًا عن القيمة الأولى والأخيرة، تستخرج NTH_VALUE(col, n) القيمة الموجودة في الموضع n ضمن الإطار، مثل ثاني أعلى سعر.

وتتبع قواعد الإطار نفسها التي تتبعها LAST_VALUE، لذا اجمعها مع إطار كامل عندما تريد القيمة ذات الترتيب n عبر التقسيم بأكمله، وليس فقط حتى الصف الحالي.

SELECT
  product_id,
  price,
  NTH_VALUE(price, 2) OVER (
    PARTITION BY product_id
    ORDER BY price DESC
    ROWS BETWEEN UNBOUNDED PRECEDING
             AND UNBOUNDED FOLLOWING
  ) AS second_highest_price
FROM prices;

مثال تطبيقي: الأولى والأخيرة معًا

يعرض تقرير شائع كل معاملة بجوار مبلغ أول وآخر معاملة للعميل. اجمع بين الدالتين، وتذكّر استخدام الإطار الصريح مع LAST_VALUE.

يحمل كل صف الآن القيمة الأولى والأخيرة للتقسيم بأكمله، ويصبح جاهزًا لحساب الفرق أو لتنفيذ خطوة تصنيف.

SELECT
  customer_id,
  txn_date,
  amount,
  FIRST_VALUE(amount) OVER w AS first_amt,
  LAST_VALUE(amount) OVER w AS last_amt
FROM transactions
WINDOW w AS (
  PARTITION BY customer_id
  ORDER BY txn_date
  ROWS BETWEEN UNBOUNDED PRECEDING
           AND UNBOUNDED FOLLOWING
);

النوافذ المسماة تحافظ على مبدأ DRY

لاحظ أن الاستعلام السابق استخدم عبارة WINDOW w AS (...) وأشار إلى OVER w مرتين. يؤدي تعريف النافذة مرة واحدة إلى تجنب تكرار مواصفة إطار طويلة، ويمنع اختلاف الدالتين عن بعضهما.

تدعم معظم قواعد البيانات الرئيسية النوافذ المسماة. ويُعد استخدام إحداها لمسة منظمة يقدّرها المحاورون عندما تشترك عدة أعمدة في نافذة واحدة.

مثال تطبيقي: الفرق من الأولى إلى الأخيرة

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

يجمع هذا بين إصلاح الإطار الكامل والحساب البسيط، وهو نوع الإجابة المتكاملة التي يريد المحاورون رؤيتها مجمّعة بطريقة واضحة.

SELECT DISTINCT
  customer_id,
  LAST_VALUE(amount) OVER w - FIRST_VALUE(amount) OVER w AS first_to_last_delta
FROM transactions
WINDOW w AS (
  PARTITION BY customer_id
  ORDER BY txn_date
  ROWS BETWEEN UNBOUNDED PRECEDING
           AND UNBOUNDED FOLLOWING
);

تحقق سريع

الالتباس الكلاسيكي في LAST_VALUE.

خلاصة

تعتمد دوال القيم الحدية على الإطار:

  • تعمل FIRST_VALUE مع الإطار الافتراضي، بينما لا تعمل LAST_VALUE بالطريقة المتوقعة.
  • ينتهي الإطار الافتراضي عند الصف الحالي، لذا أصلح LAST_VALUE باستخدام ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING، أو اعكس الترتيب واستخدم FIRST_VALUE.
  • تستخرج NTH_VALUE(col, n) القيم الموجودة في مواقع مختلفة، وتحافظ النوافذ المسماة على مبدأ DRY في مواصفات الأعمدة المتعددة.

وبذلك تكتمل مجموعة أدوات LAG وLEAD وNTILE ودوال القيم الحدية.

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

هل درس «FIRST_VALUE وLAST_VALUE وحدود الإطار» مجاني؟

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

ماذا ستتعلم في «FIRST_VALUE وLAST_VALUE وحدود الإطار»؟

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

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

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

كم من الوقت يستغرق درس «FIRST_VALUE وLAST_VALUE وحدود الإطار»؟

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

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

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

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

  1. LAG وLEAD للصفوف المتجاورة
  2. التغير من فترة إلى أخرى
  3. NTILE لتقسيم الصفوف إلى مجموعات
  4. FIRST_VALUE وLAST_VALUE وحدود الإطار
← العودة إلى SQL Interview Prep