۱۴۰۴/۰۷/۰۳ Nebular

Trigger در SQL Server

Trigger در SQL Server

1. تعریف ساده

🔹 Trigger یعنی یک قطعه کد SQL که به‌طور خودکار اجرا می‌شود وقتی روی یک جدول (یا View) عملیاتی مثل INSERT, UPDATE, یا DELETE اتفاق بیفتد.

مثل یه “گوشی مخفی” که منتظر تغییرات می‌مونه و به محض وقوع، خودش اجرا میشه.


2. انواع Trigger در SQL Server

  1. AFTER Trigger (یا FOR Trigger)
    • بعد از اینکه عمل INSERT, UPDATE, یا DELETE انجام شد اجرا می‌شود.
    • بیشتر برای ثبت لاگ یا کنترل قوانین بیزینس استفاده می‌شود.
  2. INSTEAD OF Trigger
    • به جای عملیات اصلی اجرا می‌شود.
    • بیشتر روی View کاربرد دارد.

3. جداول مجازی در Trigger

وقتی Trigger اجرا می‌شود، SQL Server دو جدول موقت در اختیارمان می‌گذارد:

  • Inserted → ردیف‌های جدید که قرار است درج یا آپدیت شوند.
  • Deleted → ردیف‌های قدیمی که قرار است حذف یا آپدیت شوند.

این‌ها مثل جدول معمولی‌اند و می‌توان روی آن‌ها SELECT زد.


4. مثال‌ها و تریس کردن

مثال 1: ثبت لاگ وقتی داده‌ای درج شد

-- جدول اصلی
CREATE TABLE Employees (
    EmpID INT PRIMARY KEY,
    Name NVARCHAR(50),
    Salary INT
);

-- جدول لاگ
CREATE TABLE EmployeesLog (
    LogID INT IDENTITY PRIMARY KEY,
    EmpID INT,
    ActionType NVARCHAR(20),
    ActionDate DATETIME DEFAULT GETDATE()
);

-- ایجاد تریگر
CREATE TRIGGER trg_AfterInsert_Employees
ON Employees
AFTER INSERT
AS
BEGIN
    INSERT INTO EmployeesLog (EmpID, ActionType)
    SELECT EmpID, 'INSERT'
    FROM inserted;
END;

🔎 Trace:

INSERT INTO Employees (EmpID, Name, Salary)
VALUES (1, 'Ali', 5000);
  • داده وارد جدول Employees شد.
  • Trigger به صورت خودکار اجرا شد.
  • رکوردی در جدول EmployeesLog درج شد با ActionType = ‘INSERT’.

مثال 2: جلوگیری از حذف کارمند با حقوق بالا

CREATE TRIGGER trg_PreventDeleteHighSalary
ON Employees
AFTER DELETE
AS
BEGIN
    IF EXISTS (SELECT * FROM deleted WHERE Salary > 10000)
    BEGIN
        RAISERROR ('Cannot delete employee with high salary!', 16, 1);
        ROLLBACK TRANSACTION;
    END
END;

🔎 Trace:

DELETE FROM Employees WHERE EmpID = 1;
  • اگر کارمند حقوق > 10000 داشت، Trigger مانع حذف شد و خطا داد.
  • در غیر این صورت حذف انجام شد.

مثال 3: استفاده از INSTEAD OF روی View

-- View که دپارتمان و کارمند را ترکیب می‌کند
CREATE VIEW vw_EmployeeDepartment
AS
SELECT e.EmpID, e.Name, d.DepartmentName
FROM Employees e
JOIN Departments d ON e.DeptID = d.DeptID;

-- تریگر برای کنترل درج در View
CREATE TRIGGER trg_InsteadOfInsert_vwEmpDept
ON vw_EmployeeDepartment
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO Employees (EmpID, Name, DeptID)
    SELECT EmpID, Name,
           (SELECT DeptID FROM Departments WHERE DepartmentName = i.DepartmentName)
    FROM inserted i;
END;

🔎 Trace:

INSERT INTO vw_EmployeeDepartment (EmpID, Name, DepartmentName)
VALUES (2, 'Sara', 'IT');
  • چون View قابل درج مستقیم نیست، Trigger اجرا شد.
  • کارمند جدید به جدول Employees اضافه شد.

5. ویژگی‌ها و محدودیت‌ها

✅ ویژگی‌ها:

  • اجرای خودکار بر اساس رخداد (INSERT/UPDATE/DELETE).
  • مناسب برای Audit (ثبت تغییرات)، Business Rules، و جلوگیری از عملیات غیرمجاز.
  • می‌تواند روی جدول یا View تعریف شود.
  • در SQL Server یک جدول می‌تواند چندین تریگر داشته باشد حتی از یک نوع.

