2010-08-26 29 views
22

Tôi có bàn TbLàm cách nào để chỉnh sửa giá trị của INSERT trong trình kích hoạt trên SQL Server?

ID | Name | Desc 
------------------------- 
1 | Sample | sample desc 

Tôi muốn tạo ra một kích hoạt trên INSERT đó sẽ thay đổi giá trị của chèn Desc, ví dụ:

INSERT INTO Tb(Name, Desc) VALUES ('x', 'y') 

sẽ dẫn đến

ID | Name | Desc 
------------------------- 
1 | Sample | sample desc 
2 | x  | Y edited 

Trong ví dụ trên tôi nhận giá trị của việc chèn Desc đã thay đổi thành chữ hoa và một dded edited vào cuối.

Đó là những gì tôi cần, nhận được Desc đang được chèn và sửa đổi.

Tôi có thể làm như thế nào?

Bạn có nên xử lý nó sau khi chèn bằng bản cập nhật không? Hoặc tạo một trigger với INSTEAD OF INSERT và sửa đổi nó mỗi khi cấu trúc bảng thay đổi?

+1

Bạn không thể làm điều này theo một cách khác? Cá nhân tôi ghét khi tôi thấy những điều kỳ lạ xảy ra trên dữ liệu và cuối cùng tôi nhận ra rằng một kích hoạt ma đã làm một số công cụ –

+0

Tôi sẽ sử dụng điều này để khắc phục sự cố xuất phát từ mã mà tôi không có quyền truy cập. Nó chèn 'url' của một mục, nhưng nó không loại bỏ dấu trọng âm và các ký tự đặc biệt, tôi sẽ kích hoạt làm điều đó cho tôi. – BrunoLM

+1

Đây không phải là một khái niệm khó và nó bảo vệ tâm trí của tôi rằng Microsoft không thể cung cấp chức năng đơn giản như trong Oracle, nơi bạn có thể sửa đổi bất kỳ giá trị nào trước khi chèn bằng cách chỉnh sửa các giá trị MỚI. tức là nếu tôi muốn luôn đặt tên người dùng lên trên trước khi chèn chúng (giả sử tôi không thể làm điều đó trong mã vì một số lý do), bạn có thể có một trình kích hoạt chèn trước đó: NEW.username: = UPPER (: NEW.username). Mặc dù vậy, trong SQL Server, bạn không thể làm tương đương với các giá trị trong bảng tạm thời INSERTED, và điều đó thật sự rất tệ. – Jim

Trả lời

30

Sử dụng trình kích hoạt chèn sau. Tham gia từ inserted bảng giả để Tb trên khóa chính. Sau đó cập nhật các giá trị của desc. Một cái gì đó như: (Nhưng có thể không biên dịch)

CREATE TRIGGER TbFixTb_Trg 
ON Tb 
AFTER INSERT 
AS 
BEGIN 
    UPDATE Tb 
    SET DESC = SomeTransformationOf(i.DESC) 
    FROM Tb 
    INNER JOIN inserted i on i.Id = Tb.Id 
END 
GO 

Trigger này xảy ra sau khi chèn đã xảy ra, nhưng trước khi insert tuyên bố hoàn tất. Vì vậy, các giá trị mới, không chính xác đã được đặt trong bảng mục tiêu. Trình kích hoạt này sẽ không cần phải thay đổi khi các cột được thêm, xóa, v.v.

caveat Ràng buộc toàn vẹn được thực thi trước khi kích hoạt sau kích hoạt. Vì vậy, bạn không thể đặt trên một ràng buộc kiểm tra để thực thi các hình thức thích hợp của DESC. Bởi vì điều đó sẽ gây ra tuyên bố thất bại trước khi kích hoạt có một cơ hội để sửa chữa bất cứ điều gì. (Vui lòng kiểm tra đoạn này trước khi dựa vào nó tăng gấp đôi Nó được một lúc kể từ khi tôi đã viết một cò..)

+0

Ngoài ra, giải pháp này sẽ không làm cho các giá trị thực sự chèn sẵn cho mệnh đề 'OUTPUT'! –

+0

Trgt là gì trong ngữ cảnh này? – CodenameCain

+1

