تخطَّ إلى المحتوى

الدوال و CASE في SQL: معالجة البيانات داخل الاستعلام

الدرس 10 من 12 · SQL

حتى الآن استعلاماتك تعرض البيانات كما هي مخزنة. لكن التقارير الحقيقية تحتاج أكثر: اسم بحروف كبيرة، ورقم مقرَّب، وكلمة «غائب» بدل خانة فارغة، وتقدير «ممتاز» بدل الدرجة 92. في هذا الدرس ستتعلم الدوال (Functions) التي تعالج القيم داخل الاستعلام، وتعبير CASE الذي يضيف منطق «إذا… وإلا» إلى SQL.

سنعمل على جدولي students و courses كما في الدروس السابقة.

SELECT title, UPPER(title) AS upper, LOWER(title) AS lower, LENGTH(title) AS len
FROM courses;

الناتج:

title upper lower len
Python PYTHON python 6
HTML HTML html 4
SQL SQL sql 3

الدالة تأخذ قيمة من كل صف وتُرجع قيمة جديدة. والبيانات في الجدول لا تتغير: التحويل يحدث في نتيجة الاستعلام فقط.

SELECT title, SUBSTR(title, 1, 2) AS short, REPLACE(title, 'L', 'l') AS replaced
FROM courses;

الناتج:

title short replaced
Python Py Python
HTML HT HTMl
SQL SQ SQl
الدالة وظيفتها
UPPER و LOWER تحويل لحروف كبيرة أو صغيرة
LENGTH عدد الحروف
SUBSTR(نص, بداية, طول) جزء من النص، والترقيم يبدأ من 1 لا من صفر
REPLACE(نص, قديم, جديد) استبدال جزء بآخر
TRIM حذف المسافات من الطرفين

من أشهر استخداماتها البحث دون حساسية لحالة الحروف: WHERE LOWER(email) = 'sara@example.com' يجد البريد مهما كُتب بحروف كبيرة أو صغيرة.

SELECT name, score, score / 10 AS int_div, score / 10.0 AS real_div,
ROUND(score / 3.0, 2) AS third
FROM students WHERE id <= 2;

الناتج:

name score int_div real_div third
سارة 92 9 9.2 30.67
عمر 78 7 7.8 26.0
  • ROUND(قيمة, خانات): تقريب إلى عدد محدد من الخانات العشرية.
  • ABS(قيمة): القيمة المطلقة، و % باقي القسمة.

COALESCE: بديل القيمة الفارغة

Section titled “COALESCE: بديل القيمة الفارغة”

تذكّر أن ليلى بلا درجة، وأن أي عملية حسابية مع NULL نتيجتها NULL. الدالة COALESCE تُرجع أول قيمة غير فارغة من القيم التي تعطيها لها:

SELECT name, score, COALESCE(score, 0) AS safe_score, score + 5 AS bonus
FROM students WHERE id >= 4;

الناتج:

name score safe_score bonus
يوسف 64 64 69
ليلى NULL 0 NULL
أحمد 71 71 76

COALESCE(score, 0) تعني: «هات الدرجة، وإذا كانت فارغة فهات صفراً». وهي مثل اللاعب الاحتياطي: ينزل الملعب فقط إذا غاب الأساسي.

CASE تفحص شروطاً بالترتيب، وتُرجع قيمة أول شرط يتحقق:

SELECT name, score,
CASE
WHEN score >= 85 THEN 'ممتاز'
WHEN score >= 70 THEN 'جيد'
WHEN score IS NULL THEN 'غائب'
ELSE 'يحتاج دعماً'
END AS level
FROM students;

الناتج:

name score level
سارة 92 ممتاز
عمر 78 جيد
منى 85 ممتاز
يوسف 64 يحتاج دعماً
ليلى NULL غائب
أحمد 71 جيد
  • كل WHEN شرط THEN قيمة فرع، والفروع تُفحص من الأعلى للأسفل. سارة تحقق الشرطين الأولين، لكنها أخذت «ممتاز» لأنه الأول.
  • ELSE: القيمة إذا لم يتحقق أي شرط. بدونها تكون النتيجة NULL.
  • END: نهاية التعبير، وبعدها اسم العمود بـ AS.

