Menu
flag Ar iconالعربيةdown icon

التعامل مع NULL في SQLite: IS NULL وCOALESCE وIFNULL

كيف تتصرف عوامل المقارنة مع قيم NULL في SQLite، ولماذا لا يعمل = و<> كما تتوقع، ومتى تستخدم IS NULL وIS NOT NULL وCOALESCE وIFNULL.

تحتوي هذه الصفحة على محررات قابلة للتشغيل — حرّر، شغّل، وشاهد النتيجة فوراً.

‏NULL في SQLite تعني "قيمة مجهولة"

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

لنجهّز جدولًا صغيرًا نجرّب عليه:

عمودان يسمحان بالقيم الفارغة (NULL). بوريس بدون بريد إلكتروني، وكليو بدون عمر، أما دان فليس لديه أيٌّ منهما. بقية الصفحة تدور حول كيفية الاستعلام عن صفوف كهذه دون أن تقع في الفخ.

لماذا لا يعمل = ولا <> مع NULL؟

أول ما يخطر ببالك هو أن تكتب WHERE email = NULL. تبدو الجملة منطقية للوهلة الأولى، لكنها لن تُرجع أي نتيجة:

صفر صفوف — مع أنّ Boris و Dan واضح إنّ بريدهم فارغ (NULL). السبب: أي مقارنة مع NULL نتيجتها NULL، ليس true ولا false. وعبارة WHERE في SQLite ما تحتفظ إلا بالصفوف التي شرطها true، وNULL ليست true. فيتم استبعاد الصف.

نفس الفخّ يتكرّر مع <>:

تتوقّع أن يُعيد هذا الاستعلام الجميع ما عدا Ada، لكنه يُعيد Cleo فقط. أما Boris وDan فيختفيان من النتيجة لأن بريدهما NULL، والسبب أن NULL <> 'ada@example.com' يُنتج هو الآخر NULL لا قيمة صحيحة.

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

استخدم IS NULL و IS NOT NULL

الطريقة الصحيحة لاختبار القيم الفارغة في SQLite هي عبر المعامل IS. فهو، بعكس =، يفهم طبيعة NULL ويُعيد دائمًا true أو false ولا يُعيد NULL أبدًا:

الاستعلام الأول يُرجع Boris و Dan، أما الثاني فيُرجع Ada و Cleo. المعاملان IS NULL و IS NOT NULL صُمِّما تحديدًا للإجابة عن السؤال: "هل هذه القيمة مفقودة؟" استخدمهما في أي موضع قد تُغريك فيه كتابة = NULL أو <> NULL.

وإذا أردت الحصول على "كل ما عدا Ada، بما في ذلك القيم المجهولة"، فادمج الشرطين صراحةً:

الآن يظهر كلٌّ من Boris و Cleo و Dan في النتائج.

انتشار NULL في العمليات الحسابية ودمج النصوص

قاعدة "القيمة المجهولة" لا تقتصر على عمليات المقارنة فحسب، بل تمتد إلى أبعد من ذلك. أي عملية تتعامل مع NULL ستُنتج NULL بدورها:

next_year وdoubled قيمتهما NULL بالنسبة لـ Cleo وDan. وحتى labelled_age جاءت NULL لهما — لأن دمج أي نص مع NULL ينتج عنه NULL، وليس 'العمر: '. فإذا كان العمود يحتمل أن يكون فارغاً واحتجت إلى قيمة صالحة للاستخدام في النهاية، فلا بد أن تتعامل مع هذه الحالة. ومن هنا تأتي أهمية الدالتين التاليتين.

دالة IFNULL: قيمة بديلة بمعاملين

تُرجع الدالة IFNULL(a, b) القيمة a ما لم تكن NULL، وفي هذه الحالة تُرجع b. وهي أبسط طريقة لاستبدال NULL بقيمة افتراضية:

بوريس ودان يظهر لهم (لا يوجد بريد إلكتروني)، أما كليو ودان فيظهر لهم 0. لاحظ أن البيانات الأصلية لم تتغير، فدالة IFNULL تعيد صياغة المُخرجات فقط.

دالة IFNULL تأخذ وسيطين فقط لا غير. وإذا احتجت إلى عدة قيم بديلة، فالحل هو COALESCE.

دالة COALESCE: أول قيمة ليست NULL هي الفائزة

تمر COALESCE(a, b, c, ...) على وسائطها واحدة تلو الأخرى وتُرجع أول قيمة ليست NULL. وهي بمثابة نسخة موسّعة من IFNULL تقبل أي عدد من القيم البديلة:

بالنسبة لـ Ada و Cleo، يُستخدم البريد الإلكتروني مباشرة. أما Boris و Dan فبريدهما NULL، لذلك تنتقل SQLite إلى الوسيط الثاني وهو عنوان مُركَّب من الاسم. ولو كان هذا بدوره NULL، لانتقلت إلى القيمة الأخيرة 'مجهول'.

تُعدّ COALESCE الخيار الأكثر توافقاً، إذ تدعمها جميع قواعد البيانات الكبرى بالطريقة نفسها. أما IFNULL فهي اختصار خاص بـ SQLite و MySQL يعمل مع وسيطين فقط. اعتمد على COALESCE كخيار افتراضي، ولا تلجأ إلى IFNULL إلا حين يكون لديك وسيطان فعلاً وتريد اسماً أقصر.