@CodenameCain Một sai lầm. Nên là 'Tb' hoặc mệnh đề from cần phải là' từ Tb Trgt'. cảm ơn vì đã bắt được điều đó. –

3

Bạn có thể muốn xem xét các kích hoạt INSTEAD OF.

CREATE TRIGGER Tb_InsteadTrigger on Tb 
INSTEAD OF INSERT 
AS 
BEGIN 
... 

Điều này sẽ cho phép bạn thao tác dữ liệu trước khi nó đi vào bảng. Trình kích hoạt có trách nhiệm chèn dữ liệu vào bảng.

24

Tôi không chắc chắn nơi bạn sẽ nhận được giá trị mới thực sự cho desc, nhưng tôi cho rằng bạn đang nhận được nó từ một bảng khác hoặc một số như vậy. Nhưng bạn có thể có một lý do để muốn làm theo cách này vì vậy dưới đây là một ví dụ về cách tôi sẽ đi về nó.

Điều bạn muốn được gọi là trình kích hoạt INSTEAD OF INSERT, nó kích hoạt thay vì chèn trên bảng với mỗi logic bạn đưa ra.

CREATE TRIGGER trgUpdateDesc 
ON Tb 
INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    INSERT INTO Tb (Name, [Desc]) 
    SELECT Name, [Desc] + 'edited' 
    FROM inserted 
END 
GO 

Tôi đã mã hóa từ 'đã chỉnh sửa' ở đó vì tôi không chắc chắn nơi bạn muốn nhận giá trị, nhưng bạn có thể dễ dàng thay thế bằng biến hoặc giá trị từ một bảng khác.

Oh cũng chắc chắn rằng đặt [] xung quanh quyết định, vì nó là một từ quan trọng trong máy chủ sql (viết tắt của giảm dần)

Hy vọng rằng sẽ giúp!

Edit:

Nếu bạn muốn làm cho nó mạnh mẽ hơn một chút để nó không phụ thuộc vào cấu trúc bảng như nhiều bạn có thể sử dụng một SAU INSERT kích hoạt để chỉ cập nhật trường như vậy.

CREATE TRIGGER [dbo].[trgUpdateDesc] 
    ON [dbo].[Tb] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    UPDATE Tb 
    SET [Desc] = UPPER(inserted.[Desc]) + ' Edited' 
    FROM inserted INNER JOIN Tb On inserted.id = Tb.id 
END 
+0

Tôi muốn lấy giá trị của 'Tẩy' và chèn nó vào. Tôi nên nói vậy. Tôi sẽ cập nhật câu hỏi của mình, xin lỗi vì điều đó – BrunoLM

+0

Điều gì sẽ xảy ra nếu bảng của tôi thay đổi? Tôi sẽ phải cập nhật trình kích hoạt mọi lúc? Có cách nào khác để làm điều đó không? – BrunoLM

8

bảng Temp có thể giúp để sử dụng INSTEAD OF INSERT kích hoạt trong khi tránh để liệt kê một cách rõ ràng tất cả các cột bảng không liên quan:

CREATE TRIGGER trgUpdateDesc 
    ON Tb 
    INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    select * into #tmp from inserted; 
    UPDATE #tmp SET Desc = Desc + 'edited' --where ...; 
    insert into Tb select * from #tmp; 
    drop table #tmp; 
END 

Mã này sẽ không cần phải sửa khi cột mới được thêm vào bảng.

Nhưng hãy cẩn thận với some additional overhead of temp tables.

Cũng lưu ý rằng SQL Server kích hoạt một lần cho các hoạt động DML hàng loạt và phải correctly handle multi-row inserts.

+0

Điều này tạo ra lỗi sau: Giá trị rõ ràng cho cột nhận dạng trong bảng 'Tb' chỉ có thể được chỉ định khi danh sách cột được sử dụng và IDENTITY_INSERT được BẬT. –

+1

@Anders, tôi đoán, phương pháp này có thể không tương thích với các cột [IDENTITY] (http://stackoverflow.com/questions/16766963/insert-record-to-sql-table-with-identity-column). Nhưng bạn cũng có thể thử thả cột này trong bảng '# tmp' bên trong trình kích hoạt. – Vadzim

Các vấn đề liên quan