PostgreSQL: عمليات المجموعات والاستعلامات المدمجة في…

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

1. ما ستتعلمه


2. القصة

Bob هو محلل بيانات في منصة تجارة إلكترونية. المدير التنفيذي يسأله ثلاثة أسئلة:

  1. أي المنتجات كانت الأكثر مبيعاً في الربع الأول والثاني والثالث؟ (UNION ALL للدمج)
  2. أي المنتجات كانت الأكثر مبيعاً في كل ربع سنة؟ (INTERSECT = دائمة الخضرة)
  3. أي المنتجات باعت جيداً في الربع ا��أول لكن ليس في الربع الثاني؟ (EXCEPT = المتراجعة)

يدرك Bob أن هذه الأسئلة تتطابق تماماً مع عمليات المجموعات الثلاث في SQL: UNION، INTERSECT، EXCEPT.


3. المفهوم

(1) نظرة عامة على عمليات المجموعات

العملية المعنى إزالة التكرار التشبيه
UNION دمج مجموعات النتائج نعم A ∪ B
UNION ALL دمج مجموعات النتائج لا A ∪ B (مع التكرارات)
INTERSECT التقاطع نعم A ∩ B
INTERSECT ALL التقاطع لا A ∩ B (مع عدد التكرارات)
EXCEPT في A لكن ليس ف�� B نعم A - B
EXCEPT ALL في A لكن ليس في B لا A - B (مع عدد التكرارات)
100%
flowchart TD
    subgraph Union
        U1((A)) --- U2((B))
        U1 & U2 --> U3["A ∪ B"]
    end
    subgraph Intersect
        I1((A)) --- I2((B))
        I1 ∩ I2 --> I3["A ∩ B"]
    end
    subgraph Except
        E1((A)) --- E2((B))
        E1 - E2 --> E3["A - B"]
    end

    style U3 fill:#c8e6c9
    style I3 fill:#e1f5fe
    style E3 fill:#fff9c4

(2) UNION و UNION ALL

(1) ▶ مثال

SQL
SELECT product_id, product_name FROM hot_products_q1
UNION
SELECT product_id, product_name FROM hot_products_q2
UNION
SELECT product_id, product_name FROM hot_products_q3
ORDER BY product_id;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

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

(2) ▶ مثال

SQL
SELECT product_id, product_name, 'Q1' AS quarter FROM hot_products_q1
UNION ALL
SELECT product_id, product_name, 'Q2' AS quarter FROM hot_products_q2
UNION ALL
SELECT product_id, product_name, 'Q3' AS quarter FROM hot_products_q3
ORDER BY quarter, product_id;
TEXT 📖 للعرض فقط
 product_id | product_name | quarter
------------+--------------+---------
        101 | Widget Pro   | Q1
        102 | Gadget Mini  | Q1
        101 | Widget Pro   | Q2
        103 | Server Rack  | Q2
        101 | Widget Pro   | Q3
        104 | Cable Max    | Q3
السيناريو الموصى به السبب
دمج مصادر مختلفة بدون تكرارات UNION ALL لا حاجة لإزالة التكرار، أسرع
دمج مع تكرارات محتملة يجب إزالتها UNION إزالة تلقائية للتكرار
دمج ووسم المصدر UNION ALL + عمود وسم الاحتفاظ بالتكرارات وتمييز المصادر

(3) ▶ مثال

SQL
SELECT 'NA' AS region, COUNT(*) AS order_count, SUM(amount) AS total FROM orders_na
UNION ALL
SELECT 'EU', COUNT(*), SUM(amount) FROM orders_eu
UNION ALL
SELECT 'APAC', COUNT(*), SUM(amount) FROM orders_apac;

Output:

TEXT 📖 للعرض فقط
 count 
-------
     5
(1 row)

(3) INTERSECT و INTERSECT ALL

(4) ▶ مثال

SQL
SELECT product_id, product_name FROM hot_products_q1
INTERSECT
SELECT product_id, product_name FROM hot_products_q2
INTERSECT
SELECT product_id, product_name FROM hot_products_q3;
TEXT 📖 للعرض فقط
 product_id | product_name
------------+--------------
        101 | Widget Pro

Widget Pro هو المنتج الدائم الخضرة الوحيد الذي كان الأكثر مبيعاً كل ربع سنة.

(5) ▶ مثال

لنفترض أن المنتج 101 يظهر مرتين في قائمة الأكثر مبيعاً للربع الأول، مرة واحدة في الربع الثاني، و3 مرات في الربع الثالث:

SQL
SELECT product_id FROM hot_products_q1_detail
INTERSECT ALL
SELECT product_id FROM hot_products_q2_detail;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

INTERSECT ALL تعيد MIN(عدد التكرارات): المنتج 101 يعيد min(2, 1) = صف واحد.

العملية إزالة التكرار معالجة الصفوف المكررة الاستخدام النموذجي
INTERSECT نعم الاحتفاظ بصف واحد فقط إيجاد العناصر المشتركة
INTERSECT ALL لا الاحتفاظ بأقل عدد تكرارات مطابقة تردد التكرار بدقة

(6) ▶ مثال

SQL
SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2023
INTERSECT
SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2024
INTERSECT
SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2025;

Output:

TEXT 📖 للعرض فقط
CREATE TABLE

العملاء المخلصون الذين قدموا طلبات في جميع السنوات الثلاث المتتالية.

(4) EXCEPT و EXCEPT ALL

(7) ▶ مثال

SQL
SELECT product_id, product_name FROM hot_products_q1
EXCEPT
SELECT product_id, product_name FROM hot_products_q2;
TEXT 📖 للعرض فقط
 product_id | product_name
------------+--------------
        102 | Gadget Mini

Gadget Mini كان الأكثر مبيعاً في الربع الأول لكنه غاب عن قائمة الربع الثاني — تراجع.

(8) ▶ مثال

SQL
SELECT product_id, product_name FROM hot_products_q2
EXCEPT
SELECT product_id, product_name FROM hot_products_q1;
TEXT 📖 للعرض فقط
 product_id | product_name
------------+--------------
        103 | Server Rack

Server Rack دخل حديثاً قائمة الأكثر مبيعاً في الربع الثاني.

(9) ▶ مثال

SQL
SELECT product_id FROM order_items_2024
EXCEPT ALL
SELECT product_id FROM order_items_2025;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

إذا ظهر المنتج 101 خمس مرات في 2024 وثلاث مرات في 2025، EXCEPT ALL تعيد 5 - 3 = صفين.

العملية إزالة التكرار معالجة الصفوف المكررة الاستخدام النموذجي
EXCEPT نعم الاحتفاظ بصف واحد فقط إيجاد الاختلافات
EXCEPT ALL لا الاحتفاظ بفارق عدد التكرارات حساب الفائض الدقيق

4. نقاط رئيسية

(1) قواعد عمليات المجموعات

القاعدة الأولى: يجب أن يكون عدد الأعمدة متساوياً.

SQL
SELECT id, name FROM table_a
UNION
SELECT id, name, price FROM table_b;
TEXT 📖 للعرض فقط
ERROR: each UNION query must have the same number of columns

القاعدة الثانية: يجب أن تكون أنواع الأعمدة المتقابلة متوافقة.

القاعدة المتطلب نتيجة المخالفة
عدد الأعمدة يجب أن يكون متساوياً خطأ ترجمة
نوع العمود يجب أن يكون متوافقاً تحويل ضمني أو خطأ
اسم العمود يأخذ اسم عمود الاستعلام الأول انتبه للأسماء المستعارة

(10) ▶ مثال

SQL
SELECT product_id, product_name AS name FROM products_active
UNION ALL
SELECT sku AS product_id, title AS name FROM products_legacy
ORDER BY product_id;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) موضع ORDER BY في عمليات المجموعات

