You are on page 1of 7

‫القادحات في قواعد المعطيات‬

‫‪Triggers in Databases‬‬

‫استخدام القادحات لفرض قيود العمل ‪Using triggers to force‬‬ ‫‪-1‬‬


‫‪constraints‬‬

‫القادح بالتعريف هو نوع خاص من اإلجرائيات المخزنة التي ًّ‬


‫تنفذ تلقائيًا عندما تتغير البيانات الموج ودة في‬
‫جدول محدد‪ .‬إذ يتم استدعاء القادح استجابة إلى أحد تعليمات ‪.Insert, Update, Delete‬‬

‫تتم معاملة القادح والتعليمة التي حفزته كمناقلة واحدة وهي مناقلة يمكن التراجع عنها من داخ ل الق ادح‬
‫وذلك في حال حصول خطأ‪.‬‬

‫توفر مخدمات قواعد البيانات طريقتين أساسيتين لفرض قيود العمل وهما القيود ‪ Constraints‬والقادحات ‪.Triggers‬‬

‫مقارنة القادحات بالقيود‬ ‫‪-2‬‬


‫الفائدة األساسية للقادحات تكمن في احتوائها على تعليمات معالجة معقدة‪ ،‬وبالتالي فهي أوسع من القي ود في‬
‫معالجتها‪.‬‬

‫تكون القادحات مفيدة في الحاالت التي ال تحقق فيها القيود الحاجات الوظيفية لتطبيق ما‪:‬‬

‫يمكن للقادحات أن تسلسل التعديالت إلى الجداول المرتبطة‪ ،‬ولكن هذه السلسلة يمكن فرضها أيض ًا ع بر قي ود‬ ‫‪‬‬
‫التكامل المرجعي واستخدام التسلسل للقيود المرجعية يكون عادة أكثر فعالية‪.‬‬
‫يمكن للقادحات أن تفرض القيود المعقدة التي يصعب فرضها باستخدام قيد االختب ار ‪ .Check Constraint‬ال يمكن لقي د‬ ‫‪‬‬
‫االختبار أن يشير إلى أعمدة موجودة في جداول أخرى‪ ،‬أما القادحات فهي قادرة على ذلك‪.‬‬
‫يمكن للقادح أن يختبر حالة الجدول قبل وبعد التعديل‪ ،‬وأن يقوم بعمليات معينة بناء على ذلك‪.‬‬ ‫‪‬‬
‫يمكن إضافة عدة قادحات لنفس نمط التغيير على الجدول‪.‬‬ ‫‪‬‬

‫إنشاء القادحات‬ ‫‪-3‬‬

‫قواعد بناء القادحات‬


‫مالك الجدول هو المستخدم االفتراضي الذي يحق له إنشاء القادحات المقابلة‪ .‬وال يمكن لمالك الجدول أن يمنح هذا الحق لغيره‪.‬‬ ‫‪‬‬
‫يمكن إنشاء القادحات في قاعدة البيانات الحالية فقط‪ ،‬رغم أن القادح يمكنه استخدام جداول موجودة في قواعد أخرى‪.‬‬ ‫‪‬‬
‫ال يمكن إنشاء قادحات على جداول مؤقتة أو خاصة بالنظام رغم أنه يمكن استخدام الجداول المؤقتة ضمن القادح‪.‬‬ ‫‪‬‬
‫ال يمكن تعريف قادحات االستبدال للحذف والتعديل على الجداول التي تحوي مفاتيح أجنبية معرفة بأفعال مرتبطة مثل التسلسل‬ ‫‪‬‬
‫‪ CASCADE‬أو إسناد قيمة ‪ NULL‬أو قيمة افتراضية ‪.DEFAULT‬‬
‫ال تؤدي تعليمة بتر الجدول ‪( Truncate Table‬وهي تعليمة مماثلة لتعليمة الحذف ‪ DELETE‬بدون شرط فلترة أي ح ذف‬ ‫‪‬‬
‫جميع السجالت من الجدول) إلى تحفيز القادح البديل عن الحذف‪.‬‬
‫يمكن فقط لمالك الجدول‪ ،‬وأعضاء المجموعة ‪ ،sysadmin‬وأعضاء المجموعات الخاص ة بقاع دة البيان ات ‪db_owner,‬‬ ‫‪‬‬
‫‪ db_ddladmin‬أن ينفذوا تعليمة ‪ .Create Trigger‬وال يمكن نقل هذا الحق إلى بقية المستخدمين‪.‬‬

‫تصميم القادحات‬ ‫‪-4‬‬


‫هناك نمطان من القادحات‪:‬‬

‫القادحات االستبدالية ‪ :Instead Of Triggers‬وهي قادحات تنفذ عوضًا عن التغيير األصلي‪ .‬أي إذا‬ ‫‪‬‬
‫كان هذا القادح استبدا ً‬
‫ال لعملية اإلضافة ‪ Insert‬فال تنفذ عملية اإلضافة وإنما ينفذ القادح عوضًا عن ه‪.‬‬

‫‪1‬‬
‫بمعنى آخر لو أردنا أن تتم عمليه اإلضافة األصلية فأن مسؤولية اإلضافة تقع على ع اتق الق ادح (أي‬
‫يجب أن نكتب كود االضافة في القادح)‪.‬‬
‫ذه‬ ‫يمكن تعريف القادحات االستبدالية على المناظير متعددة الجداول‪ ،‬األمر الذي يسمح بتوسيع أنماط التحديث الممكنة عبر ه‬
‫المناظير‪.‬‬

‫القادحات الالحقة ‪ :After Triggers‬وهي قادحات تنفذ بعد نجاح الفع ل المواف ق له ا (‪Insert,‬‬ ‫‪‬‬
‫‪ ،) Update, Delete‬في حال فشلت عملية (االضافة أو الحذف أو التعديل) فلن يتم استدعاء الق ادح‬
‫الالحق المرتبط‪.‬‬

‫يتم التحقق من القيود بعد القادحات من النمط ‪ Instead Of‬وقبل القادحات من النمط ‪ .After‬إذا س بب الق ادح‬
‫‪ Instead Of‬اختراقًا ألحد القيود فإن المناقلة الموافقة له تلغى‪ ،‬وال يتم تنفيذ القادح ‪ After‬الموافق إن وجد‪.‬‬
‫ه‪:‬‬ ‫انتب‬
‫يمكن ألي جدول أو منظار أن يحوي قادحًا استبداليًا وحيدًا‪ ،‬بينما يمكنه أن يحوي عدة قادحات الحقة‬
‫خاصة بكل فعل ممكن‪.‬‬

‫استخدام جداول السجالت المضافة والمحذوفة ‪Inserted and Deleted‬‬ ‫‪-5‬‬


‫‪Tables‬‬
‫يقوم مخدم البيانات بإنشاء وإدارة الجدولين ‪ .Inserted, Deleted‬هذان الجدوالن هما ج دوالن مؤقت ان‬
‫مخزنان في الذاكرة ويحويان القيم السابقة ‪ Deleted‬والالحقة ‪ Inserted‬الناتجة عن العملية‪.‬‬

‫يخزن جدول المحذوفات ‪ Deleted‬نسخة عن السجالت القديم ة المت أثرة بك ل من عملي تي الح ذف‬
‫والتعديل‪.‬‬

‫يخ زن ج دول اإلض افات ‪ Inserted‬نس خة عن الس جالت الجدي دة الناتج ة عن ك ل من عملي تي‬
‫اإلضافة والتعديل‪.‬‬

‫ألنه يعتبر أن عملية التعديل هي حذف للقيم القديمة وإدراج للقيم الجديدة‪.‬‬

‫افتها‬ ‫أثناء عمليتي الحذف والتعديل يقوم المخدم بحذف السجالت المتأثرة بالعملية من الجدول الموافق وإض‬
‫إلى الجدول ‪.Deleted‬‬

‫أثناء عمليتي اإلضافة والتعديل يقوم المخ دم بتخ زين القيم المحدث ة أو الجدي دة للس جالت في الج دول‬
‫‪ . Inserted‬أي أن هذا الجدول يحوي نسخًا من السجالت الجديدة المراد إضافتها إلى الجدول المرتبط‪.‬‬

‫افات ال‬ ‫بالتالي‪ :‬جدول المحذوفات ال يحوي أي سجالت للقادحات البديلة عن اإلضافة‪ ،‬كما أن جدول المض‬
‫يحوي أي سجالت للقادحات البديلة عن الحذف‪.‬‬

‫بنية الجداول في األمثلة‪:‬‬

‫‪CREATE TABLE Employee‬‬


‫(‬ ‫‪Emp_ID int identity,‬‬
‫‪Emp_Name varchar(55),‬‬
‫)‪Emp_Sal decimal (10,2‬‬
‫)‬

‫‪Insert‬‬ ‫‪into‬‬ ‫‪Employee‬‬ ‫‪values‬‬ ‫;)‪('hasan',1000‬‬


‫‪Insert‬‬ ‫‪into‬‬ ‫‪Employee‬‬ ‫‪values‬‬ ‫;)‪('wesam',1200‬‬
‫‪Insert‬‬ ‫‪into‬‬ ‫‪Employee‬‬ ‫‪values‬‬ ‫;)‪('samer',1100‬‬
‫‪Insert‬‬ ‫‪into‬‬ ‫‪Employee‬‬ ‫‪values‬‬ ‫;)‪('lamis',1300‬‬
‫‪Insert‬‬ ‫‪into‬‬ ‫‪Employee‬‬ ‫‪values‬‬ ‫;)‪('fahed',1400‬‬

‫‪2‬‬
‫‪create table Employee_log‬‬
‫(‬ ‫‪Emp_ID int,‬‬
‫‪Emp_Name varchar(55),‬‬
‫‪Emp_Sal decimal(10,2),‬‬
‫‪Audit_Action varchar(100),‬‬
‫‪Audit_Timestamp datetime‬‬
‫)‬

‫تصميم القادحات االستبدالية‪:‬‬ ‫‪-6‬‬


‫مالحظة جانبية‪ :‬استخدام القادحات العودية ‪Recursive Triggers‬‬
‫القادح العودي هو القادح الذي يقوم باستدعاء نفسه من ضمن تعريف القادح عند تنفيذ العملية الموافقة للقادح على نفس الجدول‪.‬‬

‫هناك نوعان من العودية‪:‬‬

‫العودية المباشرة ‪ :‬وتحدث عندما ننفذ نفس التعليمة التي فعلت القادح من ضمن القادح مباش رة‪ .‬مثالً إذا عرفن ا قادح ا ً ب ديالً عن التح ديث ‪TrigU‬‬ ‫‪‬‬
‫على الجدول ‪ .T‬فعندما نجري عملية تحديث لسجالت في ‪ T‬فإن القادح ‪ TrigU‬ينفذ‪ .‬إذا قمنا ضمن تعري ف الق ادح ‪ TrigU‬بتح ديث الج دول ‪T‬‬
‫مجدداً فإن القادح ‪ TrigU‬ينفذ بالعودية المباشرة‪.‬‬
‫العودية غير المباشرة‪ :‬وتحدث عندما يحفز القادح المعني قادحا ً آخر معرف على جدول ثان‪ ،‬الذي يق وم ب دوره بتنفي ذ التعليم ة ال تي فعلت الق ادح‬ ‫‪‬‬
‫األول مما يؤدي إلى إعادة استدعاء القادح بالعودية غير المباشرة‪ .‬مثالً نعرف بديل إضافة ‪ TrigI1‬على الجدول ‪ T1‬الذي يستدعي ض منه ق ادح‬
‫اإلضافة ‪ TrigI2‬المعرف على الج دول ‪ .T2‬إذا ق ام الق ادح ‪ TrigI2‬بعملي ة إض افة على الج دول ‪ T1‬ف إن الق ادح ‪ TrigI1‬ينف ذ بالعودي ة غ ير‬
‫المباشرة‪.‬‬
‫بشكل عام القادحات ليست عودية ما لم نعط قيمة لخيار قاعدة البيانات ‪ RECURSIVE TRIGGER‬القيمة ‪ .ON‬إذا وضعنا قيمة هذا الخيار ‪OFF‬‬
‫فإنه يتم منع العودية المباشرة فقط‪.‬‬

‫لمنع العودية غير المباشرة يجب أن نسند إلى خيار مخدم البيانات ‪ nested triggers‬القيمة ‪.0‬‬

‫الفائدة األساسية للقادحات االستبدالية هي لدعم المناظير القابلة للتحديث‪.‬‬


‫إذا تضمن منظار ما على أكثر من جدول‪ ،‬عندها يجب استخدام القادح االستبدالي لدعم عمليات اإلضافة والحذف والتعديل عبر ه ذا‬
‫المنظار للجداول المرتبطة به‪.‬‬

‫القادح االستبدالي مع عملية االضافة‪Instead of Insert Trigger :‬‬ ‫‪.6.1‬‬

‫هذا القادح مفيد‬ ‫يقوم القادح البديل عن االستبدال بالتنفيذ عوضا عن فعل اإلضافة العادي المنفذ من قبل المخدم‪.‬‬
‫عادة لتمكين اإلضافة عبر منظار إلى مجموعة الجداول المضمنة فيه (أو بعضها على األقل)‪.‬‬

‫في مثالنا هنا نقوم بمناقشة الموظف المضاف بشرط أن اليكون راتبه أقل ‪1000‬‬

‫‪CREATE TRIGGER triger_instead_insert ON Employee‬‬


‫‪INSTEAD OF Insert‬‬
‫‪AS‬‬
‫‪declare @emp_id int, @emp_name varchar(55),‬‬
‫;)‪@emp_sal decimal(10,2), @log_action varchar(100‬‬

‫;‪select @emp_id=i.Emp_ID from inserted i‬‬


‫;‪select @emp_name=i.Emp_Name from inserted i‬‬
‫;‪select @emp_sal=i.Emp_Sal from inserted i‬‬
‫‪SET @log_action='Inserted Record -- Instead Of Insert‬‬
‫;'‪Trigger.‬‬
‫‪BEGIN‬‬
‫)‪if(@emp_sal<=1000‬‬
‫‪begin‬‬

‫‪3‬‬
print 'Cannot Insert where salary < 1000 '
ROLLBACK;
end
else
begin
Insert into
Employee (Emp_Name,Emp_Sal)
values (@emp_name,@emp_sal);
Insert into
Employee_log(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
values(@@identity,@emp_name,@emp_sal
,@log_action,getdate() );
PRINT 'Record Inserted Successfully .'
END
END

-----------‫ ثم جرب األمثلة التالية‬-------


insert into Employee values ('wedad',1300)
insert into Employee values ('Ahmad',900)

:‫القادح االستبدالي مع عملية التعديل‬ .6.2


1000 ‫يجب عدم تنقيذ عملية التعديل على الموظف في حال كان الراتب الجديد أقل من‬

CREATE TRIGGER trgInsteadOfUpdate ON dbo.Employee


INSTEAD OF Update
AS
declare @emp_id int, @emp_name varchar(55),
@emp_sal decimal(10,2), @log_action varchar(100);
select @emp_id=i.Emp_ID from inserted i;
select @emp_name=i.Emp_Name from inserted i;
select @emp_sal=i.Emp_Sal from inserted i;
SET @log_action='Updated Record -- Instead Of Update';
BEGIN
if(@emp_sal<= 1000)
begin
RAISERROR('Cannot update where salary < 1000',16,1);
ROLLBACK;
end
else
begin
update Employee set emp_name = @emp_name
, emp_sal = @emp_sal
where emp_id = @emp_id;
insert into Employee_log(Emp_ID,Emp_Name,Emp_Sal
,Audit_Action,Audit_Timestamp)
values(@emp_id,@emp_name,@emp_sal,
@log_action,getdate());
PRINT 'Record Updated successfully';
END
END
---------------------------------
-----------‫ ثم جرب األمثلة التالية‬-------

update Employee set Emp_Sal = '1400' where emp_id = 6

4
update Employee set Emp_Sal = '900' where emp_id = 6

:‫لعرض رسائل الخطأ يمكن استخدام أي من التعليمتين‬


RAISERROR('Cannot Insert where salary < 1000',16,1);
print'Cannot Insert where salary < 1000'

:‫القادح االستبدالي مع عملية الحذف‬ .6.3


1200 ‫يتم حذف الموظف بشرط أن يكون راتبه أقبل من‬

CREATE TRIGGER trgAfterDelete ON dbo.Employee


INSTEAD OF DELETE
AS
declare @empid int, @empname varchar(55), @empsal
decimal(10,2), @audit_action varchar(100);
select @empid=d.Emp_ID FROM deleted d;
select @empname=d.Emp_Name from deleted d;
select @empsal=d.Emp_Sal from deleted d;
Begin
if(@empsal>1200)
begin
RAISERROR('Cannot delete where salary > 1200',16,1);
ROLLBACK;
end
else
begin
delete from Employee where Emp_ID=@empid;

insert into Employee_log(Emp_ID,Emp_Name,Emp_Sal,


Audit_Action,Audit_Timestamp)
values(@empid,@empname,@empsal
,'Deleted -- Instead Of Delete Trigger.',getdate() );
PRINT 'Record Deleted -- Instead Of Delete Trigger.'
end
END

-----------‫ ثم جرب األمثلة التالية‬-------


DELETE FROM Employee where emp_id = 1
DELETE FROM Employee where emp_id = 3

:‫تصميم القادحات الالحقة‬ -7


After Insert Trigger ‫القادح الالحق بعد عملية االضافة‬ .a

CREATE TRIGGER trgAfterInsert on Employee


FOR INSERT
AS declare @empid int, @empname varchar(55),
@empsal decimal(10,2), @audit_action varchar(100);
select @empid=i.Emp_ID from inserted i;
select @empname=i.Emp_Name from inserted i;
select @empsal=i.Emp_Sal from inserted i;
set @audit_action='Inserted Record -- After Insert Trigger.';

5
insert into Employee_log(Emp_ID,Emp_Name,Emp_Sal,
Audit_Action,Audit_Timestamp)
values (@empid,@empname,@empsal,
@audit_action,getdate());
PRINT 'AFTER INSERT trigger fired.'

-----------‫ ثم جرب األمثلة التالية‬-------


insert into Employee(Emp_Name,Emp_Sal)values ('sami',1000);

‫ يستمر‬،‫ حتى لو قام القادح االستبدالي بإلغاء عملية االضافة واستبدالها بأي تعليمة أخرى‬:‫مالحظة‬
.‫ وكأن عملية االضافة قد تمت بنجاح‬،‫تنفيذ القادح الالحق لعملية االضافة بعد تعليمة االضافة‬

After Update Trigger ‫القادح الالحق بعد عملية التعديل‬ .b

CREATE TRIGGER trgAfterUpdate ON dbo.Employee


FOR UPDATE
AS
declare @empid int, @empname varchar(55),
@empsal decimal(10,2), @audit_action varchar(100);
select @empid=i.Emp_ID from inserted i;
select @empname=i.Emp_Name from inserted i;
select @empsal=i.Emp_Sal from inserted i;

if update(Emp_Name)
set @audit_action='Update on Emp_name ';
else
if update (Emp_Sal)
set @audit_action='Update on Salary..';
else
if update(Emp_Name)AND update (Emp_Sal)
set @audit_action='Update on Salary and NAme';

insert into
Employee_log (Emp_ID,Emp_Name,Emp_Sal,
Audit_Action,Audit_Timestamp)
values (@empid,@empname,@empsal,
@audit_action,getdate());
PRINT 'AFTER UPDATE trigger fired.'

-----------‫ ثم جرب األمثلة التالية‬-------


update Employee set Emp_Name='Pawan' Where Emp_ID =6;

if update(Emp_Name) :‫ في السطر‬update ‫التابع‬


‫ قد تم تعديل قيمته (أي هو يستخدم لمعرفة الحقل‬Emp_Name ‫يستخدم للتحقق من أن الحقل‬
)‫الذي تغيرت قيمته من الحقل الذي لم تتغير قيمته‬

After Delete Trigger ‫القادح الالحق بعد عملية الحذف‬ .c

6
‫‪CREATE TRIGGER trgAfterDelete ON dbo.Employee‬‬
‫‪FOR DELETE‬‬
‫‪AS‬‬
‫‪declare @empid int, @empname varchar(55),‬‬
‫;)‪@empsal decimal(10,2), @audit_action varchar(100‬‬
‫‪select @empid=d.Emp_ID‬‬ ‫;‪FROM deleted d‬‬
‫;‪select @empname=d.Emp_Name from deleted d‬‬
‫‪select @empsal=d.Emp_Sal‬‬ ‫;‪from deleted d‬‬
‫;'‪select @audit_action='Deleted -- After Delete Trigger.‬‬

‫‪insert into Employee_log‬‬


‫)‪(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp‬‬
‫;))(‪values (@empid,@empname,@empsal,@audit_action,getdate‬‬
‫'‪PRINT 'AFTER DELETE TRIGGER fired.‬‬

‫‪ -------‬ثم جرب األمثلة التالية‪-----------‬‬


‫‪DELETE FROM Employee where emp_id = 5‬‬

‫تعديل القادحات‬ ‫‪-8‬‬


‫لتعديل القادح يمكننا أن نحذفه ومن ثم نعيد تعريفه كما يمكننا تعديل القادح بتعليمة واحدة‪.‬‬

‫م أي‬ ‫إذا تغير اسم أي غرض مستخدم في القادح فيجب عندها تعديل القادح بما يتوافق‪ ،‬لذلك قبل تعديل اس‬
‫غرض يجب عرض قائمة األغراض المرتبطة به لتحديد وجود أي قادحات متأثرة بهذا التغيير‪.‬‬

‫كما يمكن تعديل أي قادح يملكه المستخدم من قبل المستخدم نفسه (حكما في قاعدة البيانات الحالية) كما يمكن‬
‫لمدير النظام أن يغير اسم أي قادح ألي مستخدم‪.‬‬

‫حذف القادحات‬ ‫‪-9‬‬


‫عند حذف قادح ما فإن الجدول أو المنظار الموافق ال يتأثر‪ .‬أما إذا حذفنا جدوال أو منظ ارا ف إن جمي ع‬
‫القادحات المرتبطة ستحذف تلقائيا‪ .‬يحق لمالك القادح فقط إضافة إلى مدير النظام إمكانية حذف القادح‪.‬‬

‫نستخدم التعليمة ‪ DROP TRIGGER‬كما يبين المثال التالي‪:‬‬

‫‪DROP TRIGGER InsteadTrigger‬‬

‫‪ -------------‬انتهت المحاضرة ‪---------‬‬

‫‪7‬‬

You might also like