Làm thế nào một Trình kích hoạt T-SQL chỉ kích hoạt các thay đổi thực sự được thực hiện?


9

Tôi có một trình kích hoạt bảng trên CẬP NHẬT và CHERTN để thêm một hàng vào một bảng khác. Nó chỉ cần thêm một hàng nếu một trong bốn cột được thay đổi. Tôi đã thử sử dụng IF UPDATE (col) để kiểm tra các thay đổi nhưng nó có một điểm mù. Nó chỉ kiểm tra một số giá trị xuất hiện. Tôi cần đi sâu hơn, tôi cần so sánh các giá trị cũ và mới để thấy sự thay đổi thực sự đã xảy ra. Nó phải hoạt động với cả CHERTN và CẬP NHẬT.

Trong trường hợp CẬP NHẬT thật dễ dàng vì cả hai bảng được chèn và xóa đều có các giá trị tôi có thể so sánh trong trình kích hoạt. Tuy nhiên, đối với INSERT chỉ có bảng chèn có giá trị. Bởi vì tôi cần tất cả những thứ này trong cùng một trình kích hoạt, làm thế nào để tôi xử lý trường hợp INSERT đó?

Đây là kịch bản kích hoạt tôi muốn sửa đổi:

ALTER TRIGGER [dbo].[trATPerson_alter] 
   ON  [mydb].[dbo].[AT_Person]
   AFTER INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    -- Not all updates require a push
    IF (UPDATE([First_Name]) OR UPDATE([Last_Name]) OR UPDATE([JobCode]) OR UPDATE([Inactive]))
    BEGIN
        INSERT INTO [mydb].[dbo].[AT_Person_To_Push] (
                [Facility],
                [VendorID],
                [Person_code],
                [First_Name],
                [Last_Name],
                [JobCode],
                [Alink],
                [Inactive]
            )
        SELECT  [Facility],
                [VendorID],
                [Person_code],
                [First_Name],
                [Last_Name],
                [JobCode],
                [Alink],
                [Inactive]
        FROM inserted 
    END
END

2
Một từ nhanh chóng về việc sử dụng "NẾU CẬP NHẬT (<cột>)". Nó trả về true nếu DML chỉ định giá trị cho cột, bất kể giá trị đó có thực sự thay đổi hay không.
Jonathan Fite

Câu trả lời:


18

Bạn có thể xử lý cả CHERTN và CẬP NHẬT với toán tử đặt EXCEPT. EXISTS sẽ chỉ đánh giá TRUE cả nếu đó chỉ là một CHERTN hoặc nếu đó là CẬP NHẬT với các giá trị khác nhau cho bất kỳ cột nào trong số này.

IF EXISTS (
           SELECT First_Name, Last_Name, JobCoe, Inactive FROM inserted
           EXCEPT
           SELECT First_Name, Last_Name, JobCoe, Inactive FROM deleted
          )
BEGIN...

Điều này thanh lịch hơn nhiều so với việc xem xét các chức năng được cập nhật cột khác nhau. Chúng tôi đã kết hợp những thứ đó với một số mã mặt trước để chỉ gửi các giá trị đã thay đổi (sau nhiều tranh cãi). Sử dụng một EXCEPT có ý nghĩa hơn rất nhiều.
Peter Schott

2
Điều này không hoạt động trong trường hợp 2 hàng bị "tráo đổi" trong một bản cập nhật. Nếu chúng ta có hai John Smith cần cập nhật mã công việc (John đầu tiên từ 1 đến 2; John thứ hai từ 2 đến 1) - điều này sẽ nói rằng không có cập nhật nào xảy ra.
Steven Hibble

2
@StevenHibble - Trong khi có thể thì điều đó có thể xảy ra như thế nào? Trường hợp đó có thể dễ dàng được khắc phục bằng cách đưa các cột PK vào câu lệnh Chọn ở trên.
Chad Estes

1
Tôi muốn nói xác suất phụ thuộc vào nguồn dữ liệu và khả năng nhập dữ liệu xấu. "Rất tiếc, John Smith sai ..." dường như điều đó sẽ không bao giờ xảy ra. Trong mọi trường hợp, điều này không giải quyết được nửa còn lại của bản cập nhật nhiều hàng: làm thế nào để bạn đảm bảo chỉ chèn các hàng thay đổi? Điều này EXISTSkiểm tra rằng bất kỳ hàng thay đổi. Nếu bạn giữ phần chèn từ câu hỏi, thì bạn sẽ ghi nhật ký tất cả các hàng được cập nhật khi chỉ một thay đổi theo cách có ý nghĩa.
Steven Hibble

2

Trong trường hợp một bản cập nhật có thể ảnh hưởng đến nhiều hàng, bạn phải bảo vệ chống lại hai điều:

  1. Chúng tôi muốn xem xét các cập nhật trao đổi giá trị giữa các hàng tương tự. Nếu có hai John Smith cần Cập nhật mã công việc của họ (John đầu tiên từ 1 đến 2; John thứ hai từ 2 đến 1), chúng tôi cần cẩn thận để nói rằng cả hai đều được cập nhật.
  2. Chúng tôi chỉ muốn đăng nhập các hàng đã thay đổi trong AT_Person_To_Push. Nếu 5 hàng được cập nhật, nhưng chỉ có 2 hàng được cập nhật theo cách mà chúng tôi quan tâm, thì chúng tôi chỉ cần xử lý 2 hàng có liên quan.

Đây là cách tôi sẽ xử lý nó:

  1. Trái tham gia insertedđể deleted, bởi vì insertedsẽ có hàng cho chèn và cập nhật trong khi deletedsẽ chỉ có hàng để cập nhật.
  2. Sử dụng EXISTSvới EXCEPTđể tìm các hàng trong đó các insertedgiá trị khác với các deletedgiá trị. Bạn không thể sử dụng i.First_Name != d.First_Name OR i.Last_Name != d.Last_Name...vì bảng đã xóa sẽ trống (và LEFT THAM GIA sẽ trả về null) khi trình kích hoạt đang xử lý một INSERT.
  3. Chỉ chèn các hàng bị ảnh hưởng vào AT_Person_To_Push.
ALTER TRIGGER [dbo].[trATPerson_alter] 
   ON  [mydb].[dbo].[AT_Person]
   AFTER INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    INSERT INTO [mydb].[dbo].[AT_Person_To_Push] (
            [Facility],
            [VendorID],
            [Person_code],
            [First_Name],
            [Last_Name],
            [JobCode],
            [Alink],
            [Inactive]
        )
    SELECT  i.[Facility],
            i.[VendorID],
            i.[Person_code],
            i.[First_Name],
            i.[Last_Name],
            i.[JobCode],
            i.[Alink],
            i.[Inactive]
    FROM inserted i
         LEFT JOIN deleted d
           ON i.Person_code = d.Person_code
    -- Check for changes that require a push
    WHERE EXISTS (SELECT i.[First_Name], i.[Last_Name], i.[JobCode], i.[Inactive]
                  EXCEPT
                  SELECT d.[First_Name], d.[Last_Name], d.[JobCode], d.[Inactive]);
END

1

Thử đi,

Declare @Acton int=0

If exists (Select 1 from inserted)
set @Acton=1

If exists (Select 1 from deleted)
set @Acton=@Acton+2

if(@Action=1) -- Only insert

if(@Action=3) -- Only Update
begin
IF (UPDATE([First_Name]) OR UPDATE([Last_Name]) OR UPDATE([JobCode]) OR UPDATE([Inactive]))
Begin

End
end

if(@Action=2) -- Only Delete
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.