NULL في SQLite ليست سلسلة فارغة

من أكثر نقاط الالتباس شيوعاً: التعامل مع NULL و '' على أنهما الشيء ذاته. وهذا غير صحيح إطلاقاً.

'' هي سلسلة نصية حقيقية لكنها لا تحتوي على أي حرف. أما NULL فهو غياب القيمة تمامًا. لذلك length('') يساوي 0، بينما length(NULL) يُعيد NULL نفسه. كذلك NULL = NULL لا يساوي 1، بل يساوي NULL — وهذا بالضبط سبب وجود IS NULL في الأصل.

إذا كان العمود يقبل '' وNULL معًا، اختر واحدًا منهما ليكون دلالة على "القيمة المفقودة" والتزم به. خلطهما يُجبرك على التعامل مع حالتين في كل استعلام، وصدّقني، ستنسى إحداهما عاجلًا أم آجلًا.

سلوك NULL مع IN وNOT IN وDISTINCT

هناك مواضع أخرى تتسلل إليها قيمة null دون أن تنتبه.

استخدام IN مع قائمة تحتوي على null قد يُعطيك نتائج غير متوقعة، خصوصًا مع NOT IN:

قد تتوقع أن تحصل على كل الأشخاص الذين أعمارهم لا تساوي 25. لكنك لن تحصل على أي شيء. فـ SQLite توسّع NOT IN (25, NULL) لتصبح تقريبًا age <> 25 AND age <> NULL، والمقارنة age <> NULL نتيجتها دائمًا NULL — وبالتالي الشرط كله لن يتحقق أبدًا. الحل هو استبعاد القيم الفارغة من القائمة (أو من العمود) قبل إجراء المقارنة.

أما DISTINCT فيتعامل مع القيم الفارغة باعتبارها متساوية فيما بينها لأغراض إزالة التكرار:

تحصل على ثلاثة صفوف: بريد Ada، وبريد Cleo، وقيمة NULL واحدة (انضمّت إليها صفوف Boris وDan معًا). نفس السلوك ينطبق على GROUP BY وUNION — كلاهما يعامل القيم الفارغة كمجموعة واحدة، وهذا عكس ما يفعله المعامل = تمامًا. SQL ليست متّسقة دائمًا في هذه النقطة، لذا من المفيد أن تعرف موقف كل معامل من هذه القضية.

قائمة مراجعة سريعة

  • اختبر القيم المفقودة باستخدام IS NULL وIS NOT NULL، ولا تستخدم = NULL أبدًا.
  • أي عملية حسابية أو دمج نصوص أو مقارنة تلامس NULL ستُرجع NULL.
  • استخدم COALESCE(a, b, c, ...) لاستبدال القيم الفارغة بقيمة بديلة، أو IFNULL(a, b) كاختصار حين يكون لديك وسيطان فقط.
  • السلسلة الفارغة '' ليست مثل NULL. اختر واحدة منهما لتمثيل "مفقود" في كل عمود والتزم بها.
  • العبارة NOT IN (..., NULL) خطأ برمجي في الغالب. احذف القيم الفارغة من القائمة أولًا.

الخطوة التالية: ترتيب النتائج

بعد أن صرت قادرًا على تصفية الصفوف بشكل صحيح — بما فيها الصفوف ذات القيم الفارغة — تأتي الخطوة التالية وهي عرضها بترتيب مفيد. ORDER BY هو موضوع الصفحة التالية، وله رأيه الخاص في الموضع الذي تستقرّ فيه القيم الفارغة داخل النتائج المرتّبة.

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

لماذا لا تعمل column = NULL في SQLite؟

لأن NULL تعني "قيمة غير معروفة"، وأي مقارنة مع قيمة غير معروفة تكون نتيجتها هي الأخرى غير معروفة — وليست true. لذلك فإن WHERE col = NULL لا يطابق أي صف، حتى الصفوف التي يكون فيها العمود فارغاً فعلاً. الحل هو استخدام WHERE col IS NULL، وكذلك الأمر بالنسبة لـ <> فاستخدم بدلاً منه IS NOT NULL.

ما الفرق بين IFNULL وCOALESCE في SQLite؟

الدالة IFNULL(a, b) تأخذ وسيطين فقط لا غير، وتُرجع a إلا إذا كانت قيمتها NULL فتُرجع b. أما COALESCE(a, b, c, ...) فتقبل أي عدد من الوسائط وتُرجع أول قيمة غير NULL تجدها. باختصار، IFNULL هي اختصار لحالة الوسيطين، بينما COALESCE هي الصيغة العامة، كما أنها مدعومة في معظم قواعد بيانات SQL الأخرى.

هل قيمة NULL هي نفسها السلسلة الفارغة في SQLite؟

لا، الفرق جوهري. قيمة NULL تعني "لا توجد قيمة على الإطلاق"، بينما '' هي سلسلة نصية طولها صفر — أي قيمة حقيقية ومعروفة. التعبير '' IS NULL يُرجع 0 (أي false)، وlength('') تساوي 0، في حين أن length(NULL) تساوي NULL نفسها. إذا كان عمودك يقبل الاثنين معاً، فستحتاج إلى التعامل مع كل حالة على حدة، أو توحيدهما في قيمة واحدة.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن