PostgreSQL: أساسيات استعلام SELECT في PostgreSQL

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

1. ما ستتعلمه


2. القصة

Bob هو مهندس قواعد بيانات في منصة تجارة إلكترونية. المنصة تولد حوالي 10,000 طلب يومياً، متراكمة 100,000 سجل خلال آخر 30 يوماً. فريق العمليات يطلب منه:

  1. استعلام جميع طلبات آخر 30 يوماً، مرتبة حسب المبلغ من الأعلى إلى الأقل
  2. عرض 50 لكل صفحة، مع دعم التقسيم
  3. تصفية الطلبات الملغاة
  4. إزالة معرفات العملاء المكررة من العرض

يحتاج Bob إلى SELECT، WHERE، ORDER BY، LIMIT/OFFSET، و DISTINCT لإنجاز المهمة.


3. المفهوم: أساسيات SELECT

(1) نظرة عامة على صيغة SELECT

SQL
SELECT column1, column2, ...
FROM table_name
[WHERE condition]
[ORDER BY column [ASC|DESC] [NULLS FIRST|NULLS LAST]]
[LIMIT count [OFFSET start]];

SELECT هي عبا��ة SQL الأكثر استخداماً، تُستخدم لاسترجاع البيانات من جدول واحد أو أكثر.

(2) جميع الأعمدة مقابل أعمدة محددة

النمط الوصف الأداء موصى به لـ
SELECT * يعيد جميع الأعمدة أسوأ — ينقل بيانات زائدة استكشاف بنية الجدول بسرعة
SELECT col1, col2 يعيد الأعمدة المحددة فقط أفضل — I/O أقل استعلامات الإنتاج

(1) ▶ مثال

SQL
SELECT * FROM orders;

Output:

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

(2) ▶ مثال

SQL
SELECT order_id, customer_id, total_amount, order_date
FROM orders;

Output:

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

(3) الأسماء المستعارة للأعمدة

استخدم الكلمة المفتاحية AS (اختيارية) لإعطاء العمود أو التعبير اسماً مستعاراً لجعل النتائج أكثر قابلية للقراءة.

الاستخدام مثال الوصف
AS صريح price * qty AS subtotal موصى به — واضح
حذف AS price * qty subtotal صالح لكن أقل وض��حاً
اسم مستعار مقتبس total_amount AS "Order Total" مطلوب عندما يحتوي الاسم على مسافات أو أحرف كبيرة/صغيرة

(3) ▶ مثال

SQL
SELECT
  order_id,
  total_amount AS amount,
  order_date AS "Order Date",
  total_amount * 0.08 AS tax
FROM orders;

Output:

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

(4) التعبيرات والأعمدة المحسوبة

SELECT يمكنه أكثر من قراءة الأعمدة — يمكنه أيضاً كتابة تعبيرات حسابية، استدعاءات دوال، إلخ، لإنتاج أعمدة محسوبة.

(4) ▶ مثال

SQL
SELECT
  product_name,
  unit_price,
  unit_price * 1.1 AS price_with_tax,
  ROUND(unit_price * 1.1, 2) AS rounded_price
FROM products;

Output:

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

4. المفهوم: إزالة التكرار بـ DISTINCT

(1) إزالة التكرار الأساسية

DISTINCT تزيل الصفوف المكررة من مجموعة النتائج، تُستخدم عادةً لعد القيم الفريدة.

(5) ▶ مثال

SQL
SELECT DISTINCT customer_id
FROM orders;

Output:

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

(2) إزالة التكرار متعددة الأعمدة

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

العبارة نطاق إزالة التكرار
SELECT DISTINCT a إزالة التكرار حسب a
SELECT DISTINCT a, b إزالة التكرار حسب تركيبة (a, b)
SELECT DISTINCT ON (a) a, b PostgreSQL فقط: إزالة التكرار حسب a، الاحتفاظ بأول صف لكل مجموعة

(6) ▶ مثال

SQL
SELECT DISTINCT customer_id, order_status
FROM orders;

Output:

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

(3) DISTINCT ON: صيغة PostgreSQL فقط

DISTINCT ON (expr) تزيل التكرار حسب تعبير معين وتعيد الصف الأول في كل مجموعة (تقترن مع ORDER BY لتحديد أي صف).

(7) ▶ مثال

SQL
SELECT DISTINCT ON (customer_id)
  customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

Output:

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

5. المفهوم: تصفية WHERE

(1) معاملات المقارنة الأساسية

المعامل المعنى مثال
= يساوي order_status = 'completed'
<> أو != لا يساوي total_amount <> 0
> أكبر من total_amount > 100
< أصغر من total_amount < 50
>= أكبر من أو يساوي total_amount >= 100
<= أصغر من أو يساوي total_amount <= 500

(8) ▶ مثال

SQL
SELECT order_id, customer_id, total_amount
FROM orders
WHERE order_status = 'completed';

Output:

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

