أسس قواعد البيانات › مقدمة في SQL 3 / 24 السابق التالي

مقدمة إلى SQL

أفضل المعلمين لا يكتفون بإلقاء المعلومات على طلابهم والأمل في الأفضل. أفضل المعلمين هم الذين يضعون التوقعات بمسؤولية ويحرصون على أن يتبنى الطلاب عقلية مرنة قائمة على "أستطيع". — Walter Shields، SQL QuickStart Guide: The Simplified Beginner's Guide to Managing, Analyzing, and Manipulating Data With SQL

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

وإذا كانت لديك أي أسئلة، فنحن هنا للمساعدة.

جدولنا الأول: قائمة المقررات

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

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

ما الذي تريد تتبّعه؟

قبل أن تبدأ كتابة الشيفرة، عليك التفكير في بضعة أمور. ما الذي أريد تتبّعه بالضبط؟ ولماذا ستُستخدم البيانات؟

ألقِ نظرة على العرض التعليمي لعلوم الحاسوب التطبيقية. وهنا تجد جميع مقررات برنامج البكالوريوس لدينا للسنة الدراسية 2023-2024.

انظر إلى أحد المقررات، مثل "Front-End Development":

ورقة ECTS لمقرر تطوير الواجهة الأمامية للعام الأكاديمي 2023-2024

وما المعلومات التي تجدها هنا؟ من الواضح أننا نقتصر في هذا المثال التمهيدي على الأساسيات إلى حد بعيد.

نريد أساسًا تخزين المعلومات المفيدة لتجميع برنامجك الفردي للدراسة (ISP). ونختار البيانات التالية:

  • يُحدَّد كل مقرر تحديدًا فريدًا بـرمز المقرر. وبالنسبة إلى "Front-End Development" هذا الرمز "MBI01J". وإذا نظرت إلى مقررات أخرى ستلاحظ أن هذا الرمز يتكوّن دائمًا من 6 محارف.
  • وغني عن القول إن استخدام الرمز في كل مرة نتحدث فيها عن مقرر معين غير عملي إلى حد ما. لذا نمنح كل مقرر أيضًا اسمًا مثل "Front-End Development".
  • ومن الأمور المهمة لوضع برامج ISP عدد نقاط ECTS لكل مقرر. فمعظم المقررات لها 6 نقاط.
  • وفي عام 2023 بدأنا تقديم مقررات بالإنجليزية. ويُدرَّس المقرر نفسه الآن بالهولندية والإنجليزية معًا. وستكون لكل من النسختين رمز مقرر مختلف، لكن من المفيد مع ذلك تضمين اللغة في قائمتنا.
  • وفي أي فصل دراسي يُدرَّس المقرر؟ قد تُدرج بعض المقررات (مثل التدريب) في فصول مختلفة. ومن المفيد لبرنامجك الفردي أيضًا أن تستطيع الحصول على نظرة عامة حسب الفصل. ولنستخدم هذه القيمة كتركيبة من المرحلة (1 أو 2 أو 3) والفصل (1 أو 2). فمثلًا، القيمة 4 تعني أن هذا مقرر من المرحلة 2 والفصل 2.
  • المقررات تأتي وتذهب. فقبل بضع سنوات كان برنامج علوم الحاسوب التطبيقية (بالهولندية) مختلفًا تمامًا. فمثلًا، كان هناك مقرر "Probleemoplossend denken" ("التفكير في حل المشكلات") دُرِّس نحو خمس سنوات واختفى الآن من البرنامج. وسيتعيّن علينا إيجاد طريقة لتضمين هذه المعلومة في قائمتنا حتى نستطيع إعادة بناء نظرة عامة عن المقررات التي دُرِّست في سنة معينة.
  • ولكل مقرر منسّق ومحاضرون يدرّسونه. وتُدرَّس المقررات عادةً على يد عدة محاضرين (في السنة الأولى غالبًا 5 لكل مقرر). وسنضيف ذلك لاحقًا إلى نموذجنا لأنه صعب قليلًا في الوقت الحالي إذ يتطلب جدولًا منفصلًا (المزيد عن ذلك لاحقًا). ويمكننا في هذه المرحلة إضافة المنسّق بالفعل، لأن لكل مقرر منسّقًا واحدًا بالضبط وهو محاضر أيضًا. والمحاضرون، مثل الطلاب، لهم رمز فريد يتكوّن من حرف واحد ("u") متبوعًا بسبعة أرقام. وسنوسّع لاحقًا بيانات المحاضر ونحتفظ بمعلومات أكثر (الاسم وعنوان البريد الإلكتروني ونحو ذلك). وفي هذه المرحلة يكفي رمز المحاضر.

وستصبح البيانات من القائمة أعلاه أعمدة الجدول (عموديًا). ثم يكون لكل مقرر صف واحد (صف أفقي) في الجدول.

بعض أنواع البيانات البسيطة

تستخدم قاعدة بيانات مثل PostgreSQL عدة أنواع بيانات. وقبل أن نبدأ مع SQL، علينا أولًا أن نخبرك بشيء عن أنواع البيانات. ولكل نوع بيانات غرضه وخصائصه المحددة. ومن المهم التفكير بعناية في أنسب نوع بيانات. وفي هذه المقدمة سنقتصر على اختيار صغير.

char()

أحيانًا تعرف مسبقًا أن قيمة خاصية معينة (عمود) هي قيمة نصية. ونستخدم مصطلح "قيم أبجدية رقمية": حروف وأرقام تُفسَّر كمحارف. وإذا كانت تلك القيمة النصية لها دائمًا العدد نفسه من المحارف، فإن نوع البيانات char هو الأنسب في هذه الحالة. فرمز المقرر يتكوّن دائمًا من ستة محارف (في BCS: "MBI" متبوعة برقمين ثم حرف). لذا من الأفضل استخدام char(6) نوع بيانات.

وبالمثل، يُحدَّد كل محاضر تحديدًا فريدًا برمز يتكوّن من "u" متبوعة بسبعة أرقام، مثل "u0012047" (المعروف أيضًا بـ Jan Van Hee). لذا فإن char(8) هو نوع البيانات البديهي لذلك.

ولتخزين لغة المقرر، يصلح نوع البيانات هذا أيضًا. ففي الواقع، يمكن تمثيل أي لغة برموز ISO 639-1 (https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). الهولندية ("nl") والإنجليزية ("en") والفرنسية ("fr")... وبالتالي فإن char(2) خيار جيد.

varchar()

في بعض الأعمدة تعرف أنها تحتوي قيمًا نصية، لكنك لا تعرف مسبقًا طول القيمة النصية. ويمكنك مع ذلك استخدام char، لكن عيبه أنه يحجز دائمًا كامل مساحة الذاكرة. لنفترض أنك تستخدم نوع البيانات char(100) لاسم مقرر، للسماح بإضافة مقررات جديدة باسم أو وصف طويل جدًا. فمقرر مثل "Database foundations" لا يستخدم سوى 20 بايت من الـ 100 المحجوزة، أي ستُملأ 80 بايت بمسافات فارغة. وهذا استخدام غير كفؤ للذاكرة المتاحة.

ولهذا النوع من البيانات، من الأفضل استخدام varchar(100). وتساوي مساحة الذاكرة الإجمالية التي تشغلها قيمة نصية عدد المحارف زائد 1 أو 2 بايت لمعلومات الطول. وفي هذه الحالة، ستشغل "Database foundations" بالتالي 21 بايت (الطول = 20 + 1 بايت إضافي) من مساحة الذاكرة. وهذا استخدام أكفأ للذاكرة المتاحة مقارنة بالـ 100 بايت.

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

integer

بالنسبة إلى الأعداد الصحيحة، نوع البيانات هو integer (4 بايت، من -2147483648 إلى 2147483647). وهذا بالطبع مبالغة بعض الشيء لعمود "credits". ولدى PostgreSQL أيضًا smallint الذي يشغل 2 بايت فقط. وهذا في الواقع الخيار الأفضل هنا، فلنمضِ بهذا الخيار.

date

