الاستعلامات الفرعية Subqueries في SQL
الاستعلام الفرعي هو استعلام واقعٌ ضمن استعلام آخر بهدف استخدام البيانات الناتجة عنه في الاستعلام الرئيسي الذي يحتويه، وغالبًا ما يكون الاستعلام الفرعي عبارة عن استعلام SELECT
، ويمكن استخدامه مع أي من استعلامات SELECT
أو INSERT
أو UPDATE
أو DELETE
.
استخدام الاستعلام الفرعي في استعلام SELECT
تحديد الاستعلام الفرعي كأحد الأعمدة
يُمكن تحديد أحد الأعمدة التي ستظهر بتنفيذ استعلام SELECT
من خلال الاستعلام الفرعي الذي يعيد قيمة وحيدة لكل سجل.
مثال
إن كانت الجداول الآتية موجودة في قاعدة البيانات:
الجدول الأول: السيارات cars
Colour | Price | Year | Company | Model | CarID |
---|---|---|---|---|---|
White | 22,500 | 2018 | KIA | Optima | 05081 |
Red | 25,995 | 2017 | KIA | Optima Hybrid | 05082 |
Red | 31,900 | 2018 | KIA | Stinger | 05083 |
Black | 31,990 | 2017 | KIA | Cadenza | 05084 |
Blue | 23,240 | 2018 | KIA | Niro | 05085 |
Grey | 14,200 | 2018 | KIA | Rio 5-Door | 05086 |
Blue | 18,200 | 2018 | KIA | Forte5 | 05087 |
Blue | 32,250 | 2017 | KIA | Soul EV | 05088 |
Red | 23,385 | 2017 | Nissan | Altima | 05089 |
White | 46,195 | 2017 | Nissan | Armada | 05090 |
Black | 33,495 | 2017 | Nissan | Maxima | 05091 |
Black | 30,715 | 2017 | Nissan | Murano | 05092 |
Grey | 31,265 | 2017 | Nissan | Pathfinder | 05093 |
White | 17,875 | 2017 | Nissan | Sentra | 05094 |
Red | 12,875 | 2017 | Nissan | Versa | 05095 |
الجدول الثاني: الزبائن customers
Remaining | CarID | Name | CustomerID |
---|---|---|---|
15,495 | 05091 | Mona Sinno | 0156 |
8,875 | 05095 | Ahmad Najjar | 0157 |
19,500 | 05081 | Kareem al-Hamdan | 0158 |
11,875 | 05094 | Mohammad Qadi | 0159 |
17,500 | 05081 | Rasha Mostafa | 0160 |
10,200 | 05087 | Jaber Hammad | 0161 |
19,990 | 05084 | Wessam Fattah | 0162 |
8,875 | 05094 | Shadi Sharif | 0163 |
12,500 | 05081 | Iman Mansour | 0164 |
6,875 | 05095 | Monther Zein | 0165 |
9,200 | 05087 | Rami Fares | 0166 |
18,240 | 05085 | Ammar Arab | 0167 |
إن تنفيذ الاستعلام الآتي:
SELECT CarID, Model, Company,
( SELECT count(*)
FROM customers
WHERE customers.CarID = cars.CarID
) AS NumberOrders
FROM cars;
سيعرض عدد المشترين لكل سيارة من السيارات بعمودٍ منفصلٍ (NumberOrders
) اعتمادًا على الاستعلام الفرعي المُنفَّذ في الجدول customers
بحيث يكون الرقم التسلسلي لطلب السيارة في جدول الزبائن مساويًا للرقم التسلسلي للسيارة في جدول السيارات، وستظهر النتائج:
NumberOrders | Company | Model | CarID |
---|---|---|---|
3 | KIA | Optima | 05081 |
0 | KIA | Optima Hybrid | 05082 |
0 | KIA | Stinger | 05083 |
1 | KIA | Cadenza | 05084 |
1 | KIA | Niro | 05085 |
0 | KIA | Rio 5-Door | 05086 |
2 | KIA | Forte5 | 05087 |
0 | KIA | Soul EV | 05088 |
0 | Nissan | Altima | 05089 |
0 | Nissan | Armada | 05090 |
1 | Nissan | Maxima | 05091 |
0 | Nissan | Murano | 05092 |
0 | Nissan | Pathfinder | 05093 |
2 | Nissan | Sentra | 05094 |
2 | Nissan | Versa | 05095 |
تحديد الاستعلام الفرعي كجدول جزئي من جدول أساسي
يمكن استخدام الاستعلام الفرعي للحصول على جدول جزئي مقتبس من جدول أساسي لاستخدامه في عبارة FROM
، كما في الاستعلام الآتي:
SELECT cars.CarID, cars.Model, result.CustomerID
FROM cars JOIN
(SELECT * FROM customers
WHERE CustomerID BETWEEN 0160 AND 0165
) AS result
ON cars.CarID = result.CarID;
إن تنفيذ هذا الاستعلام على الجدولين cars
و customers
في قاعدة البيانات سيؤدي إلى عرض الرقم التسلسلي ونوع السيارة من الجدول الناتج عن الربط ما بين جدول cars
وجدول فرعي يُؤخذ من جدول customers
بحيث يكون الرقم التسلسلي للزبون واقعًا ما بين الرقمين 0160 و 0165 وتسميته باسم result
إذ يتم الربط عندما يكون الرقم التسلسلي في الجدولين متساويًا، وتكون نتيجة تنفيذه:
CustomerID | Model | CarID |
---|---|---|
0160 | Optima | 05081 |
0164 | Optima | 05081 |
0162 | Cadenza | 05084 |
0161 | Forte5 | 05087 |
0163 | Sentra | 05094 |
0165 | Versa | 05095 |
استخدام الاستعلام الفرعي لتحديد قيم ضمن الشرط WHERE
تمكن الاستفادة من الاستعلام الفرعي لتحديد عدد من القيم لتوضع ضمن الشرط في عبارة WHERE
.
لمعرفة السيارات التي لم تُشترَ من قبل أيّ من الزبائن يمكن استخدام الاستعلام الآتي:
SELECT *
FROM cars
WHERE CarID NOT IN(
SELECT CarID
FROM customers
);
لتظهر النتائج:
Colour | Price | Year | Company | Model | CarID |
---|---|---|---|---|---|
Red | 25,995 | 2017 | KIA | Optima Hybrid | 05082 |
Red | 31,900 | 2018 | KIA | Stinger | 05083 |
Grey | 14,200 | 2018 | KIA | Rio 5-Door | 05086 |
Blue | 32,250 | 2017 | KIA | Soul EV | 05088 |
Red | 23,385 | 2017 | Nissan | Altima | 05089 |
White | 46,195 | 2017 | Nissan | Armada | 05090 |
Black | 30,715 | 2017 | Nissan | Murano | 05092 |
Grey | 31,265 | 2017 | Nissan | Pathfinder | 05093 |
ولمعرفة مجموع أسعار السيارات التي لم تُشترى يمكن إضافة الدالة التجميعيّة sum للاستعلام السابق ليصبح:
SELECT SUM(Price) AS Total
FROM cars
WHERE CarID NOT IN(
SELECT CarID
FROM customers
);
وتظهر النتيجة:
Total |
---|
235,905 |
حذف السجلات التي تحقق شرط محدد باستعلام فرعي
يمكن تحديد الشرط الذي ستحذف وفقًا له البيانات ضمن الاستعلام الفرعي في عبارة WHERE
.
فلحذف السيارات التي اشتراها أيّ من الزبائن في جدول customers
من الجدول cars
، يصبح الاستعلام بالشكل الآتي:
DELETE FROM cars
WHERE CarID IN(
SELECT CarID
FROM customers
);
ليصبح الجدول cars
في قاعدة البيانات على النحو الآتي:
Colour | Price | Year | Company | Model | CarID |
---|---|---|---|---|---|
Red | 25,995 | 2017 | KIA | Optima Hybrid | 05082 |
Red | 31,900 | 2018 | KIA | Stinger | 05083 |
Grey | 14,200 | 2018 | KIA | Rio 5-Door | 05086 |
Blue | 32,250 | 2017 | KIA | Soul EV | 05088 |
Red | 23,385 | 2017 | Nissan | Altima | 05089 |
White | 46,195 | 2017 | Nissan | Armada | 05090 |
Black | 30,715 | 2017 | Nissan | Murano | 05092 |
Grey | 31,265 | 2017 | Nissan | Pathfinder | 05093 |
تحديث قيم السجلات اعتمادًا على الاستعلام الفرعي
يمكن الاعتماد على الاستعلام الفرعي لتحديد القيم الجديدة التي ستوضع في الحقل المطلوب في استعلام UPDATE
، إن كان جدول الأقساط installments
الآتي موجودًا في قاعدة البيانات:
Date | CustomerID | Amount | TransactionID |
---|---|---|---|
04/11/2017 | 0156 | 7,000 | 0206 |
11/11/2017 | 0157 | 5,000 | 0207 |
01/11/2017 | 0158 | 9,000 | 0208 |
09/11/2017 | 0159 | 6,000 | 0209 |
24/11/2017 | 0160 | 8,000 | 0210 |
11/11/2017 | 0161 | 7,000 | 0211 |
04/11/2017 | 0162 | 9,000 | 0212 |
09/11/2017 | 0163 | 5,000 | 0213 |
01/11/2017 | 0164 | 8,000 | 0214 |
09/11/2017 | 0165 | 4,000 | 0215 |
04/11/2017 | 0166 | 5,000 | 0216 |
01/11/2017 | 0167 | 10,000 | 0217 |
فلتحديث قيمة المبلغ المتبقي في جدول الزبائن customers
بحسب القيمة المدفوعة في الجدول السابق يُنفذ الاستعلام الآتي:
UPDATE customers
SET remaining = remaining -
(SELECT Amount
FROM installments
WHERE customers.CustomerID = installments.CustomerID);
ليصبح الجدول كما يلي:
Remaining | CarID | Name | CustomerID |
---|---|---|---|
8,495 | 05091 | Mona Sinno | 0156 |
3,875 | 05095 | Ahmad Najjar | 0157 |
10,500 | 05081 | Kareem al-Hamdan | 0158 |
5,875 | 05094 | Mohammad Qadi | 0159 |
9,500 | 05081 | Rasha Mostafa | 0160 |
3,200 | 05087 | Jaber Hammad | 0161 |
10,990 | 05084 | Wessam Fattah | 0162 |
3,875 | 05094 | Shadi Sharif | 0163 |
4,500 | 05081 | Iman Mansour | 0164 |
2,875 | 05095 | Monther Zein | 0165 |
4,200 | 05087 | Rami Fares | 0166 |
8,240 | 05085 | Ammar Arab | 0167 |
إضافة سجلات في جدول من جدول آخر باستخدام الاستعلام الفرعي
تمكن إضافة بعض السجلات إلى الجدول من جدول آخر اعتمادًا على استعلام فرعي بحيث تتوافق أسماء الأعمدة المختارة ما بين الجدولين.
ليكن الجدول الآتي cheapCars
موجودًا في قاعدة البيانات:
Colour | Price | Year | Company | Model | CarID |
---|---|---|---|---|---|
Grey | 12,800 | 2014 | Nissan | Versa 1.6 S | 06002 |
WHITE | 14,700 | 2014 | KIA | Rio LX | 06003 |
Blue | 13,790 | 2014 | Mitsubishi | Mirage DE | 06004 |
لإضافة سيارات أخرى لهذا الجدول من الجدول الأساسي cars
يُمكن الاعتماد على الاستعلام الفرعي بالشكل الآتي:
INSERT INTO cheapCars
SELECT * FROM cars WHERE Price < 20000;
لاحظ : في في استعلام INSERT INTO
لم نضع أقواس حول الإستعلام الفرعي.
ليصبح الجدول:
Colour | Price | Year | Company | Model | CarID |
---|---|---|---|---|---|
Grey | 12,800 | 2014 | Nissan | Versa 1.6 S | 06002 |
WHITE | 14,700 | 2014 | KIA | Rio LX | 06003 |
Blue | 13,790 | 2014 | Mitsubishi | Mirage DE | 06004 |
Grey | 14,200 | 2018 | KIA | Rio 5-Door | 05086 |
Blue | 18,200 | 2018 | KIA | Forte5 | 05087 |
White | 17,875 | 2017 | Nissan | Sentra | 05094 |
Red | 12,875 | 2017 | Nissan | Versa | 05095 |
التوافقية
SQLServer | SQLite | Oracle | PostgreSQL | MySQL |
---|---|---|---|---|
نعم | نعم | نعم | نعم | نعم |