مقدمة في استعلامات JOIN
مقدمة في استعلامات JOIN
تخيّل أنك ذهبت إلى بنك، وتحتاج موظفة الصندوق إلى عرض جدولي "معلومات الحساب" و"المعلومات الشخصية" في وقت واحد. لا تستعلم عنهما بشكل منفصل ومطابقتهما يدويًا — بل "تدمج" الجدولين باستخدام رقم هويتك لرؤية الصورة الكاملة دفعة واحدة. JOIN هو السحر في SQL الذي يتيح للجداول المتعددة "التحدث" مع بعضها البعض.
1. المفاهيم الأساسية
لماذا نحتاج إلى JOINs؟
عند تصميم قاعدة بيانات، نقسم البيانات إلى جداول متعددة لتجنب التكرار. على سبيل المثال، جدول employees يخزّن فقط department_id، بدلاً من تكرار اسم القسم وعنوانه. لكن الاستعلامات غالبًا ما تحتاج إلى "تجميع" المعلومات الكاملة مرة أخرى، وهنا تأتي JOINs.
-- بدون JOIN: لا يمكن رؤية department_id، فقط اسم القسم
SELECT name, department_id, salary FROM employees;
-- مع JOIN: اسم الموظف واسم القسم يظهران معًا
SELECT e.name, d.name AS department, e.salary
FROM employees e
JOIN departments d ON e.department_id = d.id;
أنواع العلاقات بين الجداول
| نوع العلاقة | الوصف | مثال |
|---|---|---|
| واحد لواحد (1:1) | صف واحد في الجدول A يقابل صفًا واحدًا في الجدول B | مستخدم واحد لديه بطاقة هوية واحدة |
| واحد لعديد (1:N) | صف واحد في الجدول A يقابل عدة صفوف في الجدول B | قسم واحد لديه عدة موظفين |
| عديد لعديد (M:N) | عدة صفوف في الجدول A تقابل عدة صفوف في الجدول B | الطلاب والمقررات (مرتبطة عبر جدول التسجيل) |
في قاعدة البيانات الخاصة بنا:
departments→employees: واحد لعديد (قسم واحد لديه عدة موظفين)products→orders: واحد لعديد (منتج واحد يمكن أن يظهر في عدة طلبات)
المفتاح الخارجي
المفتاح الخارجي هو الجسر الذي يُنشئ العلاقات بين الجداول. وهو عمود في الجدول A يشير إلى المفتاح الأساسي في الجدول B، مما يضمن اتساق البيانات.
-- department_id في جدول employees هو مفتاح خارجي يشير إلى id في جدول departments
CREATE TABLE employees (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
department_id INTEGER, -- مفتاح خارجي
salary DECIMAL(10,2),
hire_date DATE,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
PRAGMA foreign_keys = ON; لتفعيلها.
صيغة INNER JOIN
INNER JOIN يُرجع فقط الصفوف التي تطابقت في كلا الجدولين. إذا لم يكن لدى صف بيانات مقابلة في الجدول الآخر، يتم استبعاده.
SELECT column_name
FROM table_A
INNER JOIN table_B ON table_A.column = table_B.column;
شرط ON
يُحدد شرط ON شرط الانضمام — أي العمود المستخدم لمطابقة الصفوف بين الجدولين. عادةً يقارن مفتاحًا خارجيًا بمفتاح أساسي.
-- شرط ON: employees.department_id = departments.id
SELECT e.name, d.name AS department
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
أسماء الجداول المستعارة (AS)
عندما تكون أسماء الجداول طويلة أو تحتاج إلى التمييز بين أعمدة لها نفس الاسم، يمكنك استخدام AS لإنشاء أسماء مستعارة للجداول، مما يُبسّط الكتابة:
-- بدون أسماء مستعارة: يجب كتابة الأسماء الكاملة في كل مرة
SELECT employees.name, departments.name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
-- مع أسماء مستعارة: أكثر إيجازًا
SELECT e.name, d.name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
2. الصيغة الأساسية/الاستخدام
صيغة INNER JOIN الكاملة
SELECT table_A.column1, table_A.column2, table_B.column1
FROM table_A
INNER JOIN table_B ON table_A.foreign_key = table_B.primary_key
WHERE condition
ORDER BY column_name;
INNER — كتابة JOIN وحدها تعادل INNER JOIN.
A JOIN B ON ... JOIN C ON ....
مثال: استعلام عن الموظفين وأقسامهم (الصعوبة ⭐)
الأساسية — عرض اسم القسم الذي ينتمي إليه كل موظف:
SELECT e.name AS employee, d.name AS department, e.salary
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
الإخراج:
employee department salary
-------- ---------- --------
Zhang San Technology 15000.00
Li Si Technology 18000.00
Wang Wu Marketing 12000.00
Zhao Liu Finance 13000.00
Qian Qi Technology 20000.00
Sun Ba Marketing 11000.00
Wu Shi Finance 14000.00
ملاحظة: Zhou Jiu لا يظهر لأن department_id الخاص به هو NULL. INNER JOIN يحتفظ فقط بالصفوف التي تتطابق في كلا الجدولين.
مثال: استعلام عن تفاصيل الطلب (انضمام ثلاثة جداول) (الصعوبة ⭐⭐)
في سيناريوهات الأعمال الحقيقية، انضمام عدة جداول أمر شائع. استعلام عن اسم العميل واسم المنتج والسعر الفردي والإجمالي لكل طلب:
SELECT o.customer_name, p.name AS product,
p.price, o.quantity,
(p.price * o.quantity) AS total
FROM orders o
INNER JOIN products p ON o.product_id = p.id
ORDER BY total DESC;
الإخراج:
customer_name product price quantity total
------------- -------------- -------- -------- --------
Xiao Li iPad Air 4799.00 3 14397.00
Xiao Gang MacBook Pro 12999.00 1 12999.00
Xiao Wang iPhone 15 5999.00 2 11998.00
Xiao Ming iPhone 15 5999.00 1 5999.00
Xiao Gang iPhone 14 4999.00 1 4999.00
Xiao Hong Magic Keyboard 999.00 5 4995.00
Xiao Ming Apple Watch 2999.00 1 2999.00
Xiao Hong AirPods Pro 1899.00 2 3798.00
3. حالات الاستخدام الشائعة
الحالة 1: استعلام عن جميع موظفي قسم التكنولوجيا
أولاً ابحث عن معرف القسم عبر JOIN، ثم قم بالتصفية باستخدام WHERE:
SELECT e.name, e.salary, e.hire_date
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
WHERE d.name = 'Technology';
الإخراج:
name salary hire_date
------ -------- ----------
Zhang San 15000.00 2023-01-15
Li Si 18000.00 2022-06-01
Qian Qi 20000.00 2020-08-05
الحالة 2: عدد الموظفين في كل قسم
SELECT d.name AS department, COUNT(e.id) AS emp_count
FROM departments d
INNER JOIN employees e ON d.id = e.department_id
GROUP BY d.name;
الإخراج:
department emp_count
---------- ---------
Technology 3
Marketing 2
Finance 2
❓ أسئلة شائعة
س: أيهما أفضل أداءً، JOIN أم الاستعلام الفرعي؟ ج: بشكل عام، JOINs أفضل أداءً لأن محركات قواعد البيانات تحتوي على محسّنات متخصصة لـ JOINs. الاستعلامات الفرعية في بعض الحالات قد تُنتج جداول مؤقتة، مما يؤدي إلى أداء أسوأ قليلاً. ومع ذلك، يعتمد ذلك على حجم البيانات والفهرسة — استخدم
EXPLAINلفحص خطة التنفيذ.
س: ما الفرق بين ON و WHERE؟ ج:
ONهو شرط الانضمام الذي يُحدد كيفية إقران الجدولين؛WHEREهو شرط التصفية الذي يُحدد أي الصفوف يتم عرضها. لهما تأثيرات متشابهة في INNER JOIN، لكنهما يختلفان بشكل كبير في LEFT JOIN —ONلا يؤثر على الاحتفاظ بالجدول الأيسر، بينماWHEREيُصفّر الصفوف الفارغة.
س: هل أسماء الجداول المستعارة مطلوبة؟ ج: ليست مطلوبة، لكن يُوصى بها بشدة. أسماء الجداول المستعارة تجعل SQL أكثر إيجازًا، خاصة في الانضمامات متعددة الجداول حيث تُحسّن القراءة بشكل كبير.
س: ماذا يحدث إذا كان المفتاح الخارجي NULL؟ ج: INNER JOIN يستبعد ذلك الصف لأنه لا توجد بيانات مقابلة. إذا كنت تريد الاحتفاظ بتلك الصفوف، استخدم LEFT JOIN (يُغطى في الدرس التالي).
📖 ملخص
- قواعد البيانات تقسم البيانات إلى جداول لتجنب التكرار، وJOINs "تُجمّع" المعلومات الكاملة عند الاستعلام
- هناك ثلاثة أنواع من العلاقات بين الجداول: واحد لواحد، وواحد لعديد، وعديد لعديد؛ الأكثر شيوعًا هو واحد لعديد
- المفتاح الخارجي هو الجسر بين الجداول، يشير إلى المفتاح الأساسي في جدول آخر
- INNER JOIN يُرجع فقط الصفوف المتطابقة في كلا الجدولين، باستخدام
ONلتحديد شرط الانضمام - أسماء الجداول المستعارة (
AS) تجعل SQL أكثر إيجازًا؛ استخدمها دائمًا في الانضمامات متعددة الجداول
📝 تمارين
التمرين 1 (⭐): اكتب استعلامًا لعرض اسم العميل واسم المنتج وفئة المنتج لجميع الطلبات (يتطلب انضمام جدولي orders و products).
التمرين 2 (⭐⭐): اكتب استعلامًا لعرض متوسط الراتب لكل قسم، عرض فقط الأقسام التي يتجاوز متوسط رواتبها 12000 (تلميح: JOIN + GROUP BY + HAVING).
التمرين 3 (⭐⭐⭐): اكتب استعلامًا لعرض المبلغ الإجمالي الذي أنفقه كل عميل على المنتجات، مرتبة تنازليًا حسب المبلغ الإجمالي. اعرض اسم العميل وعدد الطلبات والمبلغ الإجمالي.
الدرس التالي
👉 08-join-types - أنواع الانضمامات موضحة: تعمّق في LEFT JOIN وRIGHT JOIN وFULL OUTER JOIN وCROSS JOIN وSELF JOIN، وأتقن استراتيجية اختيار نوع الانضمام المناسب!