التعامل مع التواريخ جزء مهم من معالجة قواعد البيانات. وفي هذا المثال التمهيدي، نحتاج إلى القدرة على بيان متى بدأ مقرر وإلى أي تاريخ كان جزءًا من البرنامج. وهناك طرق كثيرة مختلفة لتنسيق تاريخ، لكننا سنبقي الأمر بسيطًا هنا. فإذا بدأ مقرر "web development 1" في 16 سبتمبر 2015، فيمكننا إدخال ذلك التاريخ في صيغة ISO 8601 بالشكل "2015-09-16".

إنشاء المخطط

يمكن لخادم قاعدة بيانات مثل PostgreSQL أن يحتوي كثيرًا من قواعد البيانات. ويمكن أن يتكوّن كل من قاعدة البيانات من عدة مخططات. ولهذا التمرين ننشئ أولًا مخططًا جديدًا.

نفّذ الخطوات التالية في pgAdmin.

افتح اتصال pooling_60203.

افتح قاعدة البيانات المقابلة لصفك (مثل 1CS1 إذا كنت في الصف 1).

انقر بزر الفأرة الأيمن على "Schemas" واختر "Query Tool". وفي هذه النافذة يمكنك الآن تنفيذ شيفرة SQL (وتُسمّى "الجمل" أو "الاستعلامات").

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

CREATE SCHEMA u0012047; -- use your own rnumber! (comments start with -- in SQL)

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

CREATE SCHEMA
Query returned successfully in 293 msec.

وينبغي الآن تحديث قائمة المخططات. انقر بزر الفأرة الأيمن على Schemas واختر "Refresh...". ويظهر مخططك الجديد الآن في القائمة. رائع، أحسنت!

ويوضح الفيديو أدناه إنشاء مخطط والجدول فيه.

إنشاء جدول في هذا المخطط

يتكوّن مخطط قاعدة البيانات عادةً من جداول كثيرة مترابطة بمفاتيح تسمى كذلك. وفي هذا المثال التمهيدي نقتصر على جدول واحد اسمه "course". وللجدول ثمانية أعمدة.

من هنا فصاعدًا، من الجيد حفظ كل ما تكتبه في ملف .txt منفصل. وفي نهاية هذا الدرس، سنطلب منك حذف الصفوف التي أنشأتها وإسقاط الجدول. ونتيجة لذلك ستفقد كل ما أنشأته، لذا من المنطقي حفظ عملك في ملف نصي، مثلًا ملف لكل درس.

شيفرة CREATE

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

CREATE  TABLE course (
  code            char(6)  NOT NULL ,
  credits         smallint  NOT NULL ,    
  name            varchar(100)  NOT NULL , 
  start_date      date  NOT NULL ,    
  end_date        date ,    
  language        char(2)  NOT NULL ,    
  semester        smallint  NOT NULL ,    
  coordinator     char(8)  NOT NULL ,    
  CONSTRAINT pk_course_code PRIMARY KEY ( code ) 
);