(2) تصفية التاريخ

مقارنة التاريخ هي إحدى أكثر احتياجات التصفية شيوعاً في التجارة الإلكترونية.

(9) ▶ مثال

SQL
SELECT order_id, customer_id, total_amount, order_date
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';

Output:

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

(3) دمج شروط متعددة

استخدم AND، OR، NOT لدمج الشروط. الأولوية: NOT > AND > OR؛ استخدم الأقواس للتحكم الصريح.

(10) ▶ مثال

SQL
SELECT order_id, total_amount, order_status
FROM orders
WHERE order_status = 'completed'
  AND total_amount > 500
  AND order_date >= '2025-01-01';

Output:

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

6. المفهوم: ترتيب ORDER BY

(1) الترتيب الأساسي

ORDER BY افتراضياً تصاعدي (ASC)؛ يمكنك تحديد تنازلي (DESC). يدعم الترتيب حسب اسم العمود، الاسم المستعار، أو موضع العمود.

نمط الترتيب الصيغة الوصف
تصاعدي ORDER BY col ASC افتراضي، ASC اختياري
تنازلي ORDER BY col DESC من الأعلى إلى الأقل
بالاسم المستعار ORDER BY amount DESC استخدم الاسم المستعار من SELECT
بالموضع ORDER BY 3 DESC حس�� العمود الثالث في قائمة SELECT (غير موصى به)

(11) ▶ مثال

SQL
SELECT order_id, customer_id, total_amount
FROM orders
ORDER BY total_amount DESC;

Output:

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

(2) ترتيب متعدد الأعمدة

مع الترتيب متعدد الأعمدة، تُرتب الصفوف حسب العمود الأول؛ تُكسر التعادلات بالعمود الثاني، وهكذا.

(12) ▶ مثال

SQL
SELECT order_id, order_status, total_amount
FROM orders
ORDER BY order_status ASC, total_amount DESC;

Output:

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

(3) NULLS FIRST / NULLS LAST: ميزة PostgreSQL

PostgreSQL تعامل NULL كأكبر قيمة افتراضياً (الأخيرة في الترتيب التصاعدي، الأولى في التنازلي). يمكنك التحكم الصريح في موضع NULL بـ NULLS FIRST و NULLS LAST.

الترتيب الموضع الافتراضي لـ NULL قابل للتعديل إلى
ASC NULL في النهاية NULLS FIRST ينقل NULL للبداية
DESC NULL في البداية NULLS LAST ينقل NULL للنهاية

(13) ▶ مثال

SQL
SELECT product_name, discount_rate
FROM products
ORDER BY discount_rate DESC NULLS LAST;

Output:

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

7. المفهوم: تقسيم الصفحات بـ LIMIT و FETCH FIRST

(1) LIMIT / OFFSET

LIMIT يحدد عدد الصفوف المعادة؛ OFFSET يتخطى عدداً معيناً من الصفوف. معاً ينفذان تقسيم الصفحات.

(14) ▶ مثال

SQL
SELECT order_id, customer_id, total_amount, order_date
FROM orders
WHERE order_status = 'completed'
ORDER BY total_amount DESC
LIMIT 50 OFFSET 100;

Output:

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

(2) FETCH FIRST: صيغة SQL القياسية

PostgreSQL تدعم أيضاً صيغة FETCH FIRST القياسية في SQL، متطابقة دلالياً مع LIMIT.

الصيغة المكافئ الوصف
LIMIT 10 FETCH FIRST 10 ROWS ONLY الشكل القياسي
LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH FIRST 10 ROWS ONLY شكل التقسيم القياسي

(15) ▶ مثال

SQL
SELECT order_id, customer_id, total_amount
FROM orders
ORDER BY total_amount DESC
OFFSET 100 ROWS
FETCH FIRST 50 ROWS ONLY;

Output:

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

(3) معادلة تقسيم الصفحات

المعامل الحساب
الصفحة page تبدأ من 1
حجم الصفحة size مثلاً 50
OFFSET (page - 1) * size
LIMIT size

(16) ▶ مثال

BASH
page=3
size=50
offset=$(( (page - 1) * size ))
psql -c "SELECT order_id, total_amount FROM orders ORDER BY total_amount DESC LIMIT $size OFFSET $offset;"

Output:

TEXT 📖 للعرض فقط
# psql command executed successfully

8. مخطط التدفق: ترتيب تنفيذ استعلام SELECT

100%
flowchart TD
    A[FROM orders] --> B[تصفية WHERE]
    B --> C[SELECT الأعمدة / التعبيرات]
    C --> D[DISTINCT]
    D --> E[ترتيب ORDER BY]
    E --> F[تقسيم LIMIT / OFFSET]
    F --> G[مجموعة النتائج]

    style A fill:#e1f5fe
    style B fill:#fff3e0
    style C fill:#e8f5e9
    style D fill:#f3e5f5
    style E fill:#fce4ec
    style F fill:#e0f2f1
    style G fill:#c8e6c9

