Czy istnieje sposób na przekazanie informacji do wyzwalacza usuwania, aby mógł wiedzieć, kto usunął rekord?
Tak: używając bardzo fajnej (i niewykorzystanej funkcji) o nazwie CONTEXT_INFO. Zasadniczo jest to pamięć sesji, która istnieje we wszystkich zakresach i nie jest związana transakcjami. Może być używany do przekazywania informacji (dowolnych informacji - cóż, które mieszczą się w ograniczonej przestrzeni) do wyzwalaczy, a także w obie strony między wywołaniami sub-proc / EXEC. Użyłem go już wcześniej w tej samej sytuacji.
Przetestuj poniższe, aby zobaczyć, jak to działa. Zauważ, że przechodzę CHAR(128)na CONVERT(VARBINARY(128), ... Ma to na celu wymuszenie wypełniania pustego pola, aby ułatwić powrót do niego VARCHARpo wyjściu, CONTEXT_INFO()ponieważ VARBINARY(128)jest on odpowiednio wypełniony za pomocą 0x00s.
SELECT CONTEXT_INFO();
-- Initially = NULL
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), 'I deleted ALL your records! HA HA!')
);
SET CONTEXT_INFO @EncodedUser;
SELECT CONTEXT_INFO() AS [RawContextInfo],
RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())) AS [DecodedUser];
Wyniki:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
KŁADĄC WSZYSTKO RAZEM:
Aplikacja powinna wywołać procedurę przechowywaną „Usuń”, która przechodzi w nazwę użytkownika (lub cokolwiek innego), która usuwa rekord. Zakładam, że jest to już używany model, ponieważ wygląda na to, że śledzisz już operacje wstawiania i aktualizacji.
Procedura przechowywana „Usuń”:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
Wyzwalacz kontroli:
-- Set the INT value in LEFT (currently 50) to the max size of [UserWhoMadeChanges]
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
SELECT del.ID, COALESCE(
LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50),
'<unknown>')
FROM DELETED del;
Należy pamiętać, że jak zauważył @SeanGallardy w komentarzu, z powodu innych procedur i / lub zapytań ad hoc usuwających rekordy z tej tabeli, możliwe jest, że:
CONTEXT_INFOnie został ustawiony i nadal jest NULL:
Z tego powodu zaktualizowałem powyższe, INSERT INTO AuditTableaby użyć COALESCEdomyślnej wartości. Lub, jeśli nie chcesz wartości domyślnej i potrzebujesz nazwy, możesz zrobić coś podobnego do:
DECLARE @UserName VARCHAR(50); -- set to the size of AuditTable.[UserWhoMadeChanges]
SET @UserName = LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50);
IF (@UserName IS NULL)
BEGIN
ROLLBACK TRAN; -- cancel the DELETE operation
RAISERROR('Please set UserName via "SET CONTEXT_INFO.." and try again.', 16 ,1);
END;
-- use @UserName in the INSERT...SELECT
CONTEXT_INFOzostała ustawiona na wartość, która nie jest prawidłową nazwą użytkownika, a zatem może przekraczać rozmiar AuditTable.[UserWhoMadeChanges]pola:
Z tego powodu dodałem LEFTfunkcję zapewniającą, że cokolwiek zostanie złapane, CONTEXT_INFOnie złamie INSERT. Jak zaznaczono w kodzie, wystarczy ustawić 50rzeczywisty rozmiar UserWhoMadeChangespola.
AKTUALIZACJA DLA SQL Server 2016 i nowszych
SQL Server 2016 dodał ulepszoną wersję tej pamięci na sesję: kontekst sesji. Nowy kontekst sesji jest w zasadzie tabelą skrótów par klucz-wartość z „kluczem” będącym typem sysname(tj. NVARCHAR(128)) I „wartością” SQL_VARIANT. Znaczenie:
- Istnieje teraz rozdział wartości, więc mniejsze prawdopodobieństwo konfliktu z innymi zastosowaniami
- Możesz przechowywać różne typy, nie martwiąc się już o dziwne zachowanie podczas odzyskiwania wartości za pośrednictwem
CONTEXT_INFO()(szczegółowe informacje znajdują się w moim poście: Dlaczego CONTEXT_INFO () Zwraca dokładną wartość ustawioną przez SET CONTEXT_INFO? )
- Dostajesz o wiele więcej miejsca: maks. 8000 bajtów na „wartość”, łącznie do 256 kb na wszystkie klucze (w porównaniu do maks. 128 bajtów
CONTEXT_INFO)
Aby uzyskać szczegółowe informacje, zobacz następujące strony dokumentacji:
SUSER_SNAME()jest kluczem do ustalenia, kto usunął rekord.