إتقان SQL وتحسين الاستعلامات

أنماط SQL المتقدمة

4 دقيقة للقراءة

أتقن أنماط SQL المتقدمة التي تظهر في 90%+ من مقابلات هندسة البيانات. هذه الأنماط تشكل أساس التقييمات التقنية.

الغوص العميق في دوال النافذة

دوال النافذة هي المفهوم المتقدم الأكثر اختباراً في SQL. أتقن هذه الأنماط.

ROW_NUMBER، RANK، DENSE_RANK

-- سؤال المقابلة الكلاسيكي: إيجاد أعلى N لكل مجموعة
SELECT
    department,
    employee_name,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rn,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) as rnk,
    DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) as dense_rnk
FROM employees;
الدالة معالجة التعادل الفجوات
ROW_NUMBER أرقام مختلفة لا فجوات
RANK نفس الرقم فجوات بعد التعادل
DENSE_RANK نفس الرقم لا فجوات

نمط المقابلة: "احصل على أعلى 3 منتجات بالمبيعات في كل فئة"

WITH ranked AS (
    SELECT
        category_id,
        product_id,
        total_sales,
        DENSE_RANK() OVER (
            PARTITION BY category_id
            ORDER BY total_sales DESC
        ) as sales_rank
    FROM product_sales
)
SELECT * FROM ranked WHERE sales_rank <= 3;

LAG و LEAD

لتحليل السلاسل الزمنية والتسلسلية.

-- النمو شهر على شهر
SELECT
    month,
    revenue,
    LAG(revenue, 1) OVER (ORDER BY month) as prev_month_revenue,
    revenue - LAG(revenue, 1) OVER (ORDER BY month) as mom_change,
    ROUND(
        (revenue - LAG(revenue, 1) OVER (ORDER BY month)) * 100.0 /
        NULLIF(LAG(revenue, 1) OVER (ORDER BY month), 0), 2
    ) as mom_growth_pct
FROM monthly_revenue;

نمط المقابلة: "أوجد المستخدمين الذين انخفض نشاطهم من الشهر السابق"

المجاميع التراكمية والمتوسطات المتحركة

-- المجموع التراكمي والمتوسط المتحرك 7 أيام
SELECT
    date,
    daily_sales,
    SUM(daily_sales) OVER (ORDER BY date) as running_total,
    AVG(daily_sales) OVER (
        ORDER BY date
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) as moving_avg_7d
FROM daily_metrics;

مواصفات الإطار:

الصيغة المعنى
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW كل الصفوف من البداية للحالي
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW آخر 7 صفوف شاملة الحالي
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING نافذة منزلقة من 3 صفوف

تعبيرات الجدول الشائعة (CTEs)

CTEs تحسن القراءة وتمكن تفكيك الاستعلامات المعقدة.

هيكل CTE الأساسي

WITH
    daily_totals AS (
        SELECT
            date,
            SUM(amount) as total_amount
        FROM transactions
        GROUP BY date
    ),
    weekly_avg AS (
        SELECT
            AVG(total_amount) as avg_daily_amount
        FROM daily_totals
    )
SELECT
    d.date,
    d.total_amount,
    w.avg_daily_amount,
    d.total_amount - w.avg_daily_amount as variance
FROM daily_totals d
CROSS JOIN weekly_avg w;

CTEs التكرارية

أساسية للبيانات الهرمية وتجاوز الرسم البياني.

-- التسلسل الهرمي للموظفين (مخطط المنظمة)
WITH RECURSIVE org_tree AS (
    -- الحالة الأساسية: الرئيس التنفيذي (لا مدير)
    SELECT
        employee_id,
        name,
        manager_id,
        1 as level,
        CAST(name AS VARCHAR(1000)) as path
    FROM employees
    WHERE manager_id IS NULL

    UNION ALL

    -- الحالة التكرارية: الموظفين مع مديرين
    SELECT
        e.employee_id,
        e.name,
        e.manager_id,
        t.level + 1,
        t.path || ' -> ' || e.name
    FROM employees e
    INNER JOIN org_tree t ON e.manager_id = t.employee_id
)
SELECT * FROM org_tree ORDER BY level, name;

نمط المقابلة: "أوجد كل المرؤوسين (المباشرين وغير المباشرين) لمدير"

WITH RECURSIVE subordinates AS (
    SELECT employee_id, name, manager_id
    FROM employees
    WHERE manager_id = 101  -- المدير المستهدف

    UNION ALL

    SELECT e.employee_id, e.name, e.manager_id
    FROM employees e
    INNER JOIN subordinates s ON e.manager_id = s.employee_id
)
SELECT * FROM subordinates;

الربط المعقد وعمليات المجموعات

الربط الذاتي

-- أوجد الموظفين الذين يكسبون أكثر من مديرهم
SELECT
    e.name as employee,
    e.salary as employee_salary,
    m.name as manager,
    m.salary as manager_salary
FROM employees e
INNER JOIN employees m ON e.manager_id = m.employee_id
WHERE e.salary > m.salary;

EXCEPT و INTERSECT

-- أوجد العملاء الذين طلبوا في 2024 لكن ليس 2025
SELECT customer_id FROM orders WHERE YEAR(order_date) = 2024
EXCEPT
SELECT customer_id FROM orders WHERE YEAR(order_date) = 2025;

-- أوجد العملاء الذين طلبوا في كلا السنتين
SELECT customer_id FROM orders WHERE YEAR(order_date) = 2024
INTERSECT
SELECT customer_id FROM orders WHERE YEAR(order_date) = 2025;

أنماط التجميع

GROUPING SETS، CUBE، ROLLUP

-- مستويات تجميع متعددة في استعلام واحد
SELECT
    COALESCE(region, 'All Regions') as region,
    COALESCE(product_category, 'All Categories') as category,
    SUM(sales) as total_sales
FROM sales_data
GROUP BY GROUPING SETS (
    (region, product_category),
    (region),
    (product_category),
    ()
);
العبارة النتيجة
ROLLUP(a, b) (a,b), (a), ()
CUBE(a, b) (a,b), (a), (b), ()
GROUPING SETS((a,b), (a)) تلك التركيبات بالضبط

التجميع الشرطي

-- تحويل بدون كلمة PIVOT
SELECT
    product_id,
    SUM(CASE WHEN YEAR(sale_date) = 2024 THEN amount ELSE 0 END) as sales_2024,
    SUM(CASE WHEN YEAR(sale_date) = 2025 THEN amount ELSE 0 END) as sales_2025,
    COUNT(DISTINCT CASE WHEN status = 'returned' THEN order_id END) as return_count
FROM sales
GROUP BY product_id;

نصيحة المقابلة: عندما تُعطى مشكلة SQL معقدة، ابدأ بتحديد النمط المناسب (دالة نافذة، CTE تكراري، ربط ذاتي، إلخ). هذا الإطار يساعدك على هيكلة حلك بسرعة.

بعد ذلك، سنستكشف تحسين الاستعلامات وتحليل خطط التنفيذ. :::

اختبار

الوحدة 2: إتقان SQL وتحسين الاستعلامات

خذ الاختبار