⚠️ محدودیت‌ها:

  • ممکن است باعث کندی کارایی شود (چون مخفیانه اجرا می‌شود).
  • نباید منطق پیچیده خیلی زیاد داخل Trigger نوشت (سخت برای دیباگ).
  • نباید خیلی زیاد زنجیره‌ای استفاده شوند (Nested Triggers).

6. جمع‌بندی ساده

  • Trigger → اجرا خودکار هنگام تغییر داده
  • انواع → AFTER, INSTEAD OF
  • جداول مجازی → inserted و deleted
  • استفاده → لاگ‌گیری، جلوگیری از عملیات، مدیریت داده در View
  • دستورات → CREATE TRIGGER, ALTER TRIGGER, DROP TRIGGER

مثال های بیشتر

🔹 مثال ۱: جلوگیری از حذف همه داده‌ها

CREATE TRIGGER trg_PreventDeleteAll
ON Employees
FOR DELETE
AS
BEGIN
    IF (SELECT COUNT(*) FROM deleted) = (SELECT COUNT(*) FROM Employees)
    BEGIN
        RAISERROR('حذف همه داده‌ها مجاز نیست!', 16, 1)
        ROLLBACK TRANSACTION
    END
END

🟢 تریس:

  1. وقتی کاربر بگه: DELETE FROM Employees; → همه رکوردها حذف میشن.
    → تریگر فعال میشه.
    → چک می‌کنه: تعداد رکوردهای حذف‌شده (deleted) = تعداد کل رکوردهای جدول؟
    → بله. پس ROLLBACK می‌کنه و خطا میده.
  2. اگر فقط یک نفر حذف بشه: DELETE FROM Employees WHERE EmpID = 5; → چون همه رکوردها حذف نشدن، خطایی رخ نمی‌ده.

🔹 مثال ۲: ذخیره تاریخچه تغییر حقوق کارمندان

CREATE TABLE SalaryHistory (
    EmpID INT,
    OldSalary DECIMAL(10,2),
    NewSalary DECIMAL(10,2),
    ChangeDate DATETIME
);

CREATE TRIGGER trg_SalaryChange
ON Employees
AFTER UPDATE
AS
BEGIN
    IF UPDATE(Salary)
    BEGIN
        INSERT INTO SalaryHistory(EmpID, OldSalary, NewSalary, ChangeDate)
        SELECT d.EmpID, d.Salary, i.Salary, GETDATE()
        FROM deleted d
        INNER JOIN inserted i ON d.EmpID = i.EmpID;
    END
END

🟢 تریس:

  1. جدول Employees داریم. کسی حقوق کارمند شماره 3 رو تغییر میده: UPDATE Employees SET Salary = 5000 WHERE EmpID = 3;
  2. تریگر فعال میشه.
    • جدول deleted → حقوق قدیمی کارمند 3.
    • جدول inserted → حقوق جدید کارمند 3.
    • داده‌ها وارد SalaryHistory میشن.

📌 نتیجه → می‌تونیم تاریخچه تغییرات حقوق رو نگه داریم.


🔹 مثال ۳: INSTEAD OF Trigger روی View

فرض کن یه View داری:

CREATE VIEW vw_EmployeeDept
AS
SELECT e.EmpID, e.EmpName, d.DeptName
FROM Employees e
JOIN Departments d ON e.DeptID = d.DeptID;

به طور پیش‌فرض نمی‌تونی مستقیم داخل View داده Insert کنی.
ولی با INSTEAD OF Trigger میشه:

CREATE TRIGGER trg_Insert_vwEmployeeDept
ON vw_EmployeeDept
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO Employees (EmpID, EmpName, DeptID)
    SELECT EmpID, EmpName, d.DeptID
    FROM inserted i
    JOIN Departments d ON d.DeptName = i.DeptName;
END

🟢 تریس:

INSERT INTO vw_EmployeeDept (EmpID, EmpName, DeptName)
VALUES (10, 'Ali', 'HR');
  • جدول inserted → رکورد جدیدی که می‌خواستیم وارد کنیم.
  • تریگر اجرا میشه → به جای ورود مستقیم به View، داده رو به جدول Employees وارد می‌کنه و با DeptName دپارتمانش رو پیدا می‌کنه.

🔹 مزایا و معایب تریگر

✅ مزایا:

  • خودکار بودن (نیازی نیست برنامه‌نویس دستی اجرا کنه).
  • امنیت و کنترل داده‌ها.
  • ثبت تاریخچه تغییرات (Auditing).
  • اعتبارسنجی پیچیده‌تر از Constraints.

❌ معایب:

خطایابی سخت میشه (چون خودکار اجرا میشه).

پیچیدگی زیاد.

ممکنه کارایی (Performance) رو پایین بیاره.

Accept Cookies
Accept Cookies
[your-shortcode]