خانه/ وبلاگ/ آموزش Trigger در SQL Server: انواع، جدول‌های inserted و deleted و مثال
آموزش SQL

آموزش Trigger در SQL Server: انواع، جدول‌های inserted و deleted و مثال

آموزش SQL ۵ آبان ۱۴۰۵ 11 دقیقه مطالعه

Trigger کدی است که به یک جدول چسبیده است و با هر INSERT، UPDATE یا DELETE خودکار اجرا می‌شود. کاربرد معمول آن ثبت لاگ تغییرات (Audit)، اعمال قواعدی که با قیدهای ساده بیان نمی‌شوند و همگام‌سازی جدول‌هاست. در این مقاله انواع آن را با مثال می‌بینیم.

انواع Trigger

نوعزمان اجراکاربرد
AFTER (یا FOR)بعد از انجام عملیات و بررسی قیدهالاگ تغییرات، به‌روزرسانی جدول‌های وابسته
INSTEAD OFبه‌جای عملیات اصلیکنترل کامل؛ مثلاً حذف منطقی به‌جای حذف واقعی، یا ویرایش View
DDL Triggerهنگام CREATE/ALTER/DROPجلوگیری از حذف جدول، ثبت تغییرات ساختاری

جدول‌های مجازی inserted و deleted

داخل Trigger دو جدول موقت وجود دارد که ساختار آن‌ها شبیه جدول اصلی است:

عملیاتinserteddeleted
INSERTردیف‌های جدیدخالی
DELETEخالیردیف‌های حذف‌شده
UPDATEمقدارهای جدیدمقدارهای قدیمی
یک دستور می‌تواند چند ردیف را تغییر دهد؛ پس Trigger یک‌بار برای کل دستور اجرا می‌شود، نه یک‌بار برای هر ردیف. همیشه با مجموعه‌ی ردیف‌های inserted و deleted کار کن، نه با یک متغیر تکی.

مثال ۱: ثبت لاگ تغییر حقوق (AFTER UPDATE)

sql
CREATE TABLE Employee (
  EmployeeId INT PRIMARY KEY,
  FullName   NVARCHAR(100),
  Salary     DECIMAL(12,2)
);

CREATE TABLE SalaryLog (
  LogId      INT IDENTITY PRIMARY KEY,
  EmployeeId INT,
  OldSalary  DECIMAL(12,2),
  NewSalary  DECIMAL(12,2),
  ChangedBy  SYSNAME DEFAULT SUSER_SNAME(),
  ChangedAt  DATETIME2 DEFAULT SYSDATETIME()
);
GO

CREATE TRIGGER trg_Employee_SalaryAudit
ON Employee
AFTER UPDATE
AS
BEGIN
  SET NOCOUNT ON;
  IF UPDATE(Salary)
    INSERT INTO SalaryLog (EmployeeId, OldSalary, NewSalary)
    SELECT d.EmployeeId, d.Salary, i.Salary
    FROM deleted d
    JOIN inserted i ON i.EmployeeId = d.EmployeeId
    WHERE ISNULL(d.Salary, -1) <> ISNULL(i.Salary, -1);
END;
GO

UPDATE Employee SET Salary = 1500 WHERE EmployeeId = 1;
SELECT * FROM SalaryLog;

IF UPDATE(Salary) بررسی می‌کند ستون حقوق در دستور آمده باشد و شرط WHERE فقط ردیف‌هایی را لاگ می‌کند که مقدارشان واقعاً عوض شده.

مثال ۲: جلوگیری از حذف (AFTER DELETE با ROLLBACK)

sql
CREATE TRIGGER trg_Employee_NoDeleteManager
ON Employee
AFTER DELETE
AS
BEGIN
  IF EXISTS (SELECT 1 FROM deleted WHERE FullName = N'Admin')
  BEGIN
    ROLLBACK TRANSACTION;
    THROW 50010, N'حذف کاربر Admin مجاز نیست', 1;
  END
END;

مثال ۳: حذف منطقی با INSTEAD OF

به‌جای حذف واقعی، ستون IsDeleted را ۱ می‌کنیم تا داده برای ممیزی بماند:

sql
CREATE TRIGGER trg_Customer_SoftDelete
ON Customer
INSTEAD OF DELETE
AS
BEGIN
  SET NOCOUNT ON;
  UPDATE c SET IsDeleted = 1
  FROM Customer c
  JOIN deleted d ON d.CustomerId = c.CustomerId;
END;

مدیریت Trigger

sql
DISABLE TRIGGER trg_Employee_SalaryAudit ON Employee;   -- غیرفعال موقت
ENABLE  TRIGGER trg_Employee_SalaryAudit ON Employee;
DROP    TRIGGER IF EXISTS trg_Employee_SalaryAudit;

-- فهرست Triggerهای یک جدول
SELECT name, is_disabled FROM sys.triggers WHERE parent_id = OBJECT_ID('Employee');

مشکلات رایج

  • فرض یک‌ردیفی: نوشتن SELECT @id = EmployeeId FROM inserted با دستور چندردیفی نتیجه‌ی اشتباه می‌دهد.
  • Triggerهای تودرتو و بازگشتی: Triggerی که جدول دیگر را تغییر می‌دهد و آن جدول هم Trigger دارد، عیب‌یابی را سخت می‌کند.
  • منطق سنگین: هر ثانیه‌ی اجرای Trigger جزو زمان تراکنش اصلی است و قفل‌ها را بیشتر نگه می‌دارد.
  • فراموش‌شدن: Trigger «جادویی» است و برنامه‌نویس بعدی ممکن است از وجودش بی‌خبر باشد؛ مستندسازی کن.
برای قواعد ساده مثل «نمره بین ۰ تا ۲۰» از قید CHECK استفاده کن، نه Trigger. Trigger را برای ممیزی و منطق چندجدولی نگه دار.

برای شناخت بیشتر اشیاء برنامه‌نویسی، مقاله‌ی تفاوت Procedure، Function و View را بخوان.

سوالات متداول درباره‌ی این موضوع

Trigger چه زمانی اجرا می‌شود؟

به‌طور خودکار هنگام INSERT، UPDATE یا DELETE روی جدول (DML Trigger) یا هنگام تغییر ساختار پایگاه‌داده (DDL Trigger)؛ نیازی به فراخوانی دستی ندارد.

جدول‌های inserted و deleted چه هستند؟

جدول‌های مجازی موقت داخل Trigger هستند: inserted ردیف‌های جدید (بعد از تغییر) و deleted ردیف‌های قدیمی (قبل از تغییر) را نگه می‌دارند. در UPDATE هر دو پر هستند.

آیا Trigger برای کارایی بد است؟

اگر ساده و کوتاه نوشته شود مشکلی ندارد، اما منطق سنگین یا تودرتو در Trigger عملیات نوشتن را کند و عیب‌یابی را سخت می‌کند. Trigger باید برای ممیزی و قواعدی که با قید قابل بیان نیستند استفاده شود.

مصطفی موسویسازنده و نویسنده‌ی SQLFarsi. اگر اشتباهی در مقاله دیدی یا پیشنهادی داری، از طریق mousavi.dev خبر بده.

می‌خوای SQL را از پایه و با تمرین یاد بگیری؟

دوره‌ی رایگان SQLFarsi را با Playground و پروژه‌های واقعی دنبال کن.

شروع یادگیری