9. مثال شامل

أكمل Bob متطلبات فريق العمليات: استعلام الطلبات المكتملة من آخر 30 يوماً، مقسمة تنازلياً حسب المبلغ، مع الإبلاغ عن عدد العملاء المميزين.

SQL
-- الخطوة 1: طلبات آخر 30 يوماً المكتملة، مقسمة تنازلياً حسب المبلغ
SELECT
  order_id,
  customer_id,
  total_amount,
  total_amount * 0.08 AS tax_amount,
  order_date AS "Order Date",
  order_status
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY total_amount DESC NULLS LAST
LIMIT 50 OFFSET 0;

-- الخطوة 2: عد العملاء المميزين في تلك الطلبات
SELECT COUNT(DISTINCT customer_id) AS unique_customers
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days';

-- الخطوة 3: آخر طلب لكل عميل (DISTINCT ON)
SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  total_amount,
  order_date
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY customer_id, total_amount DESC;

-- الخطوة 4: أفضل 10 طلبات مع الإجمالي المحسوب (السعر + الضريبة)
SELECT
  order_id,
  customer_id,
  total_amount,
  ROUND(total_amount * 1.08, 2) AS total_with_tax,
  order_date
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY total_with_tax DESC
FETCH FIRST 10 ROWS ONLY;

❓ أسئلة شائعة

س هل يمكنني استخدام SELECT * في الإنتاج؟
ج غير موصى به. SELECT * يعيد جميع الأعمدة، مضيفاً عبء نقل الشبكة والذاكرة، وقد يكسر منطق التطبيق عندما يتغير هيكل الجدول. اذكر دائماً الأعمدة التي تحتاجها صراحةً.
س ما الفرق بين DISTINCT و GROUP BY لإزالة التكرار؟
ج DISTINCT فقط تزيل الصفوف المكررة؛ GROUP BY يمكنها أيضاً عمل تجميع. إذا كنت فقط تزيل التكرار بدون تجميع، DISTINCT أكثر بديهية؛ استخدم GROUP BY عندما تحتاج التجميع.
س كيف يكون أداء تقسيم LIMIT OFFSET عند الإزاحات الكبي��ة؟
ج OFFSET يجب أن يتخطى أول N صف، لذا كلما كانت الإزاحة أكبر، كان أبطأ. لمجموعات البيانات الكبيرة، يوصى بتقسيم keyset (تصفية WHERE على مفتاح الترتيب)، مثلاً WHERE order_id > last_seen_id LIMIT 50.
س هل NULLS FIRST/LAST هي SQL قياسية؟
ج لا، إنها امتداد PostgreSQL. MySQL و SQL Server لا تدعمها؛ ستقلدها بـ CASE أو COALESCE.
س هل يمكن استخدام DISTINCT ON بدون ORDER BY؟
ج نحوياً نعم، لكن بدون ORDER BY، أي صف يُحتفظ به لكل مجموعة غير محدد. يجب أن تقترن بـ ORDER BY للحصول على نتائج قابلة للتوقع.
س هل يمكن استخدام الاسم المستعار للعمود في WHERE؟
ج لا. في ترتيب تنفيذ SQL، WHERE تعمل قبل SELECT، لذا الاسم المستعار غير موجود بعد. لكن الأسماء المستعارة يمكن استخدامها في ORDER BY، لأن ORDER BY تعمل بعد SELECT.
س هل FETCH FIRST و LIMIT متكافئان تماماً؟
ج متطابقان وظيفياً. FETCH FIRST هي صيغة SQL:2008 القياسية؛ LIMIT هي صيغة PostgreSQL التقليدية. للكود الجديد، FETCH FIRST يحسن قابلية النقل.
س هل يمكن لـ ORDER BY الإشارة إلى عمود ليس في قائمة SELECT؟
ج نعم. PostgreSQL تسمح لـ ORDER BY بالإشارة إلى عمود ليس في SELECT، لكن إذا تم استخدام DISTINCT أو GROUP BY، يجب أن يظهر عمود الترتيب في SELECT أو GROUP BY.

📖 ملخص


📝 تمارين

  1. ⭐ اكتب استعلاماً يختار product_name و unit_price من products، مرتباً تصاعدياً حسب السعر، معيداً أول 10 صفوف فقط.

  2. ⭐⭐ اكتب استعلاماً يختار طلبات آخر 7 أيام من orders، مصفياً لـ total_amount > 200، مرتباً حسب order_date DESC، مستخدماً FETCH FIRST 20 ROWS ONLY.

  3. ⭐⭐⭐ استخدم DISTINCT ON لاستعلام طلب كل customer_id صاحب أعلى مبلغ (تلميح: ORDER BY customer_id, total_amount DESC)، وعد كم من هؤلاء العملاء لديهم أقصى طلب فردي يتجاوز 1,000 دولار.

Web-Tutorial.com

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

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

100%