الـ Subqueries في SQL

الـ Subqueries (أو Nested Queries) هي استعلامات بتتكتب جوه استعلام تاني، وبتساعدك تقسم المشكلة لخطوات صغيرة ومفهومة. الاستعلام الداخلي بيتنفذ الأول، وبعد كده النتائج بتاعته بتستخدم في الاستعلام الخارجي.


المواضيع اللي بنغطيها:

  1. الـSubquery Basics (أساسيات الـ Subqueries)
  2. الـMulti-Stage Aggregation (التجميع على مراحل)
  3. الـSubqueries in Conditional Logic (استخدام Subqueries مع الشروط)
  4. الـJoining Subqueries (دمج Subqueries مع الجداول)
  5. الـSubqueries مع UNION

ملحوظة هامة

لما تيجي تعمل Subquery حاول تحطلها Alias عشان ميعملكش Errors مثال: Top Earners | HackerRank

SELECT MAX(earnings), COUNT(*)
FROM (
    SELECT employee_id, (months * Salary) AS earnings
    FROM Employee)
    AS Subquery
WHERE earnings = (
    SELECT MAX(earnings)
    FROM (
        SELECT (months * salary) AS earnings
        FROM Employee
    ) AS innerquery
) 

1. Subquery Basics

الـ Subquery بيشتغل زي استعلام مستقل، وبنتيجه بتستخدمها في استعلام أكبر. المثال ده بيجيب الحوادث اللي حصلت يوم الجمعة، وبعد كده بيعرض الحوادث اللي مالهاش حل.

مثال: Subquery في الـ FROM

SELECT sub.*
FROM (
      SELECT *
      FROM sf_crime_incidents_2014_01
      WHERE day_of_week = 'Friday'
     ) AS sub
WHERE sub.resolution = 'NONE';
  • الـInner Query: بيختار الحوادث اللي حصلت يوم الجمعة.
  • الـOuter Query: بيصفّي الحوادث اللي مالهاش حل (resolution = 'NONE').

2. Multi-Stage Aggregation (التجميع على مراحل)

لو محتاج تعمل عمليات حسابية على أكتر من مستوى، ممكن تستخدم Subqueries لتقسيم الخطوات.

مثال: متوسط عدد الحوادث لكل شهر ويوم في الأسبوع

SELECT LEFT(sub.date, 2) AS cleaned_month,
       sub.day_of_week,
       AVG(sub.incidents) AS average_incidents
FROM (
      SELECT day_of_week,
             date,
             COUNT(incidnt_num) AS incidents
      FROM sf_crime_incidents_2014_01
      GROUP BY day_of_week, date
     ) AS sub
GROUP BY cleaned_month, sub.day_of_week
ORDER BY cleaned_month, sub.day_of_week;
  • Inner Query: بيحسب عدد الحوادث لكل يوم وتاريخ.
  • Outer Query: بيحسب المتوسط الشهري للحوادث.

3. Subqueries in Conditional Logic (استخدام الشروط)

مثال: الحوادث اللي حصلت في أقدم يوم

SELECT *
FROM tutorial.sf_crime_incidents_2014_01
WHERE Date = (SELECT MIN(date)
              FROM tutorial.sf_crime_incidents_2014_01);
  • الشرح: الاستعلام الداخلي بيرجع أقل تاريخ، والاستعلام الخارجي بيعرض الحوادث اللي حصلت في اليوم ده.

مثال: الحوادث في أول 5 أيام

SELECT *
FROM sf_crime_incidents_2014_01
WHERE Date IN (
      SELECT TOP 5 date
      FROM sf_crime_incidents_2014_01
      ORDER BY date
     );
  • الشرح: الـ Subquery الداخلي بيرجع أول 5 تواريخ، والخارجي بيعرض الحوادث المرتبطة بيهم.

4. Joining Subqueries (دمج Subqueries مع الجداول)

مثال: دمج عدد الحوادث لكل يوم مع التفاصيل

SELECT incidents.*,
       sub.incidents AS incidents_that_day
FROM sf_crime_incidents_2014_01 AS incidents
JOIN (
      SELECT date,
             COUNT(incidnt_num) AS incidents
      FROM sf_crime_incidents_2014_01
      GROUP BY date
     ) AS sub
ON incidents.date = sub.date
ORDER BY sub.incidents DESC, incidents.time;
  • Inner Query: بيجمع عدد الحوادث لكل يوم.
  • Outer Query: بيعرض التفاصيل مع عدد الحوادث لليوم ده.

5. Subqueries مع UNION

مثال: دمج جزئين من نفس البيانات

SELECT COUNT(*) AS total_rows
FROM (
      SELECT *
      FROM crunchbase_investments_part1
 
      UNION ALL
 
      SELECT *
      FROM crunchbase_investments_part2
     ) AS sub;
  • الشرح: بيجمع البيانات من جدولين ويحسب إجمالي عدد الصفوف.

أمثلة عملية:

  1. عرض الحوادث غير المحلولة لفئة معينة:
SELECT *
FROM (
      SELECT *
      FROM sf_crime_incidents_2014_01
      WHERE category = 'Warrant Arrest'
     ) AS sub
WHERE sub.resolution = 'NONE';
  1. أقل 3 فئات في عدد الحوادث:
SELECT *
FROM sf_crime_incidents_2014_01
WHERE category IN (
      SELECT TOP 3 category
      FROM (
            SELECT category,
                   COUNT(*) AS num_incidents
            FROM sf_crime_incidents_2014_01
            GROUP BY category
            ORDER BY num_incidents ASC
           ) AS sub
     );
  1. تجميع الشركات المكتسبة والمؤسسة حسب ربع السنة:
SELECT COALESCE(acquired.quarter, founded.quarter) AS quarter,
       acquired.companies_acquired,
       founded.companies_founded
FROM (
      SELECT FORMAT(acquired_date, 'yyyy-Q') AS quarter,
             COUNT(*) AS companies_acquired
      FROM crunchbase_acquisitions
      GROUP BY FORMAT(acquired_date, 'yyyy-Q')
     ) AS acquired
FULL JOIN (
      SELECT FORMAT(founded_date, 'yyyy-Q') AS quarter,
             COUNT(*) AS companies_founded
      FROM crunchbase_funding
      GROUP BY FORMAT(founded_date, 'yyyy-Q')
     ) AS founded
ON acquired.quarter = founded.quarter
ORDER BY quarter;

نصايح لاستخدام Subqueries:

  1. ابدأ بالـ Inner Query: شغل الاستعلام الداخلي لوحده الأول عشان تتأكد من النتيجة.
  2. استخدم Aliases (أسماء مختصرة): سمي الـ Subqueries بتاعتك بأسماء واضحة.
  3. تنسيق الكود: اعمل Indentation عشان الكود يكون مقروء وسهل.

الـ Subqueries أداة قوية في SQL، بتسهل عليك تقسيم العمليات المعقدة وتخلي الاستعلامات أكتر مرونة وتنظيم.