ORDER BY قد تظهر فقط بعد الاستعلام الأخير وتنطبق على مجموعة النتائج بالكامل.

(11) ▶ مثال

SQL
SELECT product_id, product_name FROM hot_products_q1
UNION ALL
SELECT product_id, product_name FROM hot_products_q2
ORDER BY product_id;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(12) ▶ مثال

SQL
(SELECT product_id FROM hot_products_q1
 EXCEPT
 SELECT product_id FROM hot_products_q2)
UNION ALL
(SELECT product_id FROM hot_products_q2
 EXCEPT
 SELECT product_id FROM hot_products_q3)
ORDER BY product_id;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

احسب الفرق أولاً، ثم ادمج. بدون أقواس، UNION لها أولوية أقل من INTERSECT/EXCEPT.

العملية الأولوية التجميع
INTERSECT الأعلى من اليسار لليمين
EXCEPT المتوسط من اليسار لليمين
UNION / UNION ALL المتوسط من اليسار لليمين

(3) معالجة NULL في عمليات المجموعات

تعامل عمليات المجموعات NULL كمتساوية (على عكس المقارنات العادية حيث NULL <> NULL).

(13) ▶ مثال

SQL
SELECT NULL AS val
UNION
SELECT NULL AS val;
TEXT 📖 للعرض فقط
 val
-----
 
(1 row)

NULLs المعاملتان تعاملان كمتطابقتين؛ UNION تزيل التكرار إلى صف واحد.

(14) ▶ مثال

SQL
SELECT NULL AS val
INTERSECT
SELECT NULL AS val;
TEXT 📖 للعرض فقط
 val
-----
 
(1 row)

NULL تطابق NULL؛ INTERSECT تعيد صفاً واحداً.

السيناريو سلوك NULL الفرق عن المقارنة العادية
UNION NULLs تعامل كمتساوية، تزال تكراراتها NULL = NULL العادية هي UNKNOWN
INTERSECT NULLs تعامل كمتساوية، تتطابق NULL = NULL العادية هي UNKNOWN
EXCEPT NULLs تعامل كمتساوية، تلغى NULL <> NULL العادية هي UNKNOWN

(4) عمليات المجموعات مقابل JOIN

(15) ▶ مثال

SQL
SELECT a.product_id
FROM hot_products_q1 a
INNER JOIN hot_products_q2 b ON a.product_id = b.product_id;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

مكافئة لـ:

SQL
SELECT product_id FROM hot_products_q1
INTERSECT
SELECT product_id FROM hot_products_q2;
البعد عملية المجموعات JOIN
الدلالات عملية مجموعات على الصفوف دمج الأعمدة
أعمدة المخرجات تأخذ أعمدة الجانب الأيسر أعمدة كلا الجدولين متاحة
إزالة التكرار UNION/INTERSECT/EXCEPT تزيل تلقائياً تحتاج DISTINCT يدوياً
مطابقة NULL NULL = NULL NULL <> NULL
الأداء البيانات الكبيرة قد ترتب لإزالة التكرار Hash Join المفهرس قد يكون أسرع
الأفضل لـ دمج/تقاطع/فرق مجموعات نتائج متشابهة الهيكل ضم جداول غير متجانسة لجلب الأعمدة

5. تطبيق عملي

(16) ▶ مثال

SQL
SELECT
  order_id   AS transaction_id,
  amount     AS credit,
  0          AS debit,
  'order'    AS type,
  created_at
FROM orders
UNION ALL
SELECT
  refund_id,
  0,
  refund_amount,
  'refund',
  created_at
FROM refunds
ORDER BY created_at;

Output:

TEXT 📖 للعرض فقط
CREATE TABLE

(17) ▶ مثال

SQL
SELECT user_id, email FROM registered_users
EXCEPT
SELECT user_id, email FROM activated_users;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(18) ▶ مثال

