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 VARCHARarasında dışarı alırken CONTEXT_INFO()beri VARBINARY(128)birlikte sağ yastıklı olduğunu 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];
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_INFOayarlanmadı ve hala NULL:
Bu nedenle , değeri varsayılan INSERT INTO AuditTableolarak 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 LEFTdışarı yakaladı ne olursa olsun sağlamak için işlevini CONTEXT_INFOkırmak olmaz INSERT. Kodda belirtildiği gibi, sadece alanın 50gerç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.