تخيّل CASE مثل موظف الفرز في البريد: ينظر إلى كل طرد، ويضعه في أول صندوق تنطبق عليه القاعدة.

وإذا كانت كل الفروع تقارن العمود نفسه بقيم محددة، فهناك صيغة أقصر:

SELECT name,
CASE city
WHEN 'القاهرة' THEN 'العاصمة'
ELSE 'خارج العاصمة'
END AS region
FROM students WHERE id <= 3;

الناتج:

name region
سارة العاصمة
عمر خارج العاصمة
منى خارج العاصمة

هنا تظهر قوة CASE الحقيقية: عدّ عدة أشياء مختلفة في استعلام واحد.

SELECT
COUNT(*) AS total,
SUM(CASE WHEN score >= 75 THEN 1 ELSE 0 END) AS passed,
SUM(CASE WHEN score < 75 THEN 1 ELSE 0 END) AS failed,
SUM(CASE WHEN score IS NULL THEN 1 ELSE 0 END) AS absent
FROM students;

الناتج:

total passed failed absent
6 3 2 1

الحيلة: CASE تحوّل كل صف إلى 1 أو 0، و SUM تجمع الآحاد. بدونها كنت ستحتاج ثلاثة استعلامات منفصلة.

ويمكن التجميع حسب ناتج CASE نفسه:

SELECT
CASE WHEN age >= 15 THEN 'كبار' ELSE 'صغار' END AS age_group,
COUNT(*) AS total,
ROUND(AVG(score), 1) AS average
FROM students
GROUP BY age_group;

الناتج:

age_group total average
صغار 4 82.7
كبار 2 71.0
SELECT CAST('42' AS INTEGER) + 1 AS n,
CAST(3.9 AS INTEGER) AS cut,
CAST(85 AS TEXT) || '%' AS pct;

الناتج:

n cut pct
43 3 85%

CAST(قيمة AS نوع) تحوّل القيمة من نوع لآخر. لاحظ أن التحويل إلى عدد صحيح يقصّ الكسر ولا يقرّب: 3.9 أصبحت 3.

  1. اعرض اسم كل كورس بحروف صغيرة مع عدد حروفه، مرتبة من الأطول للأقصر.
  2. اعرض اسم كل طالب ودرجته من 10 (أي الدرجة مقسومة على 10.0)، مع COALESCE لتظهر ليلى بصفر.
  3. أضف عموداً result يعرض «ناجح» لمن درجته 70 فأكثر، و«راسب» للأقل، و«لم يُختبر» لمن بلا درجة.
  4. تحدٍّ: في استعلام واحد، اعرض لكل مدينة عدد طلابها وعدد الحاصلين منهم على 80 فأكثر.
  • نسيان END: كل CASE تنتهي بـ END. نسيانها يعطي خطأ صياغة غير واضح.
  • ترتيب الفروع: لو وضعت WHEN score >= 70 قبل WHEN score >= 85 فلن يصل أحد إلى الفرع الثاني. ابدأ بالشرط الأخص.
  • مقارنة NULL داخل CASE: WHEN score = NULL لا تتحقق أبداً. اكتب WHEN score IS NULL.
  • دالة على عمود في WHERE: WHERE UPPER(city) = 'CAIRO' تعمل، لكنها تمنع استخدام الفهرس على العمود كما سترى في الدرس القادم.

سؤال

ماذا تُرجع COALESCE(NULL, NULL, 7, 9)؟

سؤال

طالب درجته 90 في CASE WHEN score >= 70 THEN 'جيد' WHEN score >= 85 THEN 'ممتاز' END. ما النتيجة؟

  • الدوال تعالج القيم في النتيجة دون تغيير البيانات المخزنة.
  • UPPER و LENGTH و SUBSTR و REPLACE للنصوص، و ROUND و ABS للأرقام.
  • احذر قسمة الأعداد الصحيحة، و COALESCE تعطي بديلاً للقيمة الفارغة.
  • CASE WHEN ... THEN ... ELSE ... END منطق شرطي يُفحص بالترتيب.
  • SUM(CASE ...) تعدّ عدة فئات في استعلام واحد، و CAST تحوّل الأنواع.