Kaydı kimin sildiğini bilecek şekilde Sil tetikleyicisine bilgi aktarmanın bir yolu var mı?
Evet: çok serin (ve az kullanılan özellik) kullanarak denir CONTEXT_INFO
. Esasen tüm kapsamlarda bulunan ve işlemlere bağlı olmayan oturum hafızasıdır. Bilgi (herhangi bir bilgi - iyi, sınırlı alana uyan herhangi bir bilgi) tetikleyicilere ve alt proc / EXEC çağrıları arasında ileri geri iletmek için kullanılabilir. Ve daha önce aynı durum için kullandım.
Nasıl çalıştığını görmek için aşağıdakileri test edin. Ben CHAR(128)
önce dönüştürmek dikkat edin CONVERT(VARBINARY(128), ..
. Bu daha kolay geri dönüştürme yapmak için kuvvet boş-dolgu etmektir VARCHAR
arasında dışarı alırken CONTEXT_INFO()
beri VARBINARY(128)
birlikte sağ yastıklı olduğunu 0x00
s.
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];
Sonuçlar:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
HEPSİNİ BİR ARAYA KOY:
Uygulama, Kaydı silen KullanıcıAdı'na (veya her neyse) geçen "Sil" saklı yordamını çağırmalıdır. Zaten Ekle ve Güncelle işlemlerini izliyormuş gibi göründüğünden, bunun zaten kullanılan model olduğunu varsayıyorum.
"Sil" saklı yordamı şunları yapar:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
Denetim tetikleyicisi şunları yapar:
-- 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;
@SeanGallardy'nin bir yorumda işaret ettiği gibi, bu tabloda kayıtların silinmesine ilişkin diğer prosedürler ve / veya geçici sorgular nedeniyle aşağıdakilerden birinin mümkün olabileceğini lütfen unutmayın:
CONTEXT_INFO
ayarlanmadı ve hala NULL
:
Bu nedenle , değeri varsayılan INSERT INTO AuditTable
olarak kullanmak için yukarıdakileri güncelledim COALESCE
. Veya bir varsayılan istemiyorsanız ve bir ad gerektiriyorsanız, aşağıdakine benzer bir şey yapabilirsiniz:
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_INFO
, geçerli bir KullanıcıAdı olmayan bir değere ayarlanmıştır ve bu nedenle AuditTable.[UserWhoMadeChanges]
alanın boyutunu aşabilir :
Bu nedenle ben bir katma LEFT
dışarı yakaladı ne olursa olsun sağlamak için işlevini CONTEXT_INFO
kırmak olmaz INSERT
. Kodda belirtildiği gibi, sadece alanın 50
gerçek boyutuna ayarlamanız gerekir UserWhoMadeChanges
.
SQL SERVER 2016 VE YENİ İÇİN GÜNCELLEME
SQL Server 2016, bu oturum başına belleğin geliştirilmiş bir sürümünü ekledi: Oturum Bağlamı. Yeni Oturum Bağlamı, temelde Anahtar-Değer çiftlerinin bir karma tablosu olup, "Anahtar" tip sysname
(yani NVARCHAR(128)
) ve "Değer" varlıktır SQL_VARIANT
. Anlamı:
- Artık diğer kullanımlar ile çatışması daha düşük olan değerlerin ayrılması
- Değeri geri alırken artık garip davranışlar hakkında endişelenmenize gerek olmayan çeşitli türleri saklayabilirsiniz
CONTEXT_INFO()
(ayrıntılar için lütfen gönderime bakın: CONTEXT_INFO () SET CONTEXT_INFO tarafından ayarlanan Tam Değeri neden döndürmüyor? )
- Çok daha fazla alan elde edersiniz : "Değer" başına maksimum 8000 bayt, tüm tuşlarda toplam 256 kb'ye kadar (maks. 128 bayt ile karşılaştırıldığında
CONTEXT_INFO
)
Ayrıntılar için lütfen aşağıdaki dokümantasyon sayfalarına bakın:
SUSER_SNAME()
kaydı kimin sildiğinin anahtarıdır.