Kodokon kodokon.com

الاستعلامات الفرعية: WHERE وFROM وIN وEXISTS

ضمِّن استعلامًا داخل آخر للمقارنة مع قيمة مجمّعة، أو التصفية بناءً على مجموعة، أو اختبار الوجود.

9 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

إن الاستعلام الفرعي استعلام موضوع بين قوسين داخل استعلام آخر. وفي تعليمة واحدة، يجيب عن أسئلة مثل "الطلبات التي تفوق المتوسط" أو "العملاء الذين لديهم طلب واحد على الأقل". شغّل هذا السكربت في sqliteonline.com أو sqlite3 قبل أن تبدأ.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  amount REAL NOT NULL
);

INSERT INTO customers (id, name) VALUES
  (1, 'Alice'), (2, 'Karim'),
  (3, 'Mina'), (4, 'Paulo');

INSERT INTO orders (id, customer_id, amount)
VALUES
  (1, 1, 49.90), (2, 1, 15.00),
  (3, 2, 120.50), (4, 2, 80.00),
  (5, 3, 9.90), (6, 1, 200.00);
مجموعة البيانات: أربعة عملاء، ستة طلبات.

عند وضعه في WHERE، يجب أن يُرجِع الاستعلام الفرعي العددي (scalar) قيمة واحدة: صف واحد، عمود واحد. يحسبه المحرك أولًا، ثم يستخدمه مثل أيّ ثابت آخر. ولا يمكنك فعل ذلك باستخدام WHERE amount > AVG(amount) بسيطة، فهي ممنوعة في SQL.

SQL
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
  SELECT AVG(amount) FROM orders
);
الطلبات التي تفوق متوسط السلة (79.22).

يقارن IN عمودًا مع مجموعة القيم التي يُرجِعها الاستعلام الفرعي. ويختبر EXISTS ما إذا كان الاستعلام الفرعي المرتبط (correlated) (فهو يشير إلى c.id، وهو عمود من الاستعلام الخارجي) يُرجِع صفًا واحدًا على الأقل: يتوقف المحرك حالما يُعثر على أول تطابق.

SQL
SELECT name FROM customers
WHERE id IN (
  SELECT customer_id FROM orders
  WHERE amount > 100
);

SELECT c.name FROM customers AS c
WHERE EXISTS (
  SELECT 1 FROM orders AS o
  WHERE o.customer_id = c.id
);
IN: كبار المنفقين. EXISTS: العملاء النشطون.

في FROM، يتصرف الاستعلام الفرعي مثل جدول مؤقت، يُسمى الجدول المشتق (derived table)، ويجب أن يُمنح اسمًا مستعارًا. إنه الأداة الكلاسيكية للتجميع على خطوتين: أولًا إجمالي لكل عميل، ثم متوسط تلك الإجماليات.

SQL
SELECT ROUND(AVG(t.total), 2) AS avg_basket
FROM (
  SELECT customer_id, SUM(amount) AS total
  FROM orders
  GROUP BY customer_id
) AS t;
متوسط إجمالي السلة لكل عميل نشط: 158.43.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. كم قيمة يجب أن يُرجِع استعلام فرعي مستخدَم في amount > (...)؟
    • واحدة بالضبط
    • واحدة لكل صف من الجدول الخارجي
    • بقدر ما يشاء
  2. ما الميزة الرئيسية لـ EXISTS على IN؟
    • يمكنه إرجاع عدة أعمدة
    • يتوقف عند أول صف يُعثر عليه، دون تكوين المجموعة كاملة
    • يعمل دون استعلام فرعي
  3. ما الذي يجب أن يحمله دائمًا استعلام فرعي موضوع في FROM ليكون قابلًا للنقل في كل مكان؟
    • اسمًا مستعارًا، مثل AS t
    • جملة ORDER BY
    • فاصلة منقوطة داخلية