SQL
SELECT customer_id FROM order_items WHERE product_id = 101
INTERSECT
SELECT customer_id FROM order_items WHERE product_id = 102;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(19) ▶ مثال

SQL
SELECT 'retained' AS status, COUNT(*) AS cnt FROM (
  SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2024
  INTERSECT
  SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2025
) t
UNION ALL
SELECT 'churned', COUNT(*) FROM (
  SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2024
  EXCEPT
  SELECT customer_id FROM orders WHERE EXTRACT(YEAR FROM created_at) = 2025
) t;

Output:

TEXT 📖 للعرض فقط
 count 
-------
     5
(1 row)

(20) ▶ مثال

SQL
SELECT
  product_id,
  SUM(CASE WHEN quarter = 'Q1' THEN 1 ELSE 0 END) AS q1_count,
  SUM(CASE WHEN quarter = 'Q2' THEN 1 ELSE 0 END) AS q2_count,
  SUM(CASE WHEN quarter = 'Q3' THEN 1 ELSE 0 END) AS q3_count
FROM (
  SELECT product_id, 'Q1' AS quarter FROM hot_products_q1
  UNION ALL
  SELECT product_id, 'Q2' FROM hot_products_q2
  UNION ALL
  SELECT product_id, 'Q3' FROM hot_products_q3
) combined
GROUP BY product_id
ORDER BY product_id;

Output:

TEXT 📖 للعرض فقط
 count 
-------
     5
(1 row)

6. مثال شامل

تحليل Bob للمنتجات الأكثر مبيعاً عبر الأرباع — مخرج واحد للمنتجات الدائمة الخضرة والجديدة والمتراجعة:

SQL
WITH q1 AS (
  SELECT product_id, product_name FROM hot_products WHERE quarter = 'Q1'
),
q2 AS (
  SELECT product_id, product_name FROM hot_products WHERE quarter = 'Q2'
),
q3 AS (
  SELECT product_id, product_name FROM hot_products WHERE quarter = 'Q3'
),
evergreen AS (
  SELECT product_id, product_name, 'evergreen' AS trend FROM q1
  INTERSECT
  SELECT product_id, product_name, 'evergreen' FROM q2
  INTERSECT
  SELECT product_id, product_name, 'evergreen' FROM q3
),
new_q2 AS (
  SELECT product_id, product_name, 'new_in_q2' AS trend FROM q2
  EXCEPT
  SELECT product_id, product_name, 'new_in_q2' FROM q1
),
new_q3 AS (
  SELECT product_id, product_name, 'new_in_q3' AS trend FROM q3
  EXCEPT
  SELECT product_id, product_name, 'new_in_q3' FROM q2
),
churned_q2 AS (
  SELECT product_id, product_name, 'churned_in_q2' AS trend FROM q1
  EXCEPT
  SELECT product_id, product_name, 'churned_in_q2' FROM q2
),
churned_q3 AS (
  SELECT product_id, product_name, 'churned_in_q3' AS trend FROM q2
  EXCEPT
  SELECT product_id, product_name, 'churned_in_q3' FROM q3
)
SELECT * FROM evergreen
UNION ALL
SELECT * FROM new_q2
UNION ALL
SELECT * FROM new_q3
UNION ALL
SELECT * FROM churned_q2
UNION ALL
SELECT * FROM churned_q3
ORDER BY trend, product_id;
TEXT 📖 للعرض فقط
 product_id | product_name |    trend
------------+--------------+---------------
        101 | Widget Pro   | evergreen
        103 | Server Rack  | new_in_q2
        104 | Cable Max    | new_in_q3
        102 | Gadget Mini  | churned_in_q2
        103 | Server Rack  | churned_in_q3

7. تدفق تنفيذ عمليات المجموعات

