تمارين PostgreSQL التفاعلية › تعديل البيانات 4 / 7 السابق التالي

تعديل البيانات

الاستعلام (query) عن البيانات أمر جيد ومفيد، لكنك سترغب في مرحلة ما على الأرجح في إدخال بيانات إلى قاعدة بياناتك! يتناول هذا القسم إدراج المعلومات وتحديثها وحذفها. وتُعرف العمليات التي تغيّر بياناتك كهذه مجتمعةً باسم لغة معالجة البيانات (Data Manipulation Language) أو DML.

في الأقسام السابقة، كنا نعيد إليك نتائج الاستعلام الذي نفّذته. ولأن التعديلات التي نجريها في هذا القسم لا تُعيد أي نتائج استعلام، فإننا نعرض لك بدلًا من ذلك المحتوى المحدَّث للجدول المفترض أن تعمل عليه. ويمكنك مقارنته بالجدول المعروض في "النتائج المتوقعة" لترى كيف أبليت.

إن واجهت صعوبة في هذه الأسئلة، فأنصح بشدة بكتاب Learning SQL لـ Alan Beaulieu.

1. إدراج بعض البيانات في جدول

السؤال

يضيف النادي مرفقًا جديدًا — وهو منتجع صحي (spa). نحتاج إلى إضافته إلى جدول facilities. استخدم القيم التالية:

النتائج المتوقعة

facid name membercost guestcost initialoutlay monthlymaintenance
0 Tennis Court 1 5 25 10000 200
1 Tennis Court 2 5 25 8000 200
2 Badminton Court 0 15.5 4000 50
3 Table Tennis 0 5 320 10
4 Massage Room 1 35 80 4000 3000
5 Massage Room 2 35 80 4000 3000
6 Squash Court 3.5 17.5 5000 80
7 Snooker Table 0 5 450 15
8 Pool Table 0 5 400 15
9 Spa 20 30 100000 800

الإجابة

insert into cd.facilities
    (facid, name, membercost, guestcost, initialoutlay, monthlymaintenance)
    values (9, 'Spa', 20, 30, 100000, 800);

إن INSERT INTO ... VALUES هي أبسط طريقة لإدراج بيانات في جدول. ولا يوجد الكثير مما يُقال هنا: تُستخدم VALUES لبناء صف من البيانات، يُدرجه بيان INSERT في الجدول. الأمر بهذه البساطة.

ويمكنك أن ترى قسمين بين قوسين. الأول جزء من بيان INSERT، ويحدد الأعمدة التي نقدّم بيانات لها. والثاني جزء من VALUES، ويحدد البيانات الفعلية التي نريد إدراجها في كل عمود.

إذا كنا نُدرج بيانات في كل أعمدة الجدول، كما في هذا المثال، فتحديد أسماء الأعمدة صراحةً اختياري. فما دمت تملأ البيانات لكل أعمدة الجدول، بالترتيب الذي عُرّفت به عند إنشاء الجدول، يمكنك فعل شيء مثل ما يلي:

insert into cd.facilities values (9, 'Spa', 20, 30, 100000, 800);

وبوجه عام، في SQL التي ستُعاد استخدامها، أميل إلى تفضيل الصراحة وتحديد أسماء الأعمدة.

تلميح: يمكن استخدام INSERT لإدراج بيانات في جدول.

2. إدراج صفوف متعددة من البيانات في جدول

السؤال

في التمرين السابق، تعلمت كيف تضيف مرفقًا. والآن ستضيف عدة مرافق بأمر واحد. استخدم القيم التالية:

النتائج المتوقعة

facid name membercost guestcost initialoutlay monthlymaintenance
0 Tennis Court 1 5 25 10000 200
1 Tennis Court 2 5 25 8000 200
2 Badminton Court 0 15.5 4000 50
3 Table Tennis 0 5 320 10
4 Massage Room 1 35 80 4000 3000
5 Massage Room 2 35 80 4000 3000
6 Squash Court 3.5 17.5 5000 80
7 Snooker Table 0 5 450 15
8 Pool Table 0 5 400 15
9 Spa 20 30 100000 800
10 Squash Court 2 3.5 17.5 5000 80

الإجابة

insert into cd.facilities
    (facid, name, membercost, guestcost, initialoutlay, monthlymaintenance)
    values
        (9, 'Spa', 20, 30, 100000, 800),
        (10, 'Squash Court 2', 3.5, 17.5, 5000, 80);

يمكن استخدام VALUES لتوليد أكثر من صف واحد لإدراجه في جدول، كما ترى في هذا المثال. ونأمل أن يكون واضحًا ما يجري هنا: فناتج VALUES جدول، ويُنسخ ذلك الجدول إلى cd.facilities، الجدول المحدد في أمر INSERT.

ومع أنك سترى VALUES في أغلب الأحيان عند إدراج البيانات، فإن Postgres يتيح لك استخدام VALUES في أي موضع قد تستخدم فيه SELECT. وهذا منطقي: فناتج الأمرين جدول، غير أن VALUES أكثر راحة عند التعامل مع بيانات ثابتة.

وبالمثل، يمكن استخدام SELECT في أي موضع ترى فيه VALUES. وهذا يعني أنك تستطيع إدراج نتائج SELECT بـ INSERT. على سبيل المثال:

insert into cd.facilities
    (facid, name, membercost, guestcost, initialoutlay, monthlymaintenance)
    SELECT 9, 'Spa', 20, 30, 100000, 800
    UNION ALL
        SELECT 10, 'Squash Court 2', 3.5, 17.5, 5000, 80;

وسترى في تمارين لاحقة أننا نستخدم INSERT ... SELECT لتوليد بيانات تُدرج بناءً على المعلومات الموجودة أصلًا في قاعدة البيانات.

تلميح: يمكن استخدام VALUES لتوليد أكثر من صف واحد.

3. إدراج بيانات محسوبة في جدول

السؤال

لنحاول إضافة المنتجع الصحي إلى جدول facilities مرة أخرى. لكننا نريد هذه المرة توليد قيمة facid التالية تلقائيًا، بدلًا من تحديدها كثابت. استخدم القيم التالية لكل ما عدا ذلك:

النتائج المتوقعة

facid name membercost guestcost initialoutlay monthlymaintenance
0 Tennis Court 1 5 25 10000 200
1 Tennis Court 2 5 25 8000 200
2 Badminton Court 0 15.5 4000 50
3 Table Tennis 0 5 320 10
4 Massage Room 1 35 80 4000 3000
5 Massage Room 2 35 80 4000 3000
6 Squash Court 3.5 17.5 5000 80
7 Snooker Table 0 5 450 15
8 Pool Table 0 5 400 15
9 Spa 20 30 100000 800

الإجابة

insert into cd.facilities
    (facid, name, membercost, guestcost, initialoutlay, monthlymaintenance)
    select (select max(facid) from cd.facilities)+1, 'Spa', 20, 30, 100000, 800;

استخدمنا في التمارين السابقة VALUES لإدراج بيانات ثابتة في جدول facilities. لكن لدينا هنا مطلبًا جديدًا: معرّف مولَّد ديناميكيًا. وهذا تحسين حقيقي في جودة الحياة، إذ لا يلزمنا أن نبذل الجهد يدويًا لمعرفة أكبر معرّف حالي: فأمر SQL يفعل ذلك لنا.

ولأن عبارة VALUES تُستخدم فقط لتقديم بيانات ثابتة، نحتاج إلى استبدالها باستعلام بدلًا من ذلك. وعبارة SELECT بسيطة إلى حد كبير: فهناك استعلام فرعي داخلي يحسب facid التالية بناءً على أكبر معرّف حالي، والباقي مجرد بيانات ثابتة. وناتج البيان صف نُدرجه في جدول facilities.

ومع أن هذا يعمل جيدًا في مثالنا البسيط، فليس هكذا تُنفَّذ عادةً معرّفات تتزايد في العالم الحقيقي. فيوفّر Postgres أنواع SERIAL التي تُملأ تلقائيًا بالمعرّف التالي عند إدراج صف. وإلى جانب توفير الجهد، فإن هذه الأنواع أكثر أمانًا أيضًا: فبخلاف الإجابة المعروضة في هذا التمرين، لا حاجة للقلق من أن تولّد عمليات متزامنة المعرّف نفسه.

تلميح: يمكنك حساب البيانات التي تريد إدراجها باستخدام الاستعلامات الفرعية.

4. تحديث بعض البيانات الموجودة

السؤال

وقعنا في خطأ عند إدخال بيانات ملعب التنس الثاني. فكانت النفقة الأولية 10000 وليس 8000: عليك تعديل البيانات لتصحيح الخطأ.

النتائج المتوقعة

facid name membercost guestcost initialoutlay monthlymaintenance
0 Tennis Court 1 5 25 10000 200
1 Tennis Court 2 5 25 10000 200
2 Badminton Court 0 15.5 4000 50
3 Table Tennis 0 5 320 10
4 Massage Room 1 35 80 4000 3000
5 Massage Room 2 35 80 4000 3000
6 Squash Court 3.5 17.5 5000 80
7 Snooker Table 0 5 450 15
8 Pool Table 0 5 400 15

الإجابة

update cd.facilities
    set initialoutlay = 10000
    where facid = 1;

يُستخدم بيان UPDATE لتعديل البيانات الموجودة. وإن كنت على دراية باستعلامات SELECT، فقراءته سهلة إلى حد كبير: فعبارة WHERE تعمل بالطريقة نفسها تمامًا، وتتيح لنا تصفية مجموعة الصفوف التي نريد العمل عليها. ثم تُعدَّل هذه الصفوف وفق ما تحدده عبارة SET: في هذه الحالة، ضبط النفقة الأولية.

وعبارة WHERE مهمة للغاية. فمن السهل الخطأ فيها أو حتى إسقاطها، بنتائج كارثية. تأمل الأمر التالي:

update cd.facilities
    set initialoutlay = 10000;

لا توجد عبارة WHERE لتصفية الصفوف التي تهمنا. ونتيجة ذلك أن التحديث يجري على كل صف في الجدول! وهذا نادرًا ما يكون ما نريده.

تلميح: يمكنك تعديل البيانات الموجودة باستخدام بيان UPDATE.

5. تحديث صفوف وأعمدة متعددة في الوقت نفسه

السؤال

نريد زيادة سعر ملاعب التنس لكل من الأعضاء والضيوف. حدّث التكاليف لتكون 6 للأعضاء و30 للضيوف.

النتائج المتوقعة

facid name membercost guestcost initialoutlay monthlymaintenance
0 Tennis Court 1 6 30 10000 200
1 Tennis Court 2 6 30 8000 200
2 Badminton Court 0 15.5 4000 50
3 Table Tennis 0 5 320 10
4 Massage Room 1 35 80 4000 3000
5 Massage Room 2 35 80 4000 3000
6 Squash Court 3.5 17.5 5000 80
7 Snooker Table 0 5 450 15
8 Pool Table 0 5 400 15

الإجابة

update cd.facilities
    set
        membercost = 6,
        guestcost = 30
    where facid in (0,1);

تقبل عبارة SET قائمة قيم مفصولة بفواصل تريد تحديثها.

تلميح: يمكن لعبارة SET تحديث أعمدة متعددة.

6. تحديث صف بناءً على محتوى صف آخر

السؤال

نريد تعديل سعر ملعب التنس الثاني بحيث يكون أعلى بنسبة 10% من الأول. حاول فعل ذلك دون استخدام قيم ثابتة للأسعار، حتى نتمكن من إعادة استخدام البيان إن أردنا.

النتائج المتوقعة

facid name membercost guestcost initialoutlay monthlymaintenance
0 Tennis Court 1 5 25 10000 200
1 Tennis Court 2 5.5 27.5 8000 200
2 Badminton Court 0 15.5 4000 50
3 Table Tennis 0 5 320 10
4 Massage Room 1 35 80 4000 3000
5 Massage Room 2 35 80 4000 3000
6 Squash Court 3.5 17.5 5000 80
7 Snooker Table 0 5 450 15
8 Pool Table 0 5 400 15

الإجابة

update cd.facilities facs
    set
        membercost = (select membercost * 1.1 from cd.facilities where facid = 0),
        guestcost = (select guestcost * 1.1 from cd.facilities where facid = 0)
    where facs.facid = 1;

لا يمثّل تحديث الأعمدة بناءً على بيانات محسوبة صعوبة جوهرية كبيرة: فيمكننا فعل ذلك بسهولة إلى حد كبير باستخدام الاستعلامات الفرعية. ويمكنك أن ترى هذه المقاربة في إجابتنا المختارة. ومع تزايد عدد الأعمدة التي نريد تحديثها، قد تبدأ SQL القياسية تصبح مرهقة جدًا: فأنت لا تريد تحديد استعلام فرعي منفصل لكل تحديث من 15 تحديثًا مختلفًا للأعمدة. ويوفّر Postgres امتدادًا غير قياسي لـ SQL يُسمى UPDATE...FROM يعالج ذلك: فهو يتيح لك تقديم عبارة FROM لتوليد قيم تُستخدم في عبارة SET. والمثال أدناه:

update cd.facilities facs
    set
        membercost = facs2.membercost * 1.1,
        guestcost = facs2.guestcost * 1.1
    from (select * from cd.facilities where facid = 0) facs2
    where facs.facid = 1;

تلميح: ألقِ نظرة على UPDATE FROM في وثائق PostgreSQL.

7. حذف كل الحجوزات

السؤال

في إطار تنقية قاعدة بياناتنا، نريد حذف كل الحجوزات من جدول cd.bookings. فكيف نحقق ذلك؟

الإجابة

delete from cd.bookings;

يفعل بيان DELETE ما يقوله ببساطة: يحذف صفوفًا من الجدول. ونعرض هنا الأمر في أبسط صوره، دون أي قيود. وفي هذه الحالة، يحذف كل شيء من الجدول. ومن الواضح أنه ينبغي الحذر في عمليات الحذف والتأكد دائمًا من تقييدها — وسنرى كيف نفعل ذلك في التمرين التالي. وبديل عمليات DELETE غير المقيّدة هو ما يلي:

truncate cd.bookings;

يحذف TRUNCATE أيضًا كل شيء في الجدول، لكنه يفعل ذلك بآلية أساسية أسرع. وهو ليس آمنًا تمامًا في كل الظروف، لذا استخدمه بحكمة. وعند الشك، استخدم DELETE.

تلميح: ألقِ نظرة على بيان DELETE في وثائق PostgreSQL.

8. حذف عضو من جدول cd.members

السؤال

نريد إزالة العضو 37، الذي لم يحجز قط، من قاعدة بياناتنا. فكيف نحقق ذلك؟

النتائج المتوقعة

memid surname firstname address zipcode telephone recommendedby joindate
0 GUEST GUEST GUEST 0 (000) 000-0000 2012-07-01 00:00:00
1 Smith Darren 8 Bloomsbury Close, Boston 4321 555-555-5555 2012-07-02 12:02:05
2 Smith Tracy 8 Bloomsbury Close, New York 4321 555-555-5555 2012-07-02 12:08:23
3 Rownam Tim 23 Highway Way, Boston 23423 (844) 693-0723 2012-07-03 09:32:15
4 Joplette Janice 20 Crossing Road, New York 234 (833) 942-4710 1 2012-07-03 10:25:05
5 Butters Gerald 1065 Huntingdon Avenue, Boston 56754 (844) 078-4130 1 2012-07-09 10:44:09
6 Tracy Burton 3 Tunisia Drive, Boston 45678 (822) 354-9973 2012-07-15 08:52:55
7 Dare Nancy 6 Hunting Lodge Way, Boston 10383 (833) 776-4001 4 2012-07-25 08:59:12
8 Boothe Tim 3 Bloomsbury Close, Reading, 00234 234 (811) 433-2547 3 2012-07-25 16:02:35
9 Stibbons Ponder 5 Dragons Way, Winchester 87630 (833) 160-3900 6 2012-07-25 17:09:05
10 Owen Charles 52 Cheshire Grove, Winchester, 28563 28563 (855) 542-5251 1 2012-08-03 19:42:37
11 Jones David 976 Gnats Close, Reading 33862 (844) 536-8036 4 2012-08-06 16:32:55
12 Baker Anne 55 Powdery Street, Boston 80743 844-076-5141 9 2012-08-10 14:23:22
13 Farrell Jemima 103 Firth Avenue, North Reading 57392 (855) 016-0163 2012-08-10 14:28:01
14 Smith Jack 252 Binkington Way, Boston 69302 (822) 163-3254 1 2012-08-10 16:22:05
15 Bader Florence 264 Ursula Drive, Westford 84923 (833) 499-3527 9 2012-08-10 17:52:03
16 Baker Timothy 329 James Street, Reading 58393 833-941-0824 13 2012-08-15 10:34:25
17 Pinker David 5 Impreza Road, Boston 65332 811 409-6734 13 2012-08-16 11:32:47
20 Genting Matthew 4 Nunnington Place, Wingfield, Boston 52365 (811) 972-1377 5 2012-08-19 14:55:55
21 Mackenzie Anna 64 Perkington Lane, Reading 64577 (822) 661-2898 1 2012-08-26 09:32:05
22 Coplin Joan 85 Bard Street, Bloomington, Boston 43533 (822) 499-2232 16 2012-08-29 08:32:41
24 Sarwin Ramnaresh 12 Bullington Lane, Boston 65464 (822) 413-1470 15 2012-09-01 08:44:42
26 Jones Douglas 976 Gnats Close, Reading 11986 844 536-8036 11 2012-09-02 18:43:05
27 Rumney Henrietta 3 Burkington Plaza, Boston 78533 (822) 989-8876 20 2012-09-05 08:42:35
28 Farrell David 437 Granite Farm Road, Westford 43532 (855) 755-9876 2012-09-15 08:22:05
29 Worthington-Smyth Henry 55 Jagbi Way, North Reading 97676 (855) 894-3758 2 2012-09-17 12:27:15
30 Purview Millicent 641 Drudgery Close, Burnington, Boston 34232 (855) 941-9786 2 2012-09-18 19:04:01
33 Tupperware Hyacinth 33 Cheerful Plaza, Drake Road, Westford 68666 (822) 665-5327 2012-09-18 19:32:05
35 Hunt John 5 Bullington Lane, Boston 54333 (899) 720-6978 30 2012-09-19 11:32:45
36 Crumpet Erica Crimson Road, North Reading 75655 (811) 732-4816 2 2012-09-22 08:36:38

الإجابة

delete from cd.members where memid = 37;

هذا التمرين زيادة صغيرة على التمرين السابق. فبدلًا من حذف كل الحجوزات، نريد هذه المرة أن نكون أكثر تحديدًا، وأن نحذف عضوًا واحدًا لم يحجز قط. وللقيام بذلك، ما علينا سوى إضافة عبارة WHERE إلى أمرنا، نحدد فيها العضو الذي نريد حذفه. ويمكنك أن ترى أوجه الشبه مع بيانَي SELECT وUPDATE هنا. وهناك نقطة طريفة تستحق الانتباه. جرّب هذا الأمر، لكن باستبدال معرّف العضو 0. فقد أجرى هذا العضو حجوزات كثيرة، وستجد أن الحذف يفشل بخطأ يتعلق بانتهاك قيد مفتاح أجنبي (foreign key constraint). وهذا مفهوم مهم في قواعد البيانات العلائقية، فلنستكشفه قليلًا. المفاتيح الأجنبية آلية لتعريف علاقات بين أعمدة جداول مختلفة. وفي حالتنا نستخدمها لنحدد أن عمود memid في جدول bookings مرتبط بعمود memid في جدول members. وتحدد العلاقة (أو "القيد") أنه بالنسبة لحجز معيّن، يجب أن يكون العضو المحدد في الحجز موجودًا في جدول members. ومن المفيد أن تُنفّذ قاعدة البيانات هذا الضمان: فهو يعني أن الشيفرة التي تستخدم قاعدة البيانات يمكنها الاعتماد على وجود العضو. ويصعب (بل يستحيل) فرض ذلك في مستويات أعلى: فقد تتداخل عمليات متزامنة وتترك قاعدة بياناتك في حالة معطوبة. ويدعم PostgreSQL أنواعًا مختلفة من القيود التي تتيح لك فرض بنية على بياناتك. ولمزيد من المعلومات عن القيود، راجع وثائق PostgreSQL عن المفاتيح الأجنبية

تلميح: ألقِ نظرة على بيان DELETE في وثائق PostgreSQL.

9. الحذف بناءً على استعلام فرعي

السؤال

في تماريننا السابقة، حذفنا عضوًا معيّنًا لم يحجز قط. فكيف نجعل ذلك أعم، بحيث نحذف كل الأعضاء الذين لم يحجزوا قط؟

النتائج المتوقعة

memid surname firstname address zipcode telephone recommendedby joindate
0 GUEST GUEST GUEST 0 (000) 000-0000 2012-07-01 00:00:00
1 Smith Darren 8 Bloomsbury Close, Boston 4321 555-555-5555 2012-07-02 12:02:05
2 Smith Tracy 8 Bloomsbury Close, New York 4321 555-555-5555 2012-07-02 12:08:23
3 Rownam Tim 23 Highway Way, Boston 23423 (844) 693-0723 2012-07-03 09:32:15
4 Joplette Janice 20 Crossing Road, New York 234 (833) 942-4710 1 2012-07-03 10:25:05
5 Butters Gerald 1065 Huntingdon Avenue, Boston 56754 (844) 078-4130 1 2012-07-09 10:44:09
6 Tracy Burton 3 Tunisia Drive, Boston 45678 (822) 354-9973 2012-07-15 08:52:55
7 Dare Nancy 6 Hunting Lodge Way, Boston 10383 (833) 776-4001 4 2012-07-25 08:59:12
8 Boothe Tim 3 Bloomsbury Close, Reading, 00234 234 (811) 433-2547 3 2012-07-25 16:02:35
9 Stibbons Ponder 5 Dragons Way, Winchester 87630 (833) 160-3900 6 2012-07-25 17:09:05
10 Owen Charles 52 Cheshire Grove, Winchester, 28563 28563 (855) 542-5251 1 2012-08-03 19:42:37
11 Jones David 976 Gnats Close, Reading 33862 (844) 536-8036 4 2012-08-06 16:32:55
12 Baker Anne 55 Powdery Street, Boston 80743 844-076-5141 9 2012-08-10 14:23:22
13 Farrell Jemima 103 Firth Avenue, North Reading 57392 (855) 016-0163 2012-08-10 14:28:01
14 Smith Jack 252 Binkington Way, Boston 69302 (822) 163-3254 1 2012-08-10 16:22:05
15 Bader Florence 264 Ursula Drive, Westford 84923 (833) 499-3527 9 2012-08-10 17:52:03
16 Baker Timothy 329 James Street, Reading 58393 833-941-0824 13 2012-08-15 10:34:25
17 Pinker David 5 Impreza Road, Boston 65332 811 409-6734 13 2012-08-16 11:32:47
20 Genting Matthew 4 Nunnington Place, Wingfield, Boston 52365 (811) 972-1377 5 2012-08-19 14:55:55
21 Mackenzie Anna 64 Perkington Lane, Reading 64577 (822) 661-2898 1 2012-08-26 09:32:05
22 Coplin Joan 85 Bard Street, Bloomington, Boston 43533 (822) 499-2232 16 2012-08-29 08:32:41
24 Sarwin Ramnaresh 12 Bullington Lane, Boston 65464 (822) 413-1470 15 2012-09-01 08:44:42
26 Jones Douglas 976 Gnats Close, Reading 11986 844 536-8036 11 2012-09-02 18:43:05
27 Rumney Henrietta 3 Burkington Plaza, Boston 78533 (822) 989-8876 20 2012-09-05 08:42:35
28 Farrell David 437 Granite Farm Road, Westford 43532 (855) 755-9876 2012-09-15 08:22:05
29 Worthington-Smyth Henry 55 Jagbi Way, North Reading 97676 (855) 894-3758 2 2012-09-17 12:27:15
30 Purview Millicent 641 Drudgery Close, Burnington, Boston 34232 (855) 941-9786 2 2012-09-18 19:04:01
33 Tupperware Hyacinth 33 Cheerful Plaza, Drake Road, Westford 68666 (822) 665-5327 2012-09-18 19:32:05
35 Hunt John 5 Bullington Lane, Boston 54333 (899) 720-6978 30 2012-09-19 11:32:45
36 Crumpet Erica Crimson Road, North Reading 75655 (811) 732-4816 2 2012-09-22 08:36:38

الإجابة

delete from cd.members where memid not in (select memid from cd.bookings);

يمكننا استخدام الاستعلامات الفرعية لتحديد ما إذا كان ينبغي حذف صف أم لا. وهناك طريقتان قياسيتان لفعل ذلك. في إجابتنا المميزة، يُنتج الاستعلام الفرعي قائمة بكل معرّفات الأعضاء المختلفة في جدول cd.bookings. وإن لم يكن الصف في الجدول ضمن القائمة التي يولّدها الاستعلام الفرعي، حُذف. وبديل ذلك استخدام استعلام فرعي مترابط. فحيث يشغّل مثالنا السابق استعلامًا فرعيًا كبيرًا مرة واحدة، تحدد المقاربة المترابطة بدلًا من ذلك استعلامًا فرعيًا أصغر يُشغَّل مقابل كل صف.

delete from cd.members mems where not exists (select 1 from cd.bookings where memid = mems.memid);

وقد يكون للصيغتين المختلفتين خصائص أداء مختلفة. غير أن محرّك قاعدة بياناتك حرّ في أن يحوّل استعلامك في الخفاء ليُنفّذه بأسلوب مترابط أو غير مترابط، لذا قد يكون التنبؤ بالأمر صعبًا بعض الشيء.

تلميح: يمكنك الحذف بناءً على ناتج استعلام فرعي