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

دوال النصوص في SQLite: SUBSTR وREPLACE وINSTR

شرح عملي لأهم دوال النصوص في SQLite: الدمج، SUBSTR، INSTR، REPLACE، TRIM، وأساليب تنظيف النصوص وإعادة تشكيلها داخل الاستعلامات.

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

النصوص هي مربط الفرس في معظم الاستعلامات الحقيقية

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

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

دمج النصوص في SQLite يتم بالمعامل || لا بدالة CONCAT

لا توجد في SQLite دالة باسم CONCAT، فدمج النصوص يتم عبر معامل ||:

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

غلِّف الأعمدة التي تقبل القيم الفارغة بـ COALESCE(col, '') أو COALESCE(col, 'default') عندما تريد ألا تُفسد القيمة المفقودة النص بالكامل.

دوال الطول وتحويل حالة الأحرف

ثلاث دوال ستستخدمها بشكل يومي:

LENGTH ترجع لك عدد المحارف (characters) في النص، وليس عدد البايتات. إذا كنت فعلاً بحاجة لعدد البايتات (وهي حالة نادرة لكنها مفيدة لتحليل المساحة التخزينية)، فاستخدم OCTET_LENGTH. أما UPPER و LOWER فتعملان افتراضياً على حروف ASCII فقط، فالحروف ذات العلامات (كحروف اللغات الأوروبية) تمرّ كما هي دون تعديل، إلا إذا قمت بتحميل امتداد ICU.

دالة SUBSTR: تقطيع النصوص في SQLite

تقوم SUBSTR(text, start, length) باستخراج جزء معيّن من النص. انتبه أن الفهرسة تبدأ من 1 وليس من 0، أي أن 1 يشير إلى أول محرف:

بعض الأمور التي يجب تذكّرها:

  • المعامل الثالث اختياري. إذا تركته، ستحصل على النص كاملاً ابتداءً من start حتى نهايته.
  • إذا كانت قيمة start سالبة، فإن العدّ يبدأ من نهاية النص.
  • إذا تجاوزت قيمة start نهاية النص، فستحصل على نص فارغ بدلاً من ظهور خطأ.

يمكنك أيضاً استخدام SUBSTRING كمرادف لها، خاصةً إذا كنت معتاداً عليه من قواعد بيانات أخرى.

دالة INSTR: البحث عن نص داخل نص

تُرجِع INSTR(haystack, needle) موقع أول ظهور للنص needle داخل haystack بترقيم يبدأ من 1، أو 0 إذا لم يُعثَر عليه:

ذلك التعبير الأخير هو الأسلوب المعتاد في SQLite للحصول على «كل ما يسبق الرمز @»: تحدّد موضع الفاصل بواسطة INSTR، ثم تقتطع الجزء المطلوب بواسطة SUBSTR. ستحتاج إلى هذا الثنائي كثيرًا. لكن انتبه: عندما لا يجد INSTR تطابقًا فإنه يُعيد 0، لذا يجب التحقق قبل الاقتطاع، لأن تمرير 0 إلى SUBSTR يُعطي نتائج غريبة دون أن يُصدر أي خطأ.

REPLACE: استبدال نص فرعي بآخر

تقوم الدالة REPLACE(text, old, new) باستبدال كل ظهور للنص old بالنص new:

هذه الدالة حساسة لحالة الأحرف ولا تقبل التعابير النمطية (regex)، بل سلسلة نصية حرفية فقط. لو احتجت تحويلات أكثر تعقيداً، تقدر تتداخل عدة استدعاءات لـ REPLACE معاً، لكن إذا تجاوزت ثلاثة استدعاءات متداخلة فالأفضل أن تنقل المعالجة إلى تطبيقك بدل قاعدة البيانات.

دالة TRIM في SQLite ومتغيراتها LTRIM وRTRIM

البيانات القادمة من المستخدم عادةً ما تأتي محمّلة بمسافات فارغة في بدايتها أو نهايتها، ودالة TRIM تتكفّل بإزالتها:

بشكل افتراضي تقوم هذه الدوال بإزالة المسافات. ولو أردت تحديد أحرف معيّنة لإزالتها، مرّر وسيطًا ثانيًا — وانتبه: كل حرف في هذا الوسيط يُعامَل كعنصر ضمن "مجموعة الأحرف المراد حذفها"، وليس كسلسلة نصية حرفية. لذلك فإن TRIM('xxxhelloxx', 'x') يُعطيك 'hello'.

printf: تنسيق الأرقام والنصوص في SQLite

عندما تحتاج إلى نص منسّق — عدد ثابت من المنازل العشرية، أرقام بحشو أصفار، إخراج بصيغة سداسية عشرية — فإن دالة printf (والتي تُعرف أيضًا باسم format) هي ما تبحث عنه:

محددات التنسيق تتبع أسلوب لغة C، يعني عندك %d و%s و%f و%x، مع إمكانية الحشو بالأصفار أو المسافات وغيرها. هذا الأسلوب أنظف بكثير من بناء النصوص باستخدام || مع كومة من عمليات CAST.

الفرق بين LIKE و GLOB في مطابقة الأنماط

عاملان، وعالمان مختلفان تمامًا.

العامل LIKE يستخدم رموز البدل التقليدية في SQL، حيث يمثّل % أي تسلسل من المحارف، و_ يمثّل محرفًا واحدًا فقط، وهو لا يفرّق بين الأحرف الكبيرة والصغيرة في نطاق ASCII:

GLOB يعتمد على رموز البدل المعروفة في صدفة Unix: * لأي تسلسل من المحارف، و? لمحرف واحد، و[abc] لتحديد فئة من المحارف، كما أنه حساس لحالة الأحرف:

القاعدة لاختيار المناسب: استخدم LIKE للمطابقة بأسلوب بشري مثل «يبدأ بـ» أو «يحتوي على» أو «ينتهي بـ»، واستخدم GLOB حين تهمّك حساسية حالة الأحرف أو حين تحتاج إلى أصناف الأحرف (character classes). كلاهما يستفيد من الفهارس، لكن بشرط أن يكون النمط مثبّتًا من البداية ('foo%' وليس '%foo')، لأن وضع المحرف البديل في البداية يُجبر المحرّك على فحص الجدول كاملًا.

تقسيم النص في SQLite: لا توجد دالة SPLIT

لا تأتي SQLite بدالة SPLIT_STRING جاهزة، وأمامك حلّان عمليّان:

لتقسيم النص على فاصل معيّن وتحويله إلى صفوف متعددة، فأنظف طريقة هي استخدام json_each مع مصفوفة JSON، أو الاستعانة بـ CTE تكراري. سنتطرق إلى الأسلوبين في فصول لاحقة — يكفيك الآن أن تعرف أن جملة "أعطني كل كلمة على حدة" ليست سطراً واحداً في SQLite.

مثال تطبيقي: تنظيف الأسماء

حان وقت تجميع الأفكار. تخيّل جدول users فيه أسماء عرض فوضوية: مسافات زائدة، حروف كبيرة وصغيرة مختلطة، وألقاب اختيارية مثل "Dr. " أو "Mr. " تريد التخلص منها:

يُقرأ التعبير من الداخل إلى الخارج: نزيل المسافات الخارجية أولًا، ثم نحوّل النص إلى أحرف صغيرة، فنحذف الألقاب، ثم نقصّ المسافات مرة أخرى تحسبًا لأن حذف اللقب قد يترك مسافة في البداية. كل خطوة عبارة عن دالة واحدة فقط، لكن التعقيد يأتي من تكديس هذه الدوال فوق بعضها. وحين يتجاوز عدد الطبقات ثلاثًا أو أربعًا، فهذه إشارة إلى أن الأفضل استخدام عمود محسوب (انظر فصل: المزايا المتقدمة) أو القيام بعملية التنظيف أثناء استيراد البيانات.

أبرز ما تخرج به

  • المعامل || لدمج النصوص في SQLite، لكن انتبه: قيمة NULL تُفسد النتيجة، لذا استعن بـ COALESCE.
  • SUBSTR و INSTR معًا يغطّيان معظم احتياجات "ابحث ثم اقتطع".
  • REPLACE يستبدل كل ظهور لسلسلة فرعية محددة.
  • دالة TRIM وأخواتها تقبل مجموعة أحرف مخصصة، وليس المسافات فقط.
  • printf هي الأداة المناسبة لتنسيق المخرجات النصية.
  • LIKE لمطابقة أنماط SQL دون التمييز بين الأحرف الكبيرة والصغيرة، أما GLOB فيستخدم أنماطًا على طريقة الـ shell مع التمييز بين حالة الأحرف.

التالي: الدوال العددية

بعد أن أنهينا التعامل مع النصوص، فالمحطة التالية الطبيعية هي الأرقام: التقريب، والقيم المطلقة، وغرائب القسمة، إضافة إلى الدوال الرياضية التي أضافها SQLite في إصداراته الأخيرة. هذا ما سنتناوله في الصفحة القادمة.

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

كيف يتم دمج النصوص في SQLite؟

استخدم المعامل || بدلاً من CONCAT، فـ SQLite لا يوفّر دالة CONCAT بشكل افتراضي. مثلاً 'Hello, ' || name يدمج النصّين في نص واحد. لكن انتبه: لو كان أحد الطرفين NULL فالنتيجة كلها ستكون NULL، لذا غلّف الأعمدة التي قد تحتوي قيمًا فارغة بـ COALESCE إذا لم تكن هذه النتيجة مرغوبة.

كيف أستخرج جزءًا من نص في SQLite؟

استخدم SUBSTR(text, start, length) ولها أيضًا الاسم البديل SUBSTRING. الفهرسة تبدأ من 1، فمثلاً SUBSTR('hello', 1, 3) يُرجع 'hel'. وإذا كانت قيمة start سالبة فالعدّ يبدأ من نهاية النص، أمّا الوسيط length فهو اختياري — احذفه إذا أردت أخذ كل ما تبقّى حتى آخر النص.

هل توجد دالة SPLIT_STRING في SQLite؟

لا، لا تتوفّر دالة تقسيم جاهزة في SQLite. في معظم الحالات يمكنك الجمع بين INSTR وSUBSTR لاستخراج الجزء الذي تريده، أو استخدام CTE تكراري للتقسيم على فاصل معيّن. وإن كنت تحتاجها كثيرًا فإن استخدام json_each على مصفوفة JSON يكون عادةً أنظف من كتابة دالة تقسيم يدويًا.

ما الفرق بين LIKE وGLOB في SQLite؟

LIKE لا يفرّق بين الحروف الكبيرة والصغيرة افتراضيًا (لأحرف ASCII)، ويستخدم الرمزين % و_ كمحارف بديلة. أمّا GLOB فحسّاس لحالة الأحرف ويستخدم رموز محارف Unix مثل * و? و[abc]. استخدم GLOB عندما تحتاج الحساسية لحالة الأحرف أو فئات المحارف، واستخدم LIKE للبحث الكلاسيكي المعتاد في SQL.

Coddy programming languages illustration

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

ابدأ الآن