Лучший способ определить, какие столбцы были обновлены при использовании триггеров - PullRequest
2 голосов
/ 29 октября 2010

У меня есть пользовательская таблица, которая имеет | Имя | Фамилия | DateOfBirth | ... и несколько других столбцов. В этой конкретной таблице у меня есть триггер при обновлении, который, если кто-то изменяет какие-либо пользовательские значения, создает аудит.

Моя проблема в том, что руководство хочет, чтобы визуальный аудит отображался следующим образом:

DateChanged |Change                        |Details
--------------------------------------------------------------------------------
2010/01/01  |FirstName Changed             |FirstName Changed from "John" to "Joe"  
2010/01/01  |FirstName And Lastname Changed|FirstName Changed from "Smith" to "White "And Lastname changed from "els" to "brown"
2010/01/01  |User Deleted                  |"ark Anrdrews" was deleted

Я считаю, что лучший способ справиться с этим - изменить сохраненный процесс, но как я могу дать команду триггеру записывать подобные вещи?

Ответы [ 2 ]

5 голосов
/ 29 октября 2010

В триггере есть функция, которую вы можете вызвать COLUMS_UPDATED (). Это возвращает растровое изображение столбцов в таблице триггеров, где 1 указывает, что соответствующий столбец в таблице был изменен. Само по себе это не блестяще, так как вы получили бы список индексов столбцов и все равно должны были бы написать оператор CASE, чтобы определить, какие столбцы были изменены. Если у вас не так много столбцов, которые могут быть не такими уж плохими, но если вы хотите что-то более общее, вы можете присоединиться к information_schema.columns для преобразования индексов этих столбцов в имена столбцов

Вот небольшой пример, показывающий, что вы можете сделать:

CREATE TABLE test (
ID Int NOT null IDENTITY(1,1),
NAME VARCHAR(50),
Age INT
)

 GO
---------------------------------------
CREATE TRIGGER tr_test ON test FOR UPDATE 

AS

DECLARE @cols varbinary= COLUMNS_UPDATED()
DECLARE @altered TABLE(colid int)
DECLARE @index int=1

WHILE @cols>0 BEGIN
    IF @cols & 1 <> 0 INSERT @altered(colid) VALUES(@index)
    SET @index=@index+1
    SET @cols=@cols/2
END 

DECLARE @text varchar(MAX)=''
SELECT @text=@text+C.COLUMN_NAME+', '
FROM information_schema.COLUMNS C JOIN @altered A ON c.ordinal_position=A.colid
WHERE table_name='test'

PRINT @text

GO
------------------------------------------------------
INSERT test(NAME, age) VALUES('test',12)
UPDATE test SET age=15
UPDATE test SET NAME='fred'
UPDATE test SET age=18,NAME='bert'
DROP TABLE test
1 голос
/ 29 октября 2010

MS SQL Server имеет функцию UPDATED (). Он позволяет вам указать имя поля, чтобы указать, было ли какое-либо изменение в этом поле.

Мой опыт, однако, заключается в том, что желаемая функциональность часто выходит за пределы такой обобщенной функции. Обычно я просто присоединяю псевдо-таблицу INSERTED к псевдо-таблице DELETED и сравниваю их сам.

* Такое сравнение предполагало, что таблица имеет уникальный идентификатор, будь то отдельное поле или составной ключ некоторого вида.

...