لدى التعامل مع قاعدة بيانات، قد تضطر أحيانًا لتعديل بيانات كانت مدرجة من قبل في جدول أو أكثر. كأن تُضطر مثلًا لتصحيح خطأ إملائي في إدخال معين أو إضافة معلومات جديدة إلى سجل غير مكتمل. وتوفّر لغة الاستعلام البنيوية المعروفة بـ 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
ولضمان أنّ عمود 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.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.