MySQL / الأسس العلائقية و SQL الدقيقة / الدرس 2
الاختيار والتصفية والقيم المفقودة
حوّل طلب العمل إلى استعلام حتمي وافهم المنطق ثلاثي القيم في SQL.
في هذه الصفحة
أهداف الدرس
- اختر أعمدة محددة وابن شروطاً دقيقة.
- تعامل مع NULL وحدود التواريخ والترتيب وتقسيم الصفحات.
حدد الصفوف المطلوبة
استخدم بيانات المتجر الأصلية من درس الأسس. ينبغي أن يحدد طلب التقرير الكيان والخصائص وشروط التصفية والترتيب. يختار SELECT التعبيرات ويحدد FROM مصدرها، ويحتفظ WHERE بالصفوف التي تحقق شرطاً صحيحاً فقط. تستبعد القيمتان false و unknown الصف. كما يمنع تحديد الأعمدة تغير استجابة التطبيق عند إضافة أعمدة مستقبلاً.
ركّب الشروط بعناية
تسبق AND العامل OR في الأولوية، لذا استخدم الأقواس عند جمع بدائل تجارية مع شرط مشترك. قارن أرقاماً بأنواع متوافقة. تستخدم LIKE علامة النسبة لأي سلسلة والشرطة السفلية لمحرف واحد، وليست اختبار مساواة. وتعتمد مقارنة النص على collation؛ فلا يثبت البحث غير الحساس للحالة في بيئة أن كل البيئات تقارن بالطريقة نفسها.
SELECT id, total FROM orders
WHERE status = 'paid' AND total >= 10.00
ORDER BY total DESC, id ASC;
id | total
101 | 25.00
103 | 10.00
ينطبق الشرط على الطلبين 101 و 103 بإجماليين 25.00 و 10.00. ويحسم ترتيب id التعادل. واستخدام أكبر من 10 يستبعد الطلب 103؛ لذا فإدراج الحد قرار تجاري صريح.
المجهول يختلف عن الفارغ
تدل NULL على معلومات مفقودة. التعبير NULL = NULL مجهول وليس صحيحاً. استخدم IS NULL للمدن المفقودة، ولا تستعمل COALESCE إلا إذا وافق البديل معنى التقرير. ويوفر MySQL العامل <=> للمساواة الآمنة مع NULL. تجنب NOT IN عندما تضم مجموعته NULL، فقد تصبح نتيجة القيمة غير المطابقة مجهولة فتختفي. وغالباً تكون NOT EXISTS أوضح لاختبار الغياب.
SELECT id, COALESCE(city, 'Unknown') AS display_city
FROM customers WHERE city IS NULL ORDER BY id;
SELECT NULL = NULL AS ordinary, NULL <=> NULL AS safe;
id | display_city
3 | Unknown
ordinary | safe
NULL | 1
تطابق Noor وحدها ويظهر Unknown بينما تبقى المدينة المخزنة NULL. ويعيد الاستعلام الثاني SQL NULL و 1. لا يعني استبدال العرض أننا جمعنا مدينة حقيقية أو جعلنا المساواة المعتادة آمنة مع NULL.
استخدم فترات زمنية نصف مفتوحة
لطلبات يناير قارن placed_at بحد أدنى هو 1 يناير وحد أعلى مستبعد هو 1 فبراير. الحد المنتهي عند منتصف ليل 31 يناير يفقد معظم ذلك اليوم. يخزن DATETIME القيمة التقويمية دون تحويل المنطقة الزمنية الخاص بـ TIMESTAMP. اتفق على اصطلاح زمني للتطبيق واربط قيماً زمنية صحيحة بدلاً من النصوص المحلية أو التحويل الرقمي الضمني.
الترتيب التزام
تحدد LIMIT عدد الصفوف المعادة ولا تحد بالضرورة العمل المنفذ. وبدون ORDER BY لا معنى محدداً للصفحة الأولى، ولا يضمن الفهرس ترتيب النتيجة. يعطي ORDER BY placed_at, id تسلسلاً فريداً. وقد تتطلب OFFSET الكبيرة فحص صفوف مستبعدة وتتغير الصفحات مع الإدخالات المتزامنة. سنستخدم لاحقاً آخر مفتاح ظاهر لطلب الصفحة التالية.
الأخطاء الشائعة وإصلاحها
تقرير فارغ للمدن المفقودة.
- لماذا يحدث؟
- يعطي WHERE city = NULL نتيجة مجهولة حتى لصف Noor.
- كيف تصلحه؟
- استخدم city IS NULL لاختبار الغياب صراحة.
- كيف تتجنب تكراره؟
- أدرج قيماً مفقودة وأخرى موجودة عند مراجعة شروط الأعمدة القابلة للغياب.
ERROR 1054 (42S22): Unknown column.
- لماذا يحدث؟
- استُخدم اسم مستعار من SELECT داخل WHERE قبل إتاحته.
- كيف تصلحه؟
- كرر التعبير الأصلي أو صفِّ استعلاماً خارجياً.
- كيف تتجنب تكراره؟
- ميّز أسماء المخرجات عن أعمدة المصدر عند قراءة نطاق الاستعلام.
نتائج LIMIT غير ثابتة.
- لماذا يحدث؟
- قُيدت الصفوف دون ORDER BY فريد فبقي التعادل اعتباطياً.
- كيف تصلحه؟
- أضف id الفريد كآخر عمود ترتيب.
- كيف تتجنب تكراره؟
- وثق اتجاه الترتيب وطريقة حسم التعادل في مواصفات التقرير.
اختبر فهمك
1. اكتب نطاق يناير وتوقع عدد الطلبات المطابقة.
اعرض الحل المشروح
استخدم WHERE placed_at >= '2026-01-01' AND placed_at < '2026-02-01'. تطابق الطلبات الثلاثة. تشمل الفترة كل أوقات 31 يناير وتستبعد بداية فبراير تحديداً. ويجعل ORDER BY placed_at, id العرض حتمياً.
2. توقع نتيجة WHERE city <> 'Cairo' ثم ضم المدن المفقودة صراحة.
اعرض الحل المشروح
يعيد الشرط الأول Leo فقط لأن صف Noor يعطي نتيجة مجهولة. ويعيد WHERE city <> 'Cairo' OR city IS NULL كلاً من Leo و Noor. يجيب الشرط الثاني عن سؤال أوسع، لذا يجب أن تقرر أن مجهولي المدينة ينتمون إلى الفئة المطلوبة.
أهم ما تعلمته
- يحتفظ WHERE بالشروط الصحيحة؛ والمعلومات المفقودة تحتاج إلى تفكير صريح.
- استخدم مقارنات ذات أنواع صحيحة ونطاقات زمنية نصف مفتوحة وترتيباً فريداً.