قواعد البيانات وSQL للمبتدئين
قاعدة البيانات برنامج يحفظ بياناتك في جداول من صفوف وأعمدة، ويتيح لعدة برامج أن تقرأ منها وتكتب فيها في الوقت نفسه دون أن يفسد أحدها عمل الآخر. وSQL هي اللغة التي تقول بها ما تريد: <code>SELECT</code> للقراءة و<code>INSERT</code> للإضافة و<code>UPDATE</code> للتغيير.
- الدرس 10 من 14
- مبتدئ
- مجاني، دون تسجيل
ثلاثة جداول، والعمود الذي يربطها
-
جدول المستخدمين
2- id = ٤٢، مريم
مفتاح أساسي: فريد ولا يتغير
- id = ٤٣، سعيد
الاسم والبريد يتغيران، أما id فلا
- id = ٤٢، مريم
-
جدول الطلبات
2- الطلب ١٠٠١، user_id = ٤٢
مفتاح أجنبي: لا يتكرر اسم العميل
- الطلب ١٠٠٢، user_id = ٤٢
يمكن أن يكون لمستخدم واحد عدة طلبات
- الطلب ١٠٠١، user_id = ٤٢
-
جدول المنتجات
1- id = ٧، السعر والاسم
يُكتب السعر هنا لا داخل كل طلب
- id = ٧، السعر والاسم
كل بطاقة صف وكل عمود جدول. وهذه الصورة تُظهر العلاقات لا الفهارس والقيود، وهي التي تأتي منها السرعة والصحة فعلا.
آخر مراجعة: تُراجع الحقائق وأسماء الأدوات في هذا الدرس مقابل مصادرها في هذا التاريخ.
لماذا لا يكفي ملف نصي؟
يمكنك حفظ سجلات المستخدمين في ملف نصي، ولمئة صف يعمل ذلك جيدا. وثلاثة أمور تكسره، وتظهر ثلاثتها في الشهر الأول.
الأول التزامن: فحين يسجل شخصان في اللحظة نفسها، يحاول برنامجان الكتابة في ملف واحد فتضيع إحدى الكتابتين. والثاني البحث: فإيجاد المستخدم صاحب بريد معين في ملف يعني قراءة الملف كله، وهذا يبطؤ كلما كبر الملف. والثالث صحة البيانات: فلا شيء في ملف نصي يمنع تسجيل مستخدمين اثنين بالبريد نفسه.
وقاعدة البيانات برنامج يحل هذه الثلاثة: القفل للكتابة المتزامنة، والفهارس للإيجاد السريع، والقيود كي لا تدخل بيانات غير صالحة أصلا. وأنت لا تكلمها لتحفظ لك ملفا؛ بل تكلمها لتنال تلك الضمانات الثلاث.
ونقطة تُقال أقل: قاعدة البيانات لا تحل محل الملفات. فالصور والفيديو وملفات التنزيل تبقى عادة على القرص ويُسجَّل عنوانها فقط في جدول. وووردبريس يفعل هذا أيضا، ولهذا فإن نسخة قاعدة البيانات وحدها ليست نسخة احتياطية للموقع.
الجدول والصف والعمود وذلك العمود id
الجدول يشبه ورقة في جدول ممتد: الأعمدة تقول ما الذي يُخزَّن، وكل صف سجل واحد. فجدول المستخدمين فيه أعمدة id والاسم والبريد، وكل صف فيه مستخدم واحد. ولا شيء معقدا حتى الآن.
لكن للعمود id دورا خاصا واسمه المفتاح الأساسي: قيمة فريدة في الجدول كله ولا تتغير أبدا. وهو موجود لأن لا شيء آخر يُعتمد عليه؛ فالناس تتكرر أسماؤهم، ويغيرون بريدهم، ويفقدون أرقامهم. ولهذا تحفظ الطلبات رقم id العميل بدل اسمه، ويسمى ذلك الإسناد مفتاحا أجنبيا.
وإليك مثالا حقيقيا يكسر افتراضا شائعا. الجدول الرئيسي في هذا الموقع نفسه، الذي يسميه ووردبريس posts، كان فيه ٧٨٤ صفا يوم مراجعة هذا الدرس، لكن تلك الصفوف الـ٧٨٤ كانت ٢٤ نوعا مختلفا من الأشياء: ٢٦٣ مقالة مدونة، و٢٤٠ ملف وسائط، و٣٧ صفحة، والباقي مشاريع ورسائل وإعلانات وأشياء أخرى.
والدرس الذي في هذا الرقم ينفع أي أحد: الجدول شكل لا موضوع. فكل ما يحتاج الأعمدة نفسها يمكن أن يجلس في الجدول نفسه وأن يُفصل عن الباقي بعمود إضافي واحد. والنتيجة العملية أن SELECT على جدول كهذا بلا شرط يعطيك خليطا من أربعة أشياء لا رابط بينها.
الأوامر الثلاثة التي تنجز أغلب العمل
SQL لغة طلب لا لغة أوامر خطوة بخطوة. فأنت لا تقول كيف تبحث؛ بل تقول ما الذي تريد، وقاعدة البيانات تختار الطريق بنفسها.
SELECT name, email FROM users WHERE city = 'Tehran';
INSERT INTO users (name, email, city) VALUES ('Maryam', 'm@example.com', 'Shiraz');
UPDATE users SET city = 'Isfahan' WHERE id = 42;وثلاثة أشياء في هذه الأسطر الثلاثة تستحق النظر. SELECT يقول أي الأعمدة، وFROM يقول من أي جدول، وWHERE يقول أي الصفوف. وإن كنت لا تعرف الأعمدة فإن SELECT * يجلبها كلها، وهذا حسن للاطلاع وعادة سيئة داخل شفرة البرنامج، لأن يوم يُضاف عمود يتلقى برنامجك شيئا لم يتوقعه.
وأخطر كلمة في هذه الصفحة هي WHERE بغيابها. فـUPDATE users SET city = 'Isfahan'; ليس خطأ نحويا؛ بل صحيح تماما ويغير مدينة كل المستخدمين. ووثائق MySQL وMariaDB كلتاهما تقولان ذلك صراحة، بل لكل منهما وضع يرفض جملة كهذه.
والعادة التي تحل هذا هي كتابة سطر إضافي واحد: اكتب كل UPDATE أو DELETE أولا على هيئة SELECT بالشرط نفسه وانظر كم صفا يعود. فإن لم يكن العدد ما توقعت، فشرطك خاطئ وقد عرفت للتو، لا بعد أن تكون البيانات قد ذهبت.
افعل هذا
- نفّذ الشرط نفسه أولا على هيئة SELECT وانظر عدد الصفوف
- إن لم يوافق العدد توقعك فصحّح الشرط لا الجملة
- تدرّب على نسخة من البيانات لا على البيانات الحية
- مرّر مدخلات المستخدم عبر موضع نائب لا باللصق
لا تفعل
- UPDATE أو DELETE بلا WHERE
- استعلام مبني بلصق نص المستخدم
- تنفيذ جملة كتبها غيرك ولا تفهمها
هذه القائمة لا تحل محل النسخة الاحتياطية. فـUPDATE بلا شرط على بيانات حقيقية وبلا نسخة احتياطية غير قابل للتراجع.
لا تخلط بين قاعدة البيانات والذاكرة المؤقتة
على هذا الخادم نفسه يعمل شيئان جنبا إلى جنب وعمل كل منهما مختلف تماما. أحدهما MariaDB من عائلة MySQL، ويحفظ كل بيانات الموقع الدائمة. والآخر Redis، وهو ذاكرة مؤقتة للكائنات، يحفظ في الذاكرة نتائج أسئلة طُرحت للتو على قاعدة البيانات كي لا يسأل الطلب التالي مرة أخرى.
والفرق بينهما يسعه سطر واحد: لو محونا الذاكرة المؤقتة كاملة لما ضاع شيء ولصارت الطلبات القليلة التالية أبطأ فحسب، لأن كل شيء يُبنى من قاعدة البيانات من جديد. أما لو فقدنا قاعدة البيانات فقد ذهب كل شيء.
ومن هذا السطر وحده تخرج قاعدة عملية تنفعك في كل مكان: لا تضع شيئا في الذاكرة المؤقتة وحدها أبدا. فمن حق الذاكرة المؤقتة أن تكون فارغة في أي لحظة، سواء لإعادة تشغيل أو لامتلاء الذاكرة، والبرنامج الذي يتكل على وجود قيمة فيها يفشل يوم لا تكون موجودة. فالذاكرة المؤقتة للسرعة لا للحفظ.
وهذا الفصل نفسه يوضح قرارات الاستضافة: قاعدة البيانات تحتاج قرصا سريعا ونسخا احتياطية منتظمة، والذاكرة المؤقتة تحتاج ذاكرة. وعلى استضافة ووردبريس التي أعددناها بأنفسنا يجلس الاثنان جنبا إلى جنب، لكن واحدا منهما فقط يُنسخ احتياطيا، وهكذا ينبغي أن يكون.
الديمومة مقابل السرعة: عملان لا خياران
قاعدة البيانات
- المرجع النهائي: إن لم يكن هنا فهو غير موجود
- يبقى على القرص ويؤخذ منه نسخ احتياطي
- القيود والمفاتيح تمنع البيانات غير الصالحة
الذاكرة المؤقتة
- نسخة مؤقتة من شيء بُني للتو
- في الذاكرة ومن حقه أن يكون فارغا في أي لحظة
- محوه لا يتلف شيئا بل يبطئ فحسب
وهذان ليسا خصمين ولا يحل أحدهما محل الآخر. والخطأ الشائع وضع شيء في الكفة اليمنى وحدها.
ما الذي يجعل الاستعلام آمنا؟
أخطر خطأ في العمل مع قاعدة البيانات هو بناء الاستعلام بلصق نص كتبه المستخدم. فحين تتكون جملة SQL من قطعتين، نص المستخدم وأمرك أنت، لا تملك قاعدة البيانات طريقة لتمييز أي جزء كان بيانات وأيه كان تعليمة. ويسمى هذا الصنف من الثغرات حقن SQL.
والعلاج قديم وبسيط وواحد في كل مكان: ضع موضعا نائبا مكان القيمة في نص الاستعلام وسلّم القيمة على حدة. عندئذ يُقرأ كل ما كتبه المستخدم، ولو بدا هو نفسه جملة SQL، على أنه سلسلة نصية لا غير. وفي ووردبريس تفعل الطريقة prepare على الكائن wpdb هذا بالضبط، ووثائق ووردبريس نفسها تعدّها لازمة قبل أي استعلام يحمل مدخلات المستخدم.
وملاحظة عملية توفر عليك وقتا هنا: في أغلب المشاريع أنت لا تكتب SQL خاما أصلا. فلدى ووردبريس والأطر طبقة تبني الاستعلام عنك، وتبنيه آمنا. ومعرفة SQL لتفهم ما أنتجته تلك الطبقة ولماذا هو بطيء، لا لتكتب كل استعلام بيدك.
المسار السريع مع الذكاء الاصطناعي
تحويل جملة إلى استعلام شيء تجيده النماذج اللغوية إجادة غريبة، ولهذا بالذات هو خطر: فالاستعلام الخاطئ الذي يعمل ويعيد صفوفا معقولة أسوأ من استعلام يرفع خطأ. والرويّة التي نستعملها تختلف عن «اكتب لي استعلاما» في أمرين: نعطي بنية الجدول لا البيانات، ونطلب دائما SELECT أولا حتى حين يكون الهدف تغيير البيانات.
- خذ بنية الجدول وأرسلها هي، لا الصفوف. ويكفي <code>SHOW CREATE TABLE</code> أو قائمة الأعمدة بأنواعها، ولا تغادر أي بيانات عميل جهازك.
- بالوصفة أدناه اطلب أولا SELECT يعرض بالضبط الصفوف التي ستتغير، مع عدّها.
- نفّذ ذلك الـSELECT وزن العدد بتوقعك أنت. فإن لم يوافق فالعمل يتوقف هنا وينبغي تغيير الشرط؛ ولا تنتقل إلى الجملة الثانية.
- وعندها فقط اطلب الـUPDATE، بالشرط نفسه دون تغيير، ولا تنفذه على بيانات حقيقية إلا ومعك نسخة احتياطية حديثة.
وصفة جاهزة للنسخ
بنية جدولي هي:
{مخرجات SHOW CREATE TABLE أو قائمة الأعمدة بأنواعها}
ما أريد إنجازه:
{اكتبه بلغة بسيطة، مثلا: أفرغ مدينة كل مستخدم لا طلب له في الأشهر الستة الأخيرة}
أجب بهذا الترتيب:
١. اذكر الافتراضات التي تحتاجها وليست في البنية أعلاه. وإن لزم افتراض، فاسأل أولا ولا تكتب استعلاما.
٢. أعطِ SELECT يعيد بالضبط الصفوف التي ستتغير، مع عدّ لتلك الصفوف.
٣. ثم أعطِ الـUPDATE بالشرط نفسه الوارد في الـSELECT دون أي تغيير.
٤. قل ما أسوأ حالة إن تبين أن الشرط خاطئ.
لم أعطك أي بيانات حقيقية ولا تحتاجها. وإن احتجت بيانات للإجابة فقل لماذا.
قبل أن تثق بالناتج: يرى النموذج بنية الجدول ولا يرى معنى البيانات. فهو لا يعرف هل العمود الفارغ في مشروعك يعني «لم يُملأ بعد» أم «أُفرغ عمدا»، ولا يعرف بمشغّل أو شفرة تفعل شيئا آخر عند التغيير نفسه. وأي رقم يذكره عن الصفوف المتأثرة تخمين؛ والرقم الحقيقي هو ما يعيده SELECT الخاص بك. والحد الأخير مكرر لكنه مهم: على البيانات الحية، الشيء الوحيد الذي يتراجع عن UPDATE خاطئ هو نسخة احتياطية، لا نموذج.
الذكاء الاصطناعي في هذا العمل
في هذا الموضوع يعيد إليك النموذج اللغوي وقتا حقيقيا: كتابة استعلام من وصف، وشرح استعلام كتبه غيرك، ومعرفة لماذا استعلام ما بطيء. وموقفنا أن تضع الحد عند نوع الجملة لا عند صعوبة العمل: فلـ<code>SELECT</code> خذ عون النموذج ونفّذ الناتج مطمئنا، ولكل ما يغير البيانات انظر أولا إلى الـSELECT المكافئ.
أدوات تساعد فعلا
- Claude يجيب عن وصفة هذه الصفحة جيدا، لأنك حين تطلب صراحة أن يذكر افتراضاته أولا فإنه يذكرها فعلا بدل أن يخمن. وإيران ليست في أي من قائمتي الدول المدعومة لدى أنثروبيك؛ قرأنا ذلك في صفحة أنثروبيك نفسها.
- ChatGPT خيار شائع لشرح استعلام غير مألوف وترجمته إلى لغة البشر. ولا نكتب شيئا عن الوصول من إيران لأننا لم نفحصه: فصفحة الدول المدعومة لدى أوبن إيه آي، كبقية ذلك النطاق، تعيد 403 لخادمنا، ونحن لا نكتب ادعاء بلا مصدر.
- Gemini اكتب الاستعلامات البسيطة المتكررة بنموذج سريع رخيص؛ وهنا موضعه. أما استعلام على جدول ذي بنية معقدة فالنموذج الأقوى يجيب عنه أفضل. وصفحة غوغل نفسها تقول إن تطبيق جيميناي على الويب يعمل في أكثر من ٢٣٠ دولة وإقليما، وإيران ليست في تلك القائمة.
اين ينقلب ضدك
الخطر الأساسي في هذا الموضوع استعلام خاطئ لا يرفع خطأ. فشرط ساقط أو OR مكان AND ينتج جملة تعمل وتعيد صفوفا معقولة؛ لكنها ببساطة ليست جواب سؤالك. وحين يقع هذا على SELECT تحصل على تقرير خاطئ، وحين يقع على UPDATE تكون قد غيّرت البيانات. ووثائق MySQL وMariaDB تبين بنفسها خطورة الصيغة بلا شرط، وهذا ما يجعل ترتيب «SELECT أولا» ضروريا.
والخطر الثاني يخص البيانات لا الاستعلامات: فصفوف جدول حقيقي هي عادة معلومات أشخاص حقيقيين، ولصقها في محادثة يعني إخراج بيانات شخصية من سيطرتك. وأنت لا تحتاج الصفوف أبدا للعمل مع نموذج؛ فالبنية تكفي، وهذا القرار وحده يزيل هذا الخطر تماما. ولمعرفة كيف يمكن الدفع لكل أداة من إيران انظر دليل الشراء.
المصادر: MySQL: the UPDATE statement MariaDB: UPDATE WordPress: wpdb prepare Anthropic: supported countries Google: where the Gemini web app is available
حدود هذه النصيحة
يغطي هذا الدرس قواعد البيانات العلائقية في مستوى تمهيدي ويترك عمدا أمورا عدة لأن كلا منها يريد درسه الخاص: JOIN والعمل عبر عدة جداول، والفهارس ولماذا يبطؤ استعلام، والتطبيع، والمعاملات والضمانات التي تقدمها قاعدة البيانات عند الأعطال، وقواعد البيانات غير العلائقية التي لا جداول فيها أصلا. وثمة حد أصرح: لا تتدرب على جمل هذه الصفحة على بيانات حقيقية. اصنع نسخة من قاعدة البيانات على حاسوبك واكسر فيها ما شئت؛ وهو ما نفعله نحن أيضا.
من عملنا نحن
أرقام هذا الدرس قُرئت من هذا الخادم نفسه، في التاريخ المكتوب أعلى الصفحة بوصفه آخر مراجعة. فقاعدة بيانات هذا الموقع فيها ٨٦ جدولا، وجدول posts الذي يحفظ فيه ووردبريس المحتوى كان فيه ٧٨٤ صفا. والطريف في الأمر تركيب تلك الصفوف الـ٧٨٤: ٢٤ قيمة مختلفة في عمود النوع، منها ٢٦٣ مقالة مدونة و٢٤٠ ملف وسائط و٣٧ صفحة، إضافة إلى مشاريع العمل الحر ورسائل التواصل وإعلانات السوق وأنواع أخرى، كلها في ذلك الجدول الواحد. وإلى جانب ذلك الجدول تعمل ذاكرة Redis المؤقتة على الخادم نفسه، وكما قال المتن فإن محوها كاملة لا يتلف أي بيانات. والاثنان معا أفضل تعريف عملي للفرق بين «مخزن دائم» و«نسخة سريعة»، ولهذا صارا مثال هذا الدرس.
اسئلة متابعة حقيقية
ما الفرق بين SQL وMySQL؟
SQL لغة، أما MySQL وMariaDB وPostgreSQL فبرامج تفهم تلك اللغة. فما تتعلمه يعمل في كل مكان تقريبا ولا تختلف إلا تفاصيل كل برنامج. وMariaDB اشتقاق من MySQL، وجمل هذا الدرس واحدة فيهما.
هل أحتاج SQL للعمل مع ووردبريس؟
للعمل اليومي لا؛ فووردبريس يبني كل الاستعلامات بنفسه. ويصير لازما حين تريد أن تفهم لماذا بطؤ الموقع، أو أن تستخرج تقريرا لا تعطيه أي إضافة. وحتى عندئذ ابدأ بالقراءة وأجّل الكتابة على البيانات الحية إلى الآخر.
هل يمكن التراجع عن UPDATE خاطئ؟
لا وحده. فإن كنت نفّذت الجملة داخل معاملة ولم تثبتها بعد، أمكن التراجع؛ وإلا فالطريق الوحيد استعادة نسخة احتياطية. ولهذا فإن سؤال «هل لدي نسخة حديثة؟» يُطرح على البيانات الحقيقية قبل الجملة لا بعدها.