تعلم SQL بخمس وصفات سهلة لإتقان استعلامات قواعد البيانات

دقائق القراءة: 7

لغة الاستعلامات الهيكلية SQL (Structured Query Language) هي لغة قوية ومعبرة للتعامل مع البيانات من قواعد البيانات العلائقية. ومع ذلك، قد تبدو مخيفة للمبتدئين. “الوصفات” التي سأشاركها معكم اليوم هي أمثلة أساسية من قاعدة بيانات بسيطة، لكن الأنماط التي ستتعلمونها هنا يمكن أن تساعدكم في كتابة استعلامات دقيقة. ستجعلكم هذه الوصفات تشعرون وكأنكم طهاة بيانات ماهرون في وقت قصير.

ملاحظة حول بناء الجملة: معظم الاستعلامات أدناه مكتوبة بالأسلوب المستخدم لـ PostgreSQL من سطر أوامر psql. يمكن لمحركات SQL المختلفة استخدام أوامر مختلفة قليلاً. يجب أن تعمل معظم الاستعلامات أدناه في معظم المحركات دون تعديل، على الرغم من أن بعض المحركات أو أدوات الواجهة الرسومية قد تتطلب حذف علامات الاقتباس حول أسماء الجداول والأعمدة.

الوصفة 1: استرجاع جميع المستخدمين الذين تم إنشاؤهم ضمن نطاق تاريخ محدد

المكونات

  • SELECT
  • FROM
  • WHERE
  • AND

الطريقة

 SELECT * FROM "Users" WHERE "created_at" > '2020-01-01' AND "created_at" < '2020-02-01' ;

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

الوصفة 2: البحث عن جميع التعليقات لكتاب معين، بما في ذلك المستخدم الذي أضاف التعليق

المكونات

  • JOIN

الطريقة

 SELECT "Comments"."comment", "Users"."username" FROM "Comments" JOIN "Users" ON "Comments"."userId" = "Users"."id" WHERE "Comments"."bookId" = 1 ;

يفترض هذا الاستعلام بنية الجدول التالية:

مخطط علاقات الكيانات (ERD) يوضح جداول المستخدمين والكتب والتعليقات وعلاقاتها في قاعدة البيانات.

أحد الأمور التي قد تبدأ في إرباك المبتدئين في SQL هو استخدام JOINs للعثور على البيانات من الجداول المرتبطة. يوضح مخطط علاقات الكيانات (ERD) أعلاه ثلاثة جداول: Users، Books، و Comments، وعلاقاتها. يحتوي كل جدول على عمود id الذي يظهر بخط غامق في الرسم التخطيطي لإظهار أنه المفتاح الأساسي (primary key) للجدول. هذا المفتاح الأساسي هو دائمًا قيمة فريدة ويستخدم لتمييز السجلات في الجداول.

أسماء الأعمدة المائلة userId و bookId في جدول Comments هي مفاتيح أجنبية (foreign keys)، مما يعني أنها المفتاح الأساسي في جداول أخرى وتستخدم هنا للإشارة إلى تلك الجداول. توضح الموصلات في مخطط ERD أعلاه أيضًا طبيعة العلاقات بين الجداول الثلاثة. يشير الطرف ذو النقطة الواحدة على الموصل إلى "واحد" ويشير الطرف المنقسم على الموصل إلى "متعدد"، لذا فإن جدول User له علاقة "واحد إلى متعدد" (one-to-many) بجدول Comments. يمكن للمستخدم أن يكون لديه العديد من التعليقات، على سبيل المثال، ولكن التعليق يمكن أن ينتمي إلى مستخدم واحد فقط. تتمتع جداول Books و Comments بنفس العلاقة في الرسم البياني أعلاه.

يجب أن يكون استعلام SQL منطقيًا بناءً على ما نعرفه الآن. نحن نعيد فقط الأعمدة المسماة، أي عمود comment من جدول Comments واسم المستخدم username من جدول Users المرتبط (بناءً على المفتاح الأجنبي المشار إليه). في المثال أعلاه، نقيد البحث على كتاب واحد، مرة أخرى بناءً على المفتاح الأجنبي في جدول Comments.

الوصفة 3: حساب عدد التعليقات المضافة بواسطة كل مستخدم

المكونات

  • COUNT
  • AS
  • GROUP BY

الطريقة

 SELECT "Users"."username", COUNT("Comments"."id") AS "CommentCount" FROM "Comments" JOIN "Users" ON "Comments"."userId" = "Users"."id" GROUP BY "Users"."id" ;

يقوم هذا الاستعلام الصغير ببعض الأشياء المثيرة للاهتمام. أسهلها فهمًا هو عبارة AS. تسمح لنا هذه العبارة بإعادة تسمية الأعمدة بشكل تعسفي ومؤقت في البيانات التي يتم إرجاعها. هنا، نعيد تسمية العمود المشتق، ولكنه مفيد أيضًا عندما يكون لديك عدة أعمدة id، حيث يمكنك إعادة تسميتها إلى أشياء مثل userId أو commentId وما إلى ذلك.

عبارة COUNT هي دالة SQL تقوم، كما تتوقع، بحساب الأشياء. هنا، نحسب عدد التعليقات المرتبطة بمستخدم. كيف تعمل؟ حسنًا، GROUP BY هي المكون الأخير المهم. دعنا نتخيل باختصار استعلامًا مختلفًا قليلاً:

 SELECT "Users"."username", "Comments"."comment" FROM "Comments" JOIN "Users" ON "Comments"."userId" = "Users"."id" ;

لاحظ، لا يوجد عد أو تجميع. نريد فقط كل تعليق ومن قام به. قد يبدو الإخراج شيئًا كهذا:

username comment
jackson it 's good, I liked it
jackson this was ok, not the best
quincy excellent read, recommended
quincy not worth reading
quincy I haven 't read this yet

الآن تخيل أننا أردنا حساب تعليقات Jackson و Quincy - من السهل رؤيتها بلمحة هنا، ولكن أصعب مع مجموعة بيانات أكبر كما يمكنك أن تتخيل. تخبر عبارة GROUP BY الاستعلام بشكل أساسي بمعالجة جميع سجلات jackson كمجموعة واحدة، وجميع سجلات quincy كمجموعة أخرى. ثم تقوم دالة COUNT بحساب السجلات في تلك المجموعة وإرجاع تلك القيمة:

username CommentCount
jackson 2
quincy 3

الوصفة 4: البحث عن المستخدمين الذين لم يضيفوا أي تعليق

المكونات

  • LEFT JOIN
  • IS NULL

الطريقة

 SELECT "Users"."username" FROM "Users" LEFT JOIN "Comments" ON "Users"."id" = "Comments"."userId" WHERE "Comments"."id" IS NULL ;

يمكن أن تكون عمليات الربط المختلفة (JOINs) مربكة للغاية، لذلك لن أخوض في تفاصيلها هنا. يوجد شرح ممتاز لها هنا: Visual Representations of SQL Joins، والذي يوضح أيضًا بعض الاختلافات في بناء الجملة بين نكهات SQL المختلفة.

دعنا نتخيل نسخة بديلة من هذا الاستعلام بسرعة:

 SELECT "Users"."username", "Comments"."id" AS "commentId" FROM "Users" LEFT JOIN "Comments" ON "Users"."id" = "Comments"."userId" ;

لا يزال لدينا LEFT JOIN ولكننا أضفنا عمودًا وأزلنا عبارة WHERE. قد تبدو البيانات المرتجعة شيئًا كهذا:

username commentId
jackson 1
jackson 2
quincy NULL
abbey 3

إذن، Jackson مسؤول عن التعليقين 1 و 2، و Abbey عن التعليق 3، و Quincy لم يقم بأي تعليق. الفرق بين LEFT JOIN و INNER JOIN (ما كنا نسميه JOIN حتى الآن، وهو صالح) هو أن الربط الداخلي (INNER JOIN) يعرض فقط السجلات التي توجد فيها قيم لكلا الجدولين. الربط الأيسر (LEFT JOIN)، من ناحية أخرى، يعيد كل شيء من الجدول الأول، أو الأيسر (الذي يحدد بـ FROM)، حتى لو لم يكن هناك شيء في الجدول الأيمن. لذلك، فإن الربط الداخلي سيعرض فقط سجلات Jackson و Abbey.

الآن بعد أن أصبح بإمكاننا تصور ما يرجعه LEFT JOIN، أصبح من الأسهل فهم ما يفعله جزء WHERE...IS NULL. نحن نعيد فقط هؤلاء المستخدمين الذين تكون قيمة commentId لديهم NULL، ولا نحتاج فعليًا إلى تضمين عمود القيمة NULL في الإخراج، ومن هنا جاء حذفه الأصلي.

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

المكونات

  • GROUP_CONCAT أو STRING_AGG

الطريقة (MySQL)

 SELECT "Users"."username", GROUP_CONCAT("Comments"."comment" SEPARATOR ' | ') AS "comments" FROM "Users" JOIN "Comments" ON "Users"."id" = "Comments"."userId" GROUP BY "Users"."id" ;

الطريقة (PostgreSQL)

 SELECT "Users"."username", STRING_AGG("Comments"."comment", ' | ') AS "comments" FROM "Users" JOIN "Comments" ON "Users"."id" = "Comments"."userId" GROUP BY "Users"."id" ;

توضح هذه الوصفة الأخيرة اختلافًا في بناء الجملة لوظيفة مماثلة في اثنين من أشهر محركات SQL. إليك مثال على الإخراج الذي قد نتوقعه:

username comments
jackson it 's good, I liked it | this was ok, not the best
quincy excellent read, recommended | not worth reading

يمكننا أن نرى هنا أن التعليقات قد تم تجميعها وربطها / تجميعها معًا في حقل سجل واحد.

خاتمة: إطلاق العنان لإبداعك في استعلامات SQL

الآن بعد أن أصبح لديك بعض "وصفات" SQL لتعتمد عليها، كن مبدعًا وقدم أطباق بياناتك الخاصة! أحب أن أفكر في WHERE و JOIN و COUNT و GROUP_CONCAT على أنها "الملح، الدهن، الحمض، الحرارة" (Salt, Fat, Acid, Heat) في طهي قواعد البيانات. بمجرد أن تعرف ما تفعله بهذه العناصر الأساسية، فأنت في طريقك إلى الإتقان.

إذا كانت هذه المجموعة مفيدة، أو لديك وصفات مفضلة أخرى لمشاركتها، اترك لي تعليقًا أو تابعني على Twitter: @JacksonBates.

الخلاصة التقنية

يعرض هذا المقال ببراعة خمسة أنماط أساسية ومتقدمة لاستعلامات SQL، مصممة خصيصًا لتبسيط التعامل مع قواعد البيانات العلائقية. من التصفية الأساسية باستخدام WHERE و AND، مروراً بفهم العلاقات المعقدة بين الجداول عبر JOINs والمفاتيح الأساسية والأجنبية، وصولاً إلى تجميع البيانات وتحويلها باستخدام COUNT و GROUP BY، وحتى معالجة السيناريوهات التي تتضمن بيانات مفقودة باستخدام LEFT JOIN و IS NULL. كما يبرز المقال أهمية الدوال التجميعية المتقدمة مثل GROUP_CONCAT و STRING_AGG لتقديم البيانات بشكل أكثر كفاءة. هذه "الوصفات" ليست مجرد أمثلة، بل هي لبنات بناء أساسية لكل مطور بيانات، وتؤكد على أن إتقانها يفتح آفاقًا واسعة لتحليل البيانات واستخراج رؤى قيمة منها.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *