اذهب إلى المحتوى

لدى التعامل مع قاعدة بيانات، قد تضطر أحيانًا لتعديل بيانات كانت مدرجة من قبل في جدول أو أكثر. كأن تُضطر مثلًا لتصحيح خطأ إملائي في إدخال معين أو إضافة معلومات جديدة إلى سجل غير مكتمل. وتوفّر لغة الاستعلام البنيوية المعروفة بـ SQL الكلمة المفتاحية UPDATE، التي تُمكّن المستخدمين من تعديل البيانات الموجودة في جدول ما.

يشرح هذا المقال كيفية استعمال الصيغة UPDATE في SQL لتعديل البيانات في جدول واحد أو عدة جداول مرتبطة ببعضها. كما يتناول الطريقة التي تتعامل بها SQL مع عمليات UPDATE التي قد تتعارض مع قيود المفتاح الخارجي.

مستلزمات العمل

لمتابعة الخطوات في هذا المقال، ستحتاج إلى جهاز حاسوب يُشغّل أحد أنواع أنظمة إدارة قواعد البيانات العلاقية RDBMS التي تستخدم SQL. وقد اختبرنا الأوامر البرمجية والأمثلة في هذا المقال مستخدمين البيئة التالية:

  • خادم عامل على توزيعة أوبنتو، مع مستخدم ذو صلاحيات مسؤول مختلف عن المستخدم الجذر، وجدار حماية مكوّن باستخدام UFW، ويمكنك إعداد الخادم بالاستعانة بمقالنا  كيفية تثبيت توزيعة أوبنتو من لينكس بأبسط طريقة.
  • MySQL مثبتة ومؤمنة على الخادم، كما هو موضح في المقال كيفية تثبيت MySQL على أوبونتو. وقد نفذنا خطوات هذا المقال باستخدام مستخدم MySQL مختلف عن المستخدم الجذر، ومُنشأ وفق الطريقة الموضحة في الخطوة 3 من هذا المقال.

ملاحظة: تجدر الإشارة إلى أنّ الكثير من أنظمة إدارة قواعد البيانات العلاقية لها تقديماتها الفريدة من لغة SQL. فبالرغم من كون الأوامر المُقدمة في هذا المقال ستعمل مع معظم هذه الأنظمة، ولكن قد تجد بعض الاختلافات في الصيغة أو الناتج عند تنفيذها على أنظمة مختلفة عن MySQL.

وبالعودة إلى مستلزمات العمل، ستحتاج أيضًا إلى قاعدة بيانات مع بعض الجداول المُحمّلة ببعض البيانات التجريبية النموذجية لتتمكن من التدرب على تحديث بيانات SQL. وإذا لم تكن متوفرة لديك، يمكنك مراجعة مقال الاتصال بـ MySQL وإعداد قاعدة بيانات تجريبية نموذجية للمزيد من التفاصيل حول كيفية الاتصال بخادم MySQL وإنشاء قاعدة البيانات التجريبية المُستخدمة في أمثلة هذا المقال.

الاتصال بـ MySQL وإعداد قاعدة بيانات تجريبية نموذجية

إذا كان نظام قاعدة بيانات SQL الخاص بك يعمل على خادم عن بُعد، اتصل بالخادم مُستخدمًا بروتوكول SSH من جهازك المحلي على النحو:

$ ssh user@your_server_ip

ثم افتح واجهة سطر الأوامر في خادم MySQL، مُستبدلًا user باسم حساب مستخدم MySQL الخاص بك:

$ mysql -u user -p

أنشئ قاعدة بيانات باسم updateDB:

mysql> CREATE DATABASE updateDB;

وبمجرّد إنشاء قاعدة البيانات بنجاح ستحصل على خرجٍ كالتالي:

الخرج
Query OK, 1 row affected (0.01 sec)

ولاختيار قاعدة البيانات updateDB، نفّذ تعليمة USE التالية:

mysql> USE updateDB;
الخرج
Database changed

وبعد اختيارك لقاعدة البيانات updateDB، أنشئ بعض الجداول ضمنها. ولتوضيح الأمثلة في هذا المقال، تخيّل أنّك تدير وكالة مواهب، وقد قررت تتبّع عملائك وأدائهم عبر قاعدة بيانات SQL، وبأنّك تعتزم البدء بجدولين: الجدول الأوّل لتخزين معلومات عن عملائك. وقد حددت أنّ هذا الجدول يحتاج إلى أربعة أعمدة:

  • clientID: مُعرّف كل عميل، مُعبرًا عنه بنمط بيانات الأعداد الصحيحة int، كما سيُمثّل هذا العمود المفتاح الرئيسي للجدول، بحيث تمثل كل قيمة منه دور المُعرف الفريد للسجل المُرتبط بها.
  • name: اسم كل عميل، مُعبرًا عنه بنمط بيانات varchar بحد أقصى 20 محرفًا.
  • routine: وصف مُختصر لنوع الأداء الرئيسي لكل عميل، مُعبرًا عنه بنمط بيانات varchar بحد أقصى 30 محرفًا.
  • performanceFee: عمود لتسجيل رسوم الأداء القياسية لكل عميل، يستخدم نمط البيانات decimal وتُحدد القيم في هذا العمود بحد أقصى قدره خمسة أرقام، بواقع رقمين على يمين الفاصلة العشرية. وبالتالي، تتراوح القيم المسموح بها من -999.99 إلى 999.99.

أنشئ جدولًا باسم clients يشمل هذه الأعمدة الأربعة:

mysql> CREATE TABLE clients
mysql> (clientID int PRIMARY KEY,
mysql> name varchar(20),
mysql> routine varchar(30),
mysql> standardFee decimal (5,2)
mysql> );

أمّا الجدول الثاني فسيكون مخصصًا لتخزين بيانات حول أداء عملائك في مكان عرض محدد محليًا. وبفرض أنك ارتأيت بأنّ هذا الجدول يتطلّب خمسة أعمدة:

  • showID: بمثابة عمود clientID، إذ سيحتفظ هذا العمود بمُعرّف فريد لكل عرض، مُعبرًا عنه بنمط بيانات الأعداد الصحيحة int. كما سيمُثّل هذا العمود المفتاح الرئيسي لجدول العروض shows.
  • showDate: تاريخ كل عرض. يُعبر عن قيم هذا العمود باستخدام نمط بيانات التواريخ date الذي يستخدم الصيغة YYYY-MM-DD (خانتين لليوم وخانتين للشهر وأربع خانات للسنة).
  • clientID: مُعرّف العميل الذي يؤدي في العرض، مُعبرًا عنه كعدد صحيح.
  • attendance: عدد الحضور في كل عرض، مُعبرًا عنه كعدد صحيح.
  • ticketPrice:سعر تذكرة الدخول لكل عرض. يستخدم هذا العمود نمط البيانات decimal وتُحدد القيم في هذا العمود بحد أقصى قدره خمسة أرقام، بواقع رقمين على يمين الفاصلة العشرية. وبالتالي، تتراوح القيم المسموح بها من- 999.99 إلى 999.99.

ولضمان أنّ عمود clientID لن يتضمّن سوى قيم تُمثّل مُعرّفات عملاء صالحة، قررتَ تطبيق قيد مفتاح خارجي عليه بحيث يُشير إلى عمود clientID في جدول clients. يُعد قيد المفتاح الخارجي طريقة لتحديد علاقة بين جدولين، إذ يفرض أن تكون القيم في العمود المُطبّق عليه موجودة بالفعل في العمود المُشار إليه. في المثال القادم، يشترط قيد FOREIGN KEY أن تكون كل قيمة تُضاف إلى عمود clientID في جدول shows مُسجلة مسبقًا في عمود clientID بجدول clients.

أنشئ جدولًا باسم clients يتضمن هذه الأعمدة الخمسة:

mysql> CREATE TABLE shows
mysql> (showID int PRIMARY KEY,
mysql> showDate date,
mysql> clientID int,
mysql> attendance int,
mysql> ticketPrice decimal (4,2),
mysql> CONSTRAINT client_fk
mysql> FOREIGN KEY (clientID)
mysql> REFERENCES clients(clientID)
mysql> );

ومن الجدير بالملاحظة أنّ هذا المثال يوفّر اسمًا لقيد المفتاح الخارجي، ألا وهو: client_fk. إذ تُنشئ MySQL تلقائيًا اسمًا لأي قيد تضيفه، إلّا أنّ تحديد اسم من قبلنا في هذه الحالة سيكون مفيدًا عندما نحتاج للإشارة إلى هذا القيد لاحقًا.

بعد ذلك، نفّذ تعليمة INSERT INTO التالية لملء جدول العملاء clients بخمسة سجلات من البيانات النموذجية:

mysql> INSERT INTO clients
mysql> VALUES
mysql> (1, 'Fares', 'song and dance', 180),
mysql> (2, 'Camal', 'standup', 99.99),
mysql> (3, 'Karam', 'standup', 45),
mysql> (4, 'Wael', 'song and dance', 200),
mysql> (5, 'Ahmad', 'trained squirrel', 79.99);

ثم نفّذ تعليمة INSERT INTO أخرى لملء جدول shows بعشرة سجلات من البيانات النموذجية:

mysql> INSERT INTO shows
mysql> VALUES
mysql> (1, '2019-12-25', 4, 124, 15),
mysql> (2, '2020-01-11', 5, 84, 29.50),
mysql> (3, '2020-01-17', 3, 170, 12.99),
mysql> (4, '2020-01-31', 5, 234, 14.99),
mysql> (5, '2020-02-08', 1, 86, 25),
mysql> (6, '2020-02-14', 3, 102, 39.5),
mysql> (7, '2020-02-15', 2, 101, 26.50),
mysql> (8, '2020-02-27', 2, 186, 19.99),
mysql> (9, '2020-03-06', 4, 202, 30),
mysql> (10, '2020-03-07', 5, 250, 8.99);

وبذلك، غدوتَ جاهزًا لمتابعة باقي المقال وبدء تعلم كيفية تحديث البيانات باستخدام لغة الاستعلام البنيوية SQL.

تحديث البيانات في جدول واحد

تبدو الصيغة العامّة لتعليمة UPDATE على النحو:

mysql> UPDATE table_name
mysql> SET column_name = value_expression
mysql> WHERE conditions_apply;

تُتبع الكلمة المفتاحية UPDATE باسم الجدول الذي يحتوي على البيانات المُراد تحديثها. ثم تأتي بنية SET، والتي تُحدّد بيانات العمود المُراد تحديثها وكيفية التحديث. تُعدّ بنية SET وكأنها تعيين لقيم العمود المُحدد لتُصبح مطابقة لأي تعبير قيمة تُقدّمه.

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

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

لتوضيح كيفية تعامل SQL مع عمليات التحديث UPDATE، ابدأ بالاطلاع على كافة البيانات في جدول العملاء clients. يشتمل الاستعلام التالي على علامة النجمة (*)، وهي اختصار في SQL يُمثّل كل عمود في الجدول، لذا سيُعيد هذا الاستعلام جميع البيانات من كل عمود في جدول clients.

$ SELECT * FROM clients;
الخرج
+----------+------------+------------------+-------------+
| clientID | name       | routine          | standardFee |
+----------+------------+------------------+-------------+
|        1 | Fares     | song and dance   |      180.00 |
|        2 | Camal  | standup          |       99.99 |
|        3 | Karam | standup          |       45.00 |
|        4 | Wael      | song and dance   |      200.00 |
|        5 | Ahmad        | trained squirrel |       79.99 |
+----------+------------+------------------+-------------+
5 rows in set (0.00 sec)

لنفترض على سبيل المثال أنّك لاحظت وجود خطأ في تهجئة الاسم Kamal، إذ يجب أن يبدأ بحرف K ولكنه في الجدول يبدأ بحرف C، ولذا قررت تغيير هذه القيمة عبر تنفيذ تعليمة UPDATE التالية. هذه العملية تُحدّث القيم في عمود الاسم name عن طريق تغيير قيمة عمود الاسم name في أي سجل يحتوي على الاسم Camal لتصبح Kamal:

mysql> UPDATE clients
mysql> SET name = 'Kamal'
mysql> WHERE name = 'Camal';
الخرج
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

يُظهر هذا الخرج أن سجلًا واحدًا فقط قد حُدّث. يمكنك التأكد من ذلك بتشغيل استعلام SELECT السابق مجددًا، على النحو:

$ SELECT * FROM clients;
الخرج
+----------+------------+------------------+-------------+
| clientID | name       | routine          | standardFee |
+----------+------------+------------------+-------------+
|        1 | Fares     | song and dance   |      180.00 |
|        2 | Kamal  | standup          |       99.99 |
|        3 | Karam | standup          |       45.00 |
|        4 | Wael      | song and dance   |      200.00 |
|        5 | Ahmad        | trained squirrel |       79.99 |
+----------+------------+------------------+-------------+
5 rows in set (0.00 sec)

تُظهر هذه النتائج أن القيمة المُدخلة سابقًا على أنّها Camal قد عُدلت الآن إلى Kamal.

لقد حُدثّت قيمة واحدة فقط في عمود الاسم name في هذا المثال. ولكن، يمكنك تحديث عدة قيم باستخدام بنية WHERE أشمل.

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

يرجى ملاحظة أن بنية WHERE في هذا المثال تتضمن المعامل LIKE، لذا فهي تُحدّث قيمة performanceFee لكل عميل تُطابق قيمة routine له النمط المحدد بالمحرف البديل 's%'. بمعنى آخر، سيُحدّث أجر الأداء لأي مؤدي يبدأ نوع عرضه بالحرف "s":

mysql> UPDATE clients
mysql> SET standardFee = 140
mysql> WHERE routine LIKE 's%';
الخرج
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4  Changed: 4  Warnings: 0

والآن إذا استعلمت مجددًا عن محتويات جدول العملاء clients، فستؤكد مجموعة النتائج أن أربعة من عملائك غدا لديهم الآن رسوم أداء متطابقة:

$ SELECT * FROM clients;
الخرج
+----------+------------+------------------+-------------+
| clientID | name       | routine          | standardFee |
+----------+------------+------------------+-------------+
|        1 | Fares     | song and dance   |      140.00 |
|        2 | Kamal  | standup          |      140.00 |
|        3 | Karam | standup          |      140.00 |
|        4 | Wael      | song and dance   |      140.00 |
|        5 | Ahmad        | trained squirrel |       79.99 |
+----------+------------+------------------+-------------+
5 rows in set (0.00 sec)

في حالة وجود أعمدة بالجدول تحمل قيمًا رقمية، فيُمكن تحديثها بتنفيذ عملية حسابية ضمن بنية SET. لتوضيح الأمر، بفرض أنّك توصلّت لاتفاق على زيادة رسوم الأداء لكل عميل بنسبة أربعين بالمئة، ولتطبيق هذا التغيير على جدول العملاء clients، يمكن تنفيذ عملية UPDATE كالآتي:

mysql> UPDATE clients
mysql> SET standardFee = standardFee * 1.4;
الخرج
Query OK, 5 rows affected, 1 warning (0.00 sec)
Rows matched: 5  Changed: 5  Warnings: 1

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

وتوفّر MySQL الاختصار SHOW WARNINGS الذي قد يساعد في شرح أي تحذيرات تتلقاها:

mysql> SHOW WARNINGS;
الخرج
+-------+------+--------------------------------------------------+
| Level | Code | Message                                          |
+-------+------+--------------------------------------------------+
| Note  | 1265 | Data truncated for column 'standardFee' at row 5 |
+-------+------+--------------------------------------------------+
1 row in set (0.00 sec)

يُخبرنا هذا الخرج بأن نظام قاعدة البيانات أصدر التحذير لأنه اضطر إلى اقتطاع إحدى قيم العمود standardFee الجديدة حتى تتوافق مع تنسيق الرقم العشري - خمسة أرقام مع وجود رقمين على يمين الفاصلة العشرية - المُعرّف مسبقًا.

لنستعلم عن جدول العملاء clients مجددًا للتأكد من أن رسوم الأداء لكل من العملاء قد ارتفعت بنسبة أربعين بالمئة بالفعل.

$ SELECT * FROM clients;
الخرج
+----------+------------+------------------+-------------+
| clientID | name       | routine          | standardFee |
+----------+------------+------------------+-------------+
|        1 | Fares     | song and dance   |      196.00 |
|        2 | Kamal  | standup          |      196.00 |
|        3 | Karam | standup          |      196.00 |
|        4 | Wael      | song and dance   |      196.00 |
|        5 | Ahmad        | trained squirrel |      111.99 |
+----------+------------+------------------+-------------+
5 rows in set (0.00 sec)

كما ذكرنا سابقًا، يمكنك أيضًا تحديث البيانات في عدة أعمدة دفعة واحدة باستخدام تعليمة UPDATE واحدة. للقيام بذلك، يجب تحديد كل عمود ترغب في تحديثه، متبوعًا بالتعبير الخاص بالقيمة المراد تعيينها، ثم تفصل بين كل زوج من اسم عمود وتعبير قيمة بعلامة فاصلة.

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

قبل الشروع في تحديث البيانات في جدول العروض shows، نفّذ الاستعلام التالي لاسترجاع كافة البيانات الحالية المُخزنة به حاليًا:

$ SELECT * FROM shows;
الخرج
+--------+------------+----------+------------+-------------+
| showID | showDate   | clientID | attendance | ticketPrice |
+--------+------------+----------+------------+-------------+
|      1 | 2019-12-25 |        4 |        124 |       15.00 |
|      2 | 2020-01-11 |        5 |         84 |       29.50 |
|      3 | 2020-01-17 |        3 |        170 |       12.99 |
|      4 | 2020-01-31 |        5 |        234 |       14.99 |
|      5 | 2020-02-08 |        1 |         86 |       25.00 |
|      6 | 2020-02-14 |        3 |        102 |       39.50 |
|      7 | 2020-02-15 |        2 |        101 |       26.50 |
|      8 | 2020-02-27 |        2 |        186 |       19.99 |
|      9 | 2020-03-06 |        4 |        202 |       30.00 |
|     10 | 2020-03-07 |        5 |        250 |        8.99 |
+--------+------------+----------+------------+-------------+
10 rows in set (0.01 sec)

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

mysql> UPDATE shows
mysql> SET attendance = attendance + 20,
mysql> ticketPrice = ticketPrice * 1.5
mysql> WHERE clientID IN 
mysql> (SELECT clientID
mysql> FROM clients
mysql> WHERE name = 'Karam' OR name = 'Wael');
الخرج
Query OK, 4 rows affected, 1 warning (0.00 sec)
Rows matched: 4  Changed: 4  Warnings: 1

لاحظ أن هذا المثال يستخدم استعلامًا فرعيًا في بنية WHERE لإرجاع قيم clientID لكل من Karam و Wael من جدول العملاء clients. وغالبًا ما يكون من الصعب تذكر القيم المجردة من قبيل أرقام التعريف، إلّا أنّ هذه الطريقة التي تستخدم فيها استعلامًا فرعيًا للعثور على قيمة يمكن أن تكون مفيدة في حال معرفتك لبعض السمات فقط حول السجلات المعنية.

بعد تحديث جدول العروض shows، لنستعلم عنه مجددًا للتأكد من أن التغييرات قد تمّت كما هو متوقع:

$ SELECT * FROM shows;
الخرج
+--------+------------+----------+------------+-------------+
| showID | showDate   | clientID | attendance | ticketPrice |
+--------+------------+----------+------------+-------------+
|      1 | 2019-12-25 |        4 |        144 |       22.50 |
|      2 | 2020-01-11 |        5 |         84 |       29.50 |
|      3 | 2020-01-17 |        3 |        190 |       19.49 |
|      4 | 2020-01-31 |        5 |        234 |       14.99 |
|      5 | 2020-02-08 |        1 |         86 |       25.00 |
|      6 | 2020-02-14 |        3 |        122 |       59.25 |
|      7 | 2020-02-15 |        2 |        101 |       26.50 |
|      8 | 2020-02-27 |        2 |        186 |       19.99 |
|      9 | 2020-03-06 |        4 |        222 |       45.00 |
|     10 | 2020-03-07 |        5 |        250 |        8.99 |
+--------+------------+----------+------------+-------------+
10 rows in set (0.00 sec)

يشير هذا الخرج إلى أن تعليمة UPDATE قد اكتملت بنجاح.

استخدام بنية JOIN لتحديث البيانات في جداول متعددة

ركّز هذا المقال حتى الآن على عرض طرق تحديث البيانات في جدول واحد فقط في كل مرة. ولكن، تُتيح بعض الإصدارات من SQL إمكانية تحديث أعمدة متعددة في جداول متعددة من خلال دمج الجداول مؤقتًا باستخدام بنية JOIN.

فيما يلي الصيغة العامة التي بإمكانك استخدامها لتحديث عدة جداول دفعة واحدة مستخدمًا بنية JOIN:

mysql> UPDATE table_1 JOIN table_2
mysql> ON table_1.related_column = table_2.related_column
mysql> SET table_1.column_name = value_expression,
mysql> table_2.column_name = value_expression
mysql> WHERE conditions_apply;

تبدأ صيغة هذا المثال بالكلمة المفتاحية UPDATE متبوعة بأسماء جدولين، يفصل بينهما صيغة JOIN. يلي ذلك صيغة ON، التي توضّح كيف ينبغي للاستعلام أن يدمج الجدولين معًا.

في معظم تقديمات SQL، يمكنك دمج الجداول عن طريق إيجاد تطابقات ما بين أي مجموعة من الأعمدة تحتوي على ما يُعرف في معيار SQL باسم "أنواع البيانات المؤهلة للدمج" (JOIN eligible). بمعنى آخر، يُمكن بشكل عام دمج أي عمود يحتوي على بيانات عددية مع أي عمود آخر يحتوي على بيانات عددية، بغض النظر عن أنماط البيانات المحددة لكل منهما. وبالمثل، يمكن دمج أي أعمدة تحتوي على قيم محرفية مع أي عمود آخر يحتوي على بيانات محرفية.

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

لتوضيح كيفية تنفيذ ذلك باستخدام جداول clients وshows المُنشأة مسبقًا، نفذ تعليمة UPDATE التالية. ما سيدمج جدولي clients وshows بناءً على أعمدة clientID المتطابقة في كلا الجدولين، ومن ثم تحديث قيم routine وticketPrice لسجل Fares في جدول clients وكل عروضها المدرجة في جدول shows.

mysql> UPDATE clients JOIN shows
mysql> USING (clientID)
mysql> SET clients.routine = 'mime',
mysql> shows.ticketPrice = 30
mysql> WHERE name = 'Fares';
الخرج
Query OK, 2 rows affected (0.01 sec)
Rows matched: 2  Changed: 2  Warnings: 0

لاحظ أنّ هذا المثال يدمج الجداول باستخدام الكلمة المفتاحية USING بدلاً من ON المُستخدمة في صيغة المثال السابق. وهذا ممكن لأنّ كل من الجدولين لديهما عمود clientID يتشاركان فيه نفس نوع البيانات.

لمزيد من التفاصيل حول عمليات الدمج باستخدام JOIN، ننصحك بقراءة المقال التالي كيفية استخدام عمليات الدمج في SQL.

تغيير سلوك تعليمة UPDATE للمفاتيح الخارجية

ستفشل أي تعليمة UPDATE قد تسبب تعارضًا مع قيد FOREIGN KEY افتراضيًا.

بالعودة إلى فقرة الاتصال بـ MySQL وإعداد قاعدة بيانات تجريبية نموذجية في مستلزمات العمل وبتذكّر أنّ العمود clientID في جدول العروض shows هو مفتاح خارجي يشير إلى عمود clientID في جدول العملاء clients. فهذا يعني أنّ أي قيمة مُدخلة في عمود clientID الخاص بجدول العروض يجب أن تكون موجودة بالفعل في جدول العملاء.

فإذا حاولت تحديث قيمة clientID لسجل ما في جدول العملاء والتي تظهر أيضًا في عمود clientID لجدول العروض، فسيؤدي ذلك إلى حدوث خطأ:

mysql> UPDATE clients
mysql> SET clientID = 9
mysql> WHERE name = 'Ahmad';
الخرج
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails

يمكنك تجنب هذا الخطأ بتغيير قيد المفتاح الخارجي الحالي بآخر يتعامل مع عمليات التحديث على نحوٍ مختلف.

ملاحظة: لا تسمح كافة أنظمة إدارة قواعد البيانات العلاقية أو محركات قواعد البيانات بإضافة أو إزالة قيد من جدول موجود بالفعل كما هو موضح في الفقرات التالية. فإذا كنت تستخدم نظام RDBMS غير MySQL، يجب عليك الرجوع إلى الوثائق الرسمية الخاصة به لفهم القيود الموجودة بخصوص إدارة القيود.

بالعودة إلى موضوعنا، ولاستبدال القيد الحالي، عليك بدايةً إزالته باستخدام تعليمة ALTER TABLE. تذكّر أننا في تعليمة CREATE TABLE الخاصة بجدول العروض shows، حددنا client_fk كاسم لقيد المفتاح الخارجي FOREIGN KEY للجدول:

mysql> ALTER TABLE shows
mysql> DROP FOREIGN KEY client_fk;
الخرج
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

بعد ذلك، أنشئ قيد مفتاح خارجي جديد مُعدّ ليتعامل مع عمليات التحديث UPDATE بطريقة تتناسب مع الحالة الاستخدامية المعطاة. بصرف النظر عن الإعداد الافتراضي الذي يمنع تعليمات UPDATE التي تخالف المفتاح الخارجي، هناك خياران آخران متاحان في معظم أنظمة إدارة قواعد البيانات العلاقية:

  • ON UPDATE SET NULL: يسمح لك هذا الخيار بتحديث السجلات من الجدول الأب، وسيعيد تعيين أي قيم مرتبطة بها في الجدول الابن على أنها قيم فارغة NULL.
  • ON UPDATE CASCADE: عند تحديث سجل في الجدول الأب، سيدفع هذا الخيار SQL لتحديث أي سجلات في الجدول الابن مرتبطة بذلك السجل من الجدول الأب لتتماشى مع القيمة الجديدة المُحدّثة.

في سياق هذا المثال، لا يُعد استخدام خيار ON UPDATE SET NULL منطقيًا، فلو غيّرت مُعرّف لأحد العملاء دون حذفه من جدول clients، ينبغي أن يبقى مرتبطًا بعروضه في الجدول shows. ويجب أن يظهر المُعرّف الجديد ضمن سجلات عروضه، وبالتالي يكون استخدام الخيار ON UPDATE CASCADE هو الأنسب لهذا السياق.

لإضافة قيد FOREIGN KEY يعمل وفق آلية ON UPDATE CASCADE، نفّذ أمر ALTER TABLE التالي. ستنشئ هذه التعليمة قيد جديد باسم new_client_fk يعكس تعريف القيد السابق ولكن مع إضافة خيار ON UPDATE CASCADE.

mysql> ALTER TABLE shows
mysql> ADD CONSTRAINT new_client_fk
mysql> FOREIGN KEY (clientID)
mysql> REFERENCES clients (clientID)
mysql> ON UPDATE CASCADE;
الخرج
Query OK, 10 rows affected (0.02 sec)
Records: 10  Duplicates: 0  Warnings: 0

تشير هذه النتائج إلى أن العملية قد أثرت على جميع السجلات العشرة وقامت بتعديلها في جدول العروض shows.

ملاحظة: بدلًا من تغيير تعريف جدول مُعرّف مسبقًا لتعديل كيفية تفاعل قيد المفتاح الخارجي مع عمليات UPDATE، يُمكنك من البداية تحديد هذا السلوك عند إنشاء الجدول بواسطة تعليمة CREATE TABLE، وبذلك تُعيّن السلوك المطلوب مُسبقًا.

mysql> CREATE TABLE shows
mysql> (showID int PRIMARY KEY,
mysql> showDate date,
mysql> clientID int,
mysql> attendance int,
mysql> ticketPrice decimal (4,2),
mysql> CONSTRAINT client_fk
mysql> FOREIGN KEY (clientID)
mysql> REFERENCES clients(clientID)
mysql> ON UPDATE CASCADE
mysql> );

عقب ذلك، ستكون قادرًا على تحديث قيمة clientID لأي سجل في جدول clients، وستنتقل هذه التغييرات بشكل تلقائي إلى جميع السجلات المرتبطة بها في جدول shows.

mysql> UPDATE clients
mysql> SET clientID = 9
mysql> WHERE name = 'Ahmad';
الخرج
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

رغم أن هذا الخرج يشير إلى تأثر سجل واحد فقط، إلا أنّ العملية قد حدّثت في الواقع قيمة clientID لكل سجلات جدول العروض المرتبطة بـ Ahmad في جدول shows. وللتحقق من ذلك، نفّذ الاستعلام التالي لاسترجاع كافة البيانات من الجدول shows:

$ SELECT * FROM shows;
الخرج
+--------+------------+----------+------------+-------------+
| showID | showDate   | clientID | attendance | ticketPrice |
+--------+------------+----------+------------+-------------+
|      1 | 2019-12-25 |        4 |        144 |       22.50 |
|      2 | 2020-01-11 |        9 |         84 |       29.50 |
|      3 | 2020-01-17 |        3 |        190 |       19.49 |
|      4 | 2020-01-31 |        9 |        234 |       14.99 |
|      5 | 2020-02-08 |        1 |         86 |       30.00 |
|      6 | 2020-02-14 |        3 |        122 |       59.25 |
|      7 | 2020-02-15 |        2 |        101 |       26.50 |
|      8 | 2020-02-27 |        2 |        186 |       19.99 |
|      9 | 2020-03-06 |        4 |        222 |       45.00 |
|     10 | 2020-03-07 |        9 |        250 |        8.99 |
+--------+------------+----------+------------+-------------+
10 rows in set (0.00 sec)

كما هو متوقع، تسبب التحديث الذي أُجري على عمود clientID في جدول clients في تحديث السجلات المرتبطة في جدول shows.

الخلاصة

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

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

وللمزيد حول SQL، نشجعك على متابعة المقالات المنشورة تحت وسم سلسلة تعلم SQL في أكاديمية حسوب.

ترجمة -وبتصرف- للمقال How To Update Data in SQL لصاحبه Mark Drake.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...