MySQL: شرح مفصل لاستعلامات MySQL الفرعية وعبارة EXISTS

آخر تحديث: 2026-08-26

الاستعلامات الفرعية هي إحدى ميزات لغة SQL التي تتيح التداخل — حيث تُستخدم نتائج استعلام ما كشرط لاستعلام آخر.

يقدم هذا الدرس شرحًا منهجيًّا لأشكال الاستعلامات الفرعية المختلفة وكيفية تحسينها.

100%
graph TB
    A[Subquery Categories] --> B[Tag-Based Query<br/>Return a single value]
    A --> C[Liezi Query<br/>Return a column]
    A --> D[Row-based queries<br/>Return a line]
    A --> E[Table Child Query<br/>Back to Table]
    C --> C1[IN / NOT IN]
    C --> C2[ANY / ALL]
    E --> E1[FROM Derivation Table]
    A --> F[EXISTS<br/>Existence Check]
    A --> G[Correlated Subqueries<br/>Citation Format]

1. ما ستتعلمه



2. سيناريوهات واقعية

(1) المشكلة: لا يمكن تحقيق ذلك في خطوة واحدة

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

(2) حلول للاستعلامات الفرعية

SQL
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);


3. الاستعلام الكمومي القياسي

إرجاع صف واحد وعمود واحد.

▶ مثال: الاستعلام المُعلَّم

SQL
-- Employees with above-average salaries
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- The highest-paid employee
SELECT * FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);

-- Customers with the most recent orders
SELECT * FROM customers
WHERE id = (SELECT customer_id FROM orders ORDER BY order_date DESC LIMIT 1);
▶ جرّب الكود

4. استفسارات حول كتاب «ليزي»

تُرجع عمودًا واحدًا يحتوي على عدة صفوف. تُستخدم بالاقتران مع IN و NOT IN و ANY و ALL.

▶ مثال: الاستعلام الفرعي IN

SQL
-- Customers with orders
SELECT * FROM customers
WHERE id IN (SELECT DISTINCT customer_id FROM orders);

-- Customers with no orders
SELECT * FROM customers
WHERE id NOT IN (SELECT DISTINCT customer_id FROM orders WHERE customer_id IS NOT NULL);
▶ جرّب الكود

▶ مثال: الاستعلامات الفرعية ANY/ALL

SQL
-- Salary higher than Sales Any employee in the department(Higher than the minimum)
SELECT * FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE department = 'Sales');

-- Salary higher than Sales All employees in the department(Higher than the highest)
SELECT * FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE department = 'Sales');
▶ جرّب الكود

5. الاستعلام الفرعي EXISTS

تحقق مما إذا كان الاستعلام الفرعي يُرجع أي نتائج.

▶ مثال: EXISTS

SQL
-- Customers with orders
SELECT * FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);

-- Customers with no orders
SELECT * FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
▶ جرّب الكود

(1) مقارنة بين EXISTS و IN

البعد EXISTS IN
طريقة التنفيذ مقارنة الاستعلام الفرعي بالجدول صفًّا بصف تنفيذ الاستعلام الفرعي أولاً، ثم إجراء المقارنة
حالات الاستخدام جدول خارجي صغير، استعلام فرعي كبير جدول خارجي كبير، استعلام فرعي صغير
التعامل مع القيم NULL الأمان فخ "NOT IN" مع القيم NULL
الأداء أفضل بشكل عام أفضل عندما تكون مجموعة نتائج الاستعلام الفرعي صغيرة


6. استعلامات الجداول الفرعية (الجداول المشتقة)

الاستعلامات الفرعية كجداول مؤقتة.

▶ مثال: الاستعلام الفرعي FROM

SQL
-- The highest-paid person in each department
SELECT e.* FROM employees e
INNER JOIN (
    SELECT department, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department
) dept_max ON e.department = dept_max.department AND e.salary = dept_max.max_salary;