وبعض التعليقات على شيفرة SQL هذه:

  • بالنسبة إلى اسم جدول، هل تستخدم المفرد ("course") أم الجمع (courses)؟ الآراء منقسمة. ونختار عادةً صيغة المفرد. ولا يهم فعلًا أي صيغة تختار، ما دمتَ متسقًا.
  • المسافات البيضاء والإزاحة والفراغات ليست مهمة للحاسوب لكنها مهمة للأشخاص الذين عليهم قراءة الشيفرة. لذا اكتب شيفرة قابلة للقراءة واستخدم المسافات البيضاء.
  • تحدثنا عن أنواع البيانات أعلاه: char وvarchar وsmallint وdate.
  • بين الخواص (الأعمدة) تأتي فاصلة.
  • الإضافة NOT NULL تعني أنه إذا أضفت صفًا جديدًا (مقررًا جديدًا) إلى الجدول، فإن تقديم قيمة لهذا العمود إلزامي. وبعبارة أخرى يجب أن يكون هذا العمود ممتلئًا لكل صف. وهناك حقل واحد فقط يمكن تركه فارغًا وهو حقل "end_date". وهذا منطقي أيضًا: فمقرر مثل "Database foundations" (الجديد من السنة الدراسية 2022-2023) سيُدرَّس على أمل أن يستمر سنوات عدة على أي حال. ولا نعرف بعد التاريخ الذي لن يُنظَّم فيه. لذا يكون لكل مقرر جارٍ قيمة فارغة في عمود "end_date".
  • ويضيف السطر الأخير شرطًا مهمًا (CONSTRAINT) اسمه "pk_course_code": عمود "code" هو المفتاح الأساسي. أي أن هذه القيمة تحدد كل صف تحديدًا فريدًا. وإذا حاولت في الجدول إضافة صف جديد بالرمز نفسه، يردّ خادم قاعدة البيانات برسالة خطأ تحافظ بدورها على سلامة البيانات. ونتحدث عن المفاتيح بالتفصيل في فصل نموذج البيانات المنطقي.
  • تُفصل جمل SQL المتعددة بفاصلة منقوطة (;). ومع أن هذه الشيفرة تحتوي جملة واحدة (طويلة) فقط، فسيضع معظم المطورين ; بعدها افتراضيًا.

انسخ كل الشيفرة حتى ; والصقها ونفّذها (F5).

وإذا سار كل شيء على ما يرام، يردّ خادم قاعدة البيانات بـ:

CREATE TABLE
Query returned successfully in 1 secs 151 msec.

أول طالب في الصف ينفّذ هذه الشيفرة سيحصل فعلًا على هذه الرسالة. أما جميع الطلاب التالين فسيحصلون على خطأ على هذا النحو:

ERROR:  relation "course" already exists
SQL state: 42P07

وفي القسم التالي، سنفحص هذا الخطأ الشائع ونقدّم لك حلين.

اختيار المخطط الصحيح

لقد جعلناك عن قصد ترتكب خطأ يجب أن يرتكبه (وسيرتكبه) الجميع مرة واحدة على الأقل. فكل جدول تنشئه ينتهي تلقائيًا في المخطط "public". تحقق من ذلك... سترى أن جدول "course" موجود هناك. ولهذا يحصل الجميع — باستثناء أول طالب — على رسالة الخطأ التي تفيد بوجود جدول بهذا الاسم بالفعل. فالجميع يعملون في المخطط "public" ويحاولون إنشاء جدول باسم موجود بالفعل.

وهناك حلان لهذه المشكلة:

ضع دائمًا اسم المخطط قبل اسم الجدول. وبشكل محدد، يجب أن أعدّل أنا (استخدم اسم مخططك الخاص، أي برقم r الخاص بك) جملة CREATE إلى:

CREATE  TABLE u0012047.course (
  code          char(6)  NOT NULL ,
  ...
);

ويقترح كثيرون هذا الحل كممارسة جيدة، وكثير من الأدوات البرمجية (مثل DBSchema التي سنستخدمها لاحقًا) تفعله بهذه الطريقة بانتظام.

وهناك بديل هو أن تحدد search_path أولًا. وتصبح شيفرتي حينئذ (لا تنسَ الفاصلة المنقوطة بين جملتي SQL):

SET search_path to u0012047;
CREATE  TABLE course (
  code          char(6)  NOT NULL ,
  ...
);

كرّر الآن جملة CREATE أعلاه من القسم السابق لإنشاء الجدول في مخططك الخاص.

إضافة البيانات بـ INSERT INTO

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

ذكر جميع الأعمدة لإعطاء القيم

اكتب ونفّذ الشيفرة التالية (وللمرة الأخيرة: استبدل اسم مخططي باسم مخططك الخاص). ويمكنك بالطبع أيضًا ضبط search_path بشكل صحيح وحينئذ لن تحتاج إلى إحلال اسم المخطط قبل اسم الجدول.

INSERT INTO u0012047.course(code, credits, name, start_date, language, semester,
coordinator) VALUES ('MBI10H', 6, 'Database Foundations', '2022-09-15', 1, 'u0152691');
-- comment: the coordinator is Bram Van Impe, this is his lecturer code

توضع النصوص والتواريخ بين علامات اقتباس مفردة. والنقاط والفصل عددان صحيحان، أي دون علامات اقتباس.

غير أنك ستحصل على رسالة خطأ من خادم قاعدة البيانات. حاول تفسيرها وعدّل الاستعلام بحيث ينجح في إضافة هذه المعلومات.

وإذا ردّ الخادم بكلمة "successfully"، يمكنك التحقق من محتوى الجدول بأكمله بأمر SELECT (وسنفصّله في قسم لاحق):

SELECT * -- the star * means: return the full row 
FROM u0012047.course;

ويردّ الخادم بالعبارة التالية:

النتيجة بعد عبارة INSERT واحدة

لاحظ أن حقل "end_date" له القيمة NULL. وهذا يعني أنه لا توجد قيمة لهذا الحقل.

أعمدة فارغة

هناك طريقة أقصر لإضافة صف، حيث تهمّ القيمة NULL. وكمثال، لنضف مقرر "Programming 1". ونفعل ذلك بالشيفرة التالية:

INSERT INTO u0012047.course
VALUES ('MBI02H', 6, 'Programming 1', '2022-09-15', NULL, 'nl', 1, 'u0118171');
-- the coordinator is Karen Baerts u0118171

أترى الفرق الكبير؟ لم تعد بحاجة إلى سرد أسماء الأعمدة، لكن عليك الآن إدخال القيمة NULL صراحةً للعمود "end_date". وتحقق بـ SELECT * FROM ... من أن هذا المقرر قد أُضيف إلى مخططك أيضًا.

المهمة

أضف الآن عددًا (10 على الأقل) من مقرراتك إلى مخططك. وتأكد من أن لديك أيضًا مقررًا واحدًا على الأقل من الفصول 2 و3 و4 و5 و6. وأضف أيضًا ويفضَّل مقررًا بـلغة أخرى (مثل Français pour le boulot أو Visual user environments... اخترع شيئًا بنفسك إن لزم). وأضف أيضًا بعض المقررات بـأقل من 6 نقاط أو أكثر. وأضف كذلك بعض المقررات التي لم تعد تُدرَّس، وتجد قائمة بالمقررات التي دُرِّست في 2021-2022 هنا. وتاريخ الانتهاء لهذه المقررات هو 2022-09-15.

نصيحة مهمة: سندمّر لاحقًا الجدول كاملًا. لذا احفظ جميع الاستعلامات التي تكتبها لإضافة صفوف جديدة في ملف .txt.

وما دمتَ لا تغلق pgAdmin، ستجد جميع الاستعلامات السابقة تحت علامة التبويب "Query History".

عرض البيانات بـ SELECT

استخدمت بالفعل SELECT * FROM table name أعلاه للحصول على المحتوى الكامل لجدولك. وقد أضفت ما مجموعه 11 مقررًا إلى جدولي. وتتيح هذه الصفوف الـ 11، في بقية هذا النص، تجربة استعلامات SELECT مختلفة.

يمكنك عرض هذا الجدول في قاعدة البيانات "df" والمخطط "sql_intro_en". وقد مُنح كل طالب حقوق USAGE على المخطط وصلاحيات SELECT على الجدول. لذا لا يمكنك الإضافة أو التحديث أو الحذف. ولذلك تعمل في مخططك وجدولك الخاصين حيث لا قيود عليك. ويُغطّى موضوع الأذونات في فصل لاحق.

أحيانًا بالطبع لا تريد رؤية جميع أعمدة الجدول. افترض أنك تريد فقط قائمة بجميع أسماء المقررات يتبعها عدد نقاطها. وفي SELECT تحدد حينئذ تلك الأعمدة صراحةً بالترتيب الصحيح.

SELECT name, credits
FROM sql_intro_en.course;

يُعرض العمودان name وcredits فقط

بعد التأمل، لا أظن أن ترويسة العمود في النظرة العامة أعلاه مناسبة. فبدلًا من "name" في ترويسة العمود، أفضّل وضع "name course". ويمكن فعل ذلك بالاستعلام التالي باستخدام AS:

SELECT name AS "name course", credits
FROM sql_intro_en.course;

لاحظ أنك تحتاج إلى وضع "name course" بين علامتي اقتباس مزدوجتين لأن هذه السلسلة تحتوي مسافة.

تحديد صفوف معينة بـ WHERE

تحتوي نتيجة SELECT ... FROM ... جميع صفوف الجدول. وعادةً لا تهتم بجميع الصفوف بل بالصفوف التي تحقق شرطًا واحدًا أو أكثر فقط. ومثال: أريد نظرة عامة على جميع المقررات التي أنا منسّقها أو كنت منسّقها في الماضي. ورقم موظفي هو "u0012047". ويمكن أن تعرض النظرة العامة جميع الأعمدة. وسيكون الاستعلام:

SELECT *
FROM sql_intro_en.course
WHERE coordinator = 'u0012047';

يُعرض صفان:

أنا منسّق لمقررَين حاليًا أو سابقًا لاحظ استخدام علامات الاقتباس المفردة في السلاسل. علاوة على ذلك، معامل المقارنة في SQL حساس لحالة الأحرف. فالاستعلام نفسه مع WHERE coordinator = ‘U0012047’ لن يعيد صفًا واحدًا لأن جميع أرقام الموظفين أُدخلت بحروف صغيرة.

المعاملات المنطقية

يمكنك دمج الشروط بما يسمى "المعاملات المنطقية": AND وOR وNOT. وستأتي تفاصيل أكثر لاحقًا، لكن مثال صغير الآن. فالشرط المركّب بـ AND يكون صحيحًا فقط إذا كان الشرطان صحيحين. جرّب التمرين التالي.

اسرد جميع المقررات التي لها أقل من 6 نقاط ECTS وتُدرَّس بالهولندية. وتحتوي القائمة على العمودين "name" و"code" و"credits" فقط.

الحل

SELECT name, code, credits
FROM sql_intro_en.course
WHERE credits < 6 AND language = 'nl';

الاختبار على الحقول الفارغة

إذا أردت الاختبار على القيمة NULL فلا يمكنك استخدام علامة التساوي = بل ينبغي استخدام IS NULL أو IS NOT NULL. لننجز تمرينًا صغيرًا.

اسرد جميع المقررات التي لم تعد تُنظَّم.

الحل

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

SELECT *
FROM sql_intro_en.course
WHERE end_date IS NOT NULL;

حذف الصفوف بـ DELETE

ينبغي أن يكون خادم قاعدة البيانات قادرًا أيضًا على حذف الصفوف. فربما تكون البيانات قديمة أو لم تعد منطبقة أو خاطئة فقط. وبالطبع هذه عملية ينبغي أن تكون حذرًا بها. فأنت تستخدم أمر DELETE دائمًا تقريبًا مع WHERE لحذف صفوف معينة فقط من الجدول.

وكمثال، نزيل من الجدول جميع المقررات التي لها أقل من 4 نقاط:

DELETE
FROM u0012047.course
WHERE credits < 4;

ويردّ خادم قاعدة البيانات برسالة تفيد بحذف ثلاثة صفوف من الجدول. وتحقق بـ SELECT * من الصفوف التي أُزيلت.

DELETE 3  
Query returned successfully in 76 msec.

وهناك أيضًا جملة TRUNCATE تتيح لك حذف محتوى الجدول بأكمله. فيبقى الجدول نفسه، لكن تُحذف جميع الصفوف.

تعديل البيانات بـ UPDATE

يحصل المحاضرون على مهام مختلفة، وتتغير أسماء المقررات أو نقاطها أو فصولها... لذا تحتاج أيضًا إلى القدرة على تعديل الصفوف. وبسبب تغيير في تكليفي، لم أعد منسّق مقرر "Front-End Development". والمنسّق الجديد Johan برقم موظف "u0039456". ونحدّث البيانات في الجدول بالاستعلام الأصعب قليلًا UPDATE ... SET ... WHERE ...:

UPDATE u0012047.course
SET coordinator = 'u0039456'
WHERE code = 'MBI01H';

وإذا انطبق الشرط في WHERE على عدة صفوف، فإن منسّق جميع هذه الصفوف يُعدَّل. وبعبارة أخرى، إنه استعلام ينبغي أن تكون حذرًا به. وبما أننا نجري هنا اختبارًا على المفتاح الأساسي "code"، فلا يوجد سوى صف واحد ينجح فيه هذا الاختبار وبالتالي يمكن تحديثه.

وإذا نجحت عمليتك، يمكنك عرض النتيجة بـ SELECT عادي.

منسّق جديد لمقرر MBI01H

بالنسبة إلى جميع المقررات الجارية المدرَّسة في الفصل الثالث، غيّر الفصل إلى 4.

الحل

UPDATE u0012047.course
SET semester = 4
WHERE semester = 3 AND end_date IS NULL;

ترتيب الصفوف بـ ORDER BY

يعيد خادم قاعدة البيانات نتيجة الاستعلام بترتيب معين لا يمكنك التنبؤ به. وهو يعتمد على نوع الخادم (فـ postgreSQL يفعل ذلك بطريقة مختلفة عن InnoDB مثلًا)، والاستعلام، والتحسين الداخلي، ونحو ذلك. وأنت كثيرًا ما تريد ترتيب القوائم حسب عمود واحد أو أكثر: أبجديًا، من الصغير إلى الكبير... ويرتّب الاستعلام التالي جميع المقررات حسب عدد النقاط المتزايد، أي أن المقرر ذا أقل عدد من النقاط في الأعلى.

SELECT *
FROM sql_intro_en.course
ORDER BY credits ASC;

والترتيب الافتراضي من الصغير إلى الكبير ("تصاعدي"). ويمكنك في هذه الحالة إغفال كلمة "ASC". فهذا إذن استعلام مكافئ:

SELECT *
FROM sql_intro_en.course
ORDER BY credits;

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

SELECT *
FROM sql_intro_en.course
ORDER BY 2;

ويمكنك أيضًا الترتيب من الكبير إلى الصغير ("ترتيب تنازلي"). ويعرض هذا الاستعلام قائمة بالمقررات (الاسم والنقاط والمنسّق فقط) بترتيب أبجدي عكسي:

SELECT name, credits, coordinator
FROM sql_intro_en.course
ORDER BY name DESC;  -- alternative: ORDER BY 1 DESC

الترتيب من Z إلى A

ويمكنك أيضًا الترتيب حسب عدة أعمدة بوضع فاصلة بين أسماء الأعمدة (أو أرقامها) بعد ORDER BY. اكتب الاستعلام الذي يعرض القائمة الكاملة (جميع الأعمدة) مرتبة حسب عدد النقاط من الصغير إلى الكبير ثم (داخل عدد النقاط نفسه) حسب الفصل الدراسي المتناقص.

الحل

SELECT *
FROM sql_intro_en.course
ORDER BY credits ASC, semester DESC;   -- alternative: ORDER BY 2, 7 DESC

حذف الجدول بأكمله بـ DROP

في هذا الفصل التمهيدي حصلت على نظرة موجزة على كثير من الخطوات المختلفة: إنشاء مخطط، وتعريف جدول، وملؤه بالبيانات، والاستعلام، والتحديث، وحذف الصفوف، والترتيب... وحان وقت الختام بـتنظيف ما أنشأناه. ويتم حذف جدول فقط إذا كنت مالك الجدول. وحتى لو منحت أشخاصًا آخرين أذونات لمعالجة جدولك، فلن يستطيع أولئك الأشخاص حذفه.

وغني عن القول إن هذه عملية عليك التفكير فيها بعناية. فما يذهب لا يعود!

قصة مصورة

تحذف جدولًا بأمر DROP.

DROP TABLE u0012047.course;

ويردّ الخادم بـ:

DROP TABLE  
Query returned successfully in 128 msec.

تحقق (لا تنسَ "Refresh") من أن الجدول لم يعد في مخططك. ثم يمكنك أيضًا حذف المخطط نفسه بـ:

DROP SCHEMA u0012047;