100%
flowchart TD
    A["الاستعلام A"] --> C{العملية}
    B["الاستعلام B"] --> C
    C -->|UNION| D["دمج + إزالة التكرار"]
    C -->|UNION ALL| E["دمج (الحفاظ على التكرارات)"]
    C -->|INTERSECT| F["مطابقة + إزالة التكرار"]
    C -->|EXCEPT| G["A - B + إزالة التكرار"]
    D --> H["ORDER BY (اختياري)"]
    E --> H
    F --> H
    G --> H
    H --> I["النتيجة النهائية"]

    style D fill:#c8e6c9
    style F fill:#e1f5fe
    style G fill:#fff9c4
الخطوة العملية الوصف
1 تنفيذ كل استعلام فرعي ينفذ بشكل مستقل؛ مجموعات النتائج يجب أن تشترك في الهيكل
2 عملية المجموعات UNION/INTERSECT/EXCEPT
3 إزالة التكرار (إذا لزم) UNION/INTERSECT/EXCEPT تزيل التكرار افتراضياً
4 ORDER BY تنطبق على مجموعة النتائج النهائية
5 LIMIT تحديد صفوف المخرجات النهائية

❓ أسئلة شائعة

س أيهما أسرع، UNION أم UNION ALL؟
ج UNION ALL أسرع لأنها لا تزيل التكرار. إذا كنت متأكداً من عدم وجود تكرارات، أو لا تحتاج إزالة التكرار، فضّل UNION ALL.
س اسم أي عمود تستخدمه عملية المجموعات؟
ج تأخذ اسم عمود الاستعلام الأول (أو الاسم المستعار). لتوحيدها، اكتب الاسم المستعار في الاستعلام الأول.
س هل يمكن استخدام عملية المجموعات في استعلام فرعي؟
ج نعم. SELECT * FROM (A UNION B) AS t صالحة؛ ضعها بين أقواس وأضف اسماً مستعار��ً.
س ما هي أولوية عمليات المجموعات المتعددة؟
ج INTERSECT > (EXCEPT = UNION). INTERSECT لها أعلى أولوية؛ EXCEPT و UNION في نفس المستوى. استخدم الأقواس لجعل الأولوية صريحة.
س هل NULL حقاً تساوي NULL في عمليات المجموعات؟
ج نعم. في عمليات المجموعات تعامل NULLs كمتساوية — هذا سلوك SQL قياسي، على عكس المقارنات العادية حيث NULL = NULL هي UNKNOWN.
س متى أستخدم عملية المجموعات بدلاً من JOIN؟
ج استخدم عملية المجموعات عندما تحتاج فقط اختبار "موجود / غير موجود" ولا تحتاج الأعمدة المضمومة؛ استخدم JOIN عندما تحتاج دمج أعمدة من كلا الجدولين. عمليات المجموعات تقرأ بشكل أكثر بديهية؛ JOIN أكثر مرونة.

📖 ملخص


📝 تمارين

  1. ⭐ استخدم UNION ALL لدمج جداول طلبات 2024 و 2025، مضيفاً عمود وسم السنة، مرتباً تنازلياً حسب المبلغ.
  2. ⭐ استخدم EXCEPT لإيجاد المستخدمين الموجودين في جدول customers لكن ليس في جدول active_users.
  3. ⭐⭐ استخدم INTERSECT لإيجاد معرفات المنتجات الأكثر مبيعاً التي تظهر في جميع الأرباع الثلاثة، واضمم جدول products لإخراج أسماء المنتجات.
  4. ⭐⭐ استخدم CTE + EXCEPT لتحليل تراجع العملاء: العملاء الذين لديهم طلبات في 2024 لكن لا شيء في 2025.
  5. ⭐⭐⭐ اكتب عبارة SQL واحدة تجمع UNION ALL + INTERSECT + EXCEPT: أخرج تقريراً يغطي ثلاث فئات منتجات (دائمة الخضرة / جديدة / متراجعة)، كل منها بعمود وسم، وأخيراً استخدم GROUP BY لعد المنتجات في كل فئة.
Web-Tutorial.com

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

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

100%