Podczas konfigurowania ścieżki audytu nie mam problemu ze śledzeniem, kto aktualizuje lub wstawia rekordy do tabeli, jednak śledzenie, kto usuwa rekordy, wydaje się bardziej problematyczne.
Mogę śledzić Wstawki / Aktualizacje, umieszczając w polu Wstaw / Aktualizuj pole „Zaktualizowany przez”. Dzięki temu wyzwalacz INSERT / UPDATE ma dostęp do pola „Zaktualizowany przez” za pośrednictwem inserted.UpdatedBy
. Jednak w przypadku wyzwalacza Usuń żadne dane nie są wstawiane / aktualizowane. Czy istnieje sposób na przekazanie informacji do wyzwalacza usuwania, aby mógł wiedzieć, kto usunął rekord?
Oto wyzwalacz Wstaw / Aktualizuj
ALTER TRIGGER [dbo].[trg_MyTable_InsertUpdate]
ON [dbo].[MyTable]
FOR INSERT, UPDATE
AS
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
VALUES (inserted.ID, inserted.LastUpdatedBy)
FROM inserted
Korzystanie z SQL Server 2012
sql-server
sql-server-2012
trigger
audit
webworm
źródło
źródło
SUSER_SNAME()
jest kluczem do ustalenia, kto usunął rekord.SUSER_SNAME()
aby działał w sytuacji takiej jak aplikacja internetowa, w której do komunikacji z bazą danych dla całej aplikacji może być używany pojedynczy użytkownik.Odpowiedzi:
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.Informacje kontekstowe to VARBINARY (128)
Ustaw za pomocą: SET CONTEXT_INFO
Uzyskaj przez: CONTEXT_INFO ()
Przetestuj poniższe, aby zobaczyć, jak to działa. Zauważ, że przechodzę
CHAR(128)
naCONVERT(VARBINARY(128), ..
. Ma to na celu wymuszenie wypełniania pustego pola, aby ułatwić powrót do niegoVARCHAR
po wyjściu,CONTEXT_INFO()
ponieważVARBINARY(128)
jest on odpowiednio wypełniony za pomocą0x00
s.Wyniki:
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ń”:
Wyzwalacz kontroli:
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_INFO
nie został ustawiony i nadal jestNULL
:Z tego powodu zaktualizowałem powyższe,
INSERT INTO AuditTable
aby użyćCOALESCE
domyślnej wartości. Lub, jeśli nie chcesz wartości domyślnej i potrzebujesz nazwy, możesz zrobić coś podobnego do:CONTEXT_INFO
została ustawiona na wartość, która nie jest prawidłową nazwą użytkownika, a zatem może przekraczać rozmiarAuditTable.[UserWhoMadeChanges]
pola:Z tego powodu dodałem
LEFT
funkcję zapewniającą, że cokolwiek zostanie złapane,CONTEXT_INFO
nie złamieINSERT
. Jak zaznaczono w kodzie, wystarczy ustawić50
rzeczywisty rozmiarUserWhoMadeChanges
pola.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:CONTEXT_INFO()
(szczegółowe informacje znajdują się w moim poście: Dlaczego CONTEXT_INFO () Zwraca dokładną wartość ustawioną przez SET CONTEXT_INFO? )CONTEXT_INFO
)Aby uzyskać szczegółowe informacje, zobacz następujące strony dokumentacji:
źródło
@@SPID
. Jest to pamięć na sesję / połączenie. Jedna sesja nie może zastąpić informacji kontekstowych innej sesji. A kiedy sesja się wylogowuje, wartość zanika. Nie ma czegoś takiego jak „wcześniej ustawiony element”.Nie możesz tego zrobić, chyba że chcesz zapisać identyfikator użytkownika serwera SQL zamiast aplikacji na poziomie pierwszym.
Możesz wykonać miękkie usuwanie, mając kolumnę o nazwie UsunięteBy i ustawiając ją w razie potrzeby, a następnie wyzwalacz aktualizacji może wykonać prawdziwe usunięcie (lub zarchiwizować rekord, na ogół unikam twardego usuwania, jeśli to możliwe i legalne), a także aktualizując dziennik audytu . Aby wymusić usunięcie w ten sposób, zdefiniuj
on delete
wyzwalacz, który wywołuje błąd. Jeśli nie chcesz dodawać kolumny do tabeli fizycznej, możesz zdefiniować widok, który dodaje kolumnę i zdefiniowaćinstead of
wyzwalacze do obsługi aktualizacji tabeli podstawowej, ale może to być przesada.źródło
SPARSE
kolumny SQL Server ?Tak, najwyraźniej istnieją dwa sposoby ;-). Jeśli istnieją jakiekolwiek zastrzeżenia do używania,
CONTEXT_INFO
jak zasugerowałem w mojej innej odpowiedzi tutaj , właśnie pomyślałem o innym sposobie, który ma czystsze funkcjonalne oddzielenie od innych kodów / procesów: użyj lokalnej tabeli tymczasowej.Nazwa tabeli tymczasowej powinna zawierać nazwę tabeli usuwanej, ponieważ pomoże to oddzielić ją od wszelkich innych kodów, które mogą się zdarzyć w tej samej sesji. Coś w stylu:
#<TableName>DeleteAudit
Zaletą lokalnej tabeli temp.
CONTEXT_INFO
Jest to, że jeśli ktoś w innym proc - czyli w jakiś sposób wywołuje ten konkretny proces „Usuń” - po prostu niepoprawnie używa tej samej nazwy tabeli temp, podproces a) utworzy nowy lokalny tabela tymczasowa żądanej nazwy, która będzie oddzielna od początkowej tabeli tymczasowej (mimo że ma taką samą nazwę), oraz b) wszelkie instrukcje DML względem nowej lokalnej tabeli tymczasowej w podprocesie nie wpłyną na żadne dane w lokalna tabela temp utworzona tutaj w procesie nadrzędnym, a zatem nie ma zastępowania danych. Oczywiście, jeśli kwestie podproces oświadczenie DML przeciwko tej temp nazwy tabeli bez uprzedniego wydawania CREATE TABLE tej samej nazwie, a następnie te oświadczenia DML będzie wpływać na dane w tej tabeli. ALE, w tym momencie stajemy się naprawdętutaj przypadek, nawet bardziej niż z prawdopodobieństwem nakładających się zastosowańCONTEXT_INFO
(tak, wiem, że tak się stało, dlatego mówię „przypadek”, a nie „nigdy się nie zdarzy”).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ń”:
Wyzwalacz kontroli:
Przetestowałem ten kod w wyzwalaczu i działa zgodnie z oczekiwaniami.
źródło