มีวิธีการส่งผ่านข้อมูลไปยังทริกเกอร์การลบเพื่อที่จะได้รู้ว่าใครเป็นผู้ลบบันทึกหรือไม่?
ใช่: โดยใช้มากเย็น (และภายใต้คุณลักษณะใช้) CONTEXT_INFO
เรียกว่า เป็นหน่วยความจำเซสชันหลักที่มีอยู่ในขอบเขตทั้งหมดและไม่ผูกพันตามธุรกรรม มันสามารถใช้ในการส่งผ่านข้อมูล (ข้อมูลใด ๆ - ดีใด ๆ ที่เหมาะกับพื้นที่ จำกัด ) เพื่อเรียกและกลับมาระหว่างการเรียก sub-proc / EXEC และฉันเคยใช้มันมาก่อนในสถานการณ์เดียวกันนี้
ทดสอบกับสิ่งต่อไปนี้เพื่อดูว่ามันทำงานอย่างไร ขอให้สังเกตว่าฉันกำลังแปลงไปก่อนCHAR(128)
CONVERT(VARBINARY(128), ..
นี่คือการบังคับให้เว้นว่างไว้เพื่อให้ง่ายต่อการแปลงกลับไปเป็นVARCHAR
เมื่อได้รับมันออกมาCONTEXT_INFO()
เนื่องจากVARBINARY(128)
มีบุด้วย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];
ผล:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
วางมันทั้งหมดเข้าด้วยกัน:
แอปควรเรียกขั้นตอนการจัดเก็บ "ลบ" ที่ส่งผ่านในชื่อผู้ใช้ (หรืออะไรก็ตาม) ที่จะลบบันทึก ฉันคิดว่านี่เป็นรุ่นที่ใช้อยู่แล้วเพราะดูเหมือนว่าคุณกำลังติดตามการแทรกและการอัปเดตอยู่แล้ว
กระบวนงานที่เก็บไว้ "ลบ" ไม่:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
ทริกเกอร์การตรวจสอบทำ:
-- 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 ชี้ให้เห็นในความคิดเห็นเนื่องจากขั้นตอนอื่น ๆ และ / หรือแบบสอบถามเฉพาะกิจการลบบันทึกจากตารางนี้อาจเป็นไปได้ว่า:
CONTEXT_INFO
ยังไม่ได้ตั้งค่าและยังคงNULL
:
ด้วยเหตุนี้ฉันได้อัปเดตข้างต้นINSERT INTO AuditTable
เพื่อใช้COALESCE
ค่าเริ่มต้น หรือหากคุณไม่ต้องการค่าเริ่มต้นและต้องการชื่อคุณสามารถทำสิ่งที่คล้ายกับ:
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
ได้รับการตั้งค่าเป็นชื่อผู้ใช้ที่ไม่ถูกต้องและอาจเกินขนาดของAuditTable.[UserWhoMadeChanges]
ฟิลด์:
ด้วยเหตุนี้ฉันเพิ่มLEFT
ฟังก์ชั่นเพื่อให้มั่นใจว่าสิ่งที่จะคว้าออกมาจะไม่ทำลายCONTEXT_INFO
INSERT
ตามที่ระบุไว้ในรหัสคุณเพียงแค่ต้องตั้งค่า50
ขนาดจริงของUserWhoMadeChanges
ฟิลด์
อัปเดตสำหรับ SQL Server 2016 และใหม่กว่า
SQL Server 2016 เพิ่มหน่วยความจำต่อเซสชันที่ปรับปรุงแล้วนี้: บริบทบริบท บริบทเซสชันใหม่เป็นหลักตารางแฮชของคู่ค่าคีย์กับ "กุญแจ" เป็นประเภทsysname
(เช่นNVARCHAR(128)
) และ "ราคา" SQL_VARIANT
เป็นอยู่ ความหมาย:
- ขณะนี้มีการแยกค่าเพื่อให้มีโอกาสน้อยที่จะขัดแย้งกับการใช้งานอื่น
- คุณสามารถจัดเก็บประเภทต่าง ๆ ไม่จำเป็นต้องกังวลเกี่ยวกับพฤติกรรมแปลก ๆ เมื่อรับค่ากลับมาทาง
CONTEXT_INFO()
(สำหรับรายละเอียดโปรดดูโพสต์ของฉัน: ทำไมไม่ CONTEXT_INFO () ส่งคืนค่าที่แน่นอนที่กำหนดโดย SET CONTEXT_INFO? )
- คุณได้รับพื้นที่มากขึ้น: สูงสุด 8000 ไบต์ต่อ "ค่า", รวมได้ถึง 256kb สำหรับทุกปุ่ม (เทียบกับ 128 ไบต์สูงสุด
CONTEXT_INFO
)
สำหรับรายละเอียดโปรดดูหน้าเอกสารประกอบต่อไปนี้:
SUSER_SNAME()
เป็นกุญแจสำคัญในการรับผู้ที่ลบบันทึก