-- Customer Order Statistics
SELECT c.name, order_stats.total_orders, order_stats.total_amount
FROM customers c
INNER JOIN (
    SELECT customer_id, COUNT(*) AS total_orders, SUM(amount) AS total_amount
    FROM orders
    GROUP BY customer_id
) order_stats ON c.id = order_stats.customer_id;
▶ جرّب الكود

7. الاستعلامات الفرعية المترابطة

تشير الاستعلامات الفرعية إلى حقول من الجدول الخارجي.

▶ مثال: الاستعلامات الفرعية المترابطة

SQL
-- The highest-paid employee in each department
SELECT * FROM employees e1
WHERE salary = (
    SELECT MAX(salary) FROM employees e2
    WHERE e2.department = e1.department
);

-- Employees whose salaries are higher than the department average
SELECT * FROM employees e1
WHERE salary > (
    SELECT AVG(salary) FROM employees e2
    WHERE e2.department = e1.department
);
▶ جرّب الكود

8. تحسين الاستعلامات الفرعية

الاستراتيجية الوصف
استخدم عمليات «JOIN» بدلاً من الاستعلامات الفرعية عادةً ما يستطيع مُحسِّن MySQL التعامل مع هذا الأمر، لكن عمليات «JOIN» أكثر سهولة في الاستخدام
استخدم EXISTS بدلاً من IN عادةً ما تكون EXISTS أسرع عند التعامل مع مجموعات البيانات الكبيرة
تجنب الاستعلامات الفرعية المترابطة أعد صياغة الاستعلام باستخدام JOIN كلما أمكن ذلك
فهرسة الاستعلامات الفرعية فهرسة حقول الربط/التصفية في الاستعلامات الفرعية


❓ أسئلة شائعة

س أيهما أسرع، الاستعلام الفرعي أم عملية JOIN؟
ج بشكل عام، تكون عملية JOIN أسرع (حيث يمكن للمُحسِّن تحسينها بشكل أفضل). ومع ذلك، فإن الأمر يعتمد على توزيع البيانات؛ استخدم الأمر EXPLAIN للمقارنة.
س كم عدد مستويات الاستعلامات الفرعية التي يمكن تداخلها؟
ج يحدد MySQL عمق التداخل (عادةً 255 مستوى)، لكن يُنصح عمومًا بعدم تجاوز 3 مستويات.
س هل توجد مشكلة تتعلق بقيمة NULL عند استخدام NOT IN؟
ج نعم. NOT IN (1, 2, NULL) تُرجع دائمًا قيمة NULL. استخدم NOT EXISTS بدلاً من ذلك.
س أيهما أسرع، الاستعلام الفرعي أم عملية JOIN؟
ج يعتمد ذلك على حجم البيانات والفهارس؛ وبشكل عام، تعتبر عملية JOIN أكثر كفاءة. نوصي باستخدام EXPLAIN لمقارنة خطط التنفيذ الفعلية.
س كم عدد مستويات الاستعلامات الفرعية التي يمكن تداخلها؟
ج من الناحية النظرية، لا يوجد حد أقصى، لكن قابلية القراءة تصبح سيئة للغاية عند تجاوز ثلاثة مستويات؛ لذا يُنصح باستخدام CTE (جملة WITH) بدلاً من ذلك.

📖 ملخص


📝 تمارين

  1. المشكلة الأساسية (الصعوبة ⭐): استخدم الاستعلامات الفرعية للعثور على الموظفين الذين تزيد رواتبهم عن متوسط الراتب.

  2. مشكلة متقدمة (مستوى الصعوبة: ⭐⭐): استخدم EXISTS للعثور على العملاء الذين لم يسبق لهم تقديم أي طلب.

  3. سؤال التحدي (مستوى الصعوبة: ⭐⭐⭐): استخدم استعلام فرعي مرتبط لتحديد الموظف الذي يحصل على أعلى راتب في كل قسم.

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%