簡體   English   中英

如何在 SQL Server 中創建接受外部參數的觸發器?

[英]How to create triggers which accepts external parameters in SQL Server?

是否可以編寫一個接受外部參數的觸發器?

這樣做的主要原因是,我只能使用一個數據庫用戶連接到數據庫。 現在我正在開發一個數據庫應用程序,並為每個單獨的表創建了觸發器來存儲歷史記錄。

在存儲歷史數據時,我想存儲完成InsertUpdateDelete應用程序用戶名 我想使用User_Name()但后來知道,它只返回數據庫用戶,而不是應用程序用戶。

因此,我正在尋找一些關於使用外部參數創建觸發器的建議,以便我可以將應用程序用戶的 id 傳遞給此觸發器。 認為我已經清楚地解釋了我的需求。 提前致謝 !

編輯
外部參數應該類似於我們可以傳遞值的存儲過程參數

編輯2
可能是我的描述不夠清楚。 所以我給你舉個例子。
我正在開發的 Web 應用程序與帳戶相關。 所以要跟蹤所需的數據變化。 例如,客戶人員可以更改員工的工資和佣金信息。 如果輸入/更新了錯誤的信息,那么整體財務結果將產生巨大的負面影響。 現在在系統中,一個用戶使用用戶名和密碼登錄系統,然后對員工信息進行一些更改。 在這個階段,我想保持跟蹤,誰更改了員工信息,何時更改以及更改完成之前的值和更改完成后的值。 這樣,將來如果出現任何問題,我可以通過 PROOF 找出犯錯的用戶。
不一定應該使用觸發器來完成,但也歡迎任何其他替代方法。

你需要重新設計你的方法。 數據庫無法只知道有關您的應用程序用戶信息的任何信息。 而且,不,您不能將參數傳遞給觸發器。 但是你可以從 withing 觸發器中引用你自己的表,所以有一種方法......


當您連接到數據庫時,每個連接都會獲得它自己的進程 ID。 您可以通過@@spid 獲得此信息。

因此,當您的觸發器觸發時,您可以使用它來了解導致更改的連接。

您可以使用同一個數據庫登錄擁有 100 個並發連接,每個連接都有自己的 @@spid 值。


但是,為了對您有用,您需要准備所有連接。 每次建立連接時,您的應用程序都應該寫入一個表以記錄使用該@@spid 的應用程序使用情況。

也許像這樣簡單的事情...

CREATE TABLE
  map_spid_application_user (
    spid          BIGINT,
    application   VARCHAR(128),
    user          VARCHAR(128),
    PRIMARY KEY (spid)
  )

然后,在每個連接上,運行這樣的東西(也許通過存儲過程)...

DELETE map_spid_application_user WHERE spid = @@spid

INSERT INTO map_spid_application_user SELECT @@spid, 'myApp', 'myUser'


然后,在您的觸發器中,您可以引用/加入該表以找出@@spid 所指的對象。


您還可以變得更加智能,並使用類似的方法來永久記錄用戶連接的內容,例如 spid。 任何 spid 的當前用戶將始終是具有最近連接日期時間的用戶。


那時你幾乎可以做任何你喜歡的事情。 因為您正在創建所有信息,而不是依靠數據庫來了解@@spid 以外的任何信息。

將用戶名存儲在每個表中,並在數據更改時將其作為參數傳入。 從那里,觸發器可以將數據存檔到另一個表。

在你的地方,我將使用這個例子,如果在你的數據庫中有人會進行事件更新或選擇,你將能夠添加一些你想要的信息。

示例表:

CREATE TABLE RAF1
(
strona NUMBER,
nazwa VARCHAR2(40)
);

示例觸發器(如果您將 nazw='same' 寫入 nazwa='roland' 它連接到此表,您可以編輯此示例,則此觸發器將始終存在。

create or replace TRIGGER sam 
BEFORE INSERT OR UPDATE OF nazwa
 ON RAF1 FOR EACH ROW WHEN (new.nazwa = 'same')
 BEGIN :new.nazwa := 'ronald'; END

由於觸發器是設計的niladic模塊,這意味着它們不支持參數。 在外層和 niladic 模塊之間傳遞信息的一種技術是使用上下文信息或會話上下文。

Declare @mycontextinfo AS VARBINARY(128) = CAST('Application User Name' AS VARBINARY(128))
SET CONTEXT_INFO @mycontextinfo;

您可以從會話中的任何位置讀取上下文信息,包括如下觸發器:

SELECT CAST(CONTEXT_INFO() AS VARCHAR(128)) AS mycontextinfo;

另一種最復雜的方法是使用會話上下文;

EXEC sys.sp_set_Session_context @key = 'ApplicationUser', @value = 'XXX', @read_only = 1;

然后,當您需要從會話中的任何位置讀取值時,您可以使用以下代碼:

SELECT SESSION_CONTEXT('ApplicationUser') AS [USER]

請記住,這是在 SQL Server 2016 中添加的。

我已經按照你的描述做了。 我不能說我對結果感到滿意,因為解決方案可能相當脆弱 - 當發生連接共享等奇怪的事情時會中斷。 它也只是感覺不對,但如果您願意,可以嘗試一下。

  1. 在應用程序端,將用戶名填充到 ConnectionString 的 AppName 屬性中。
  2. 在觸發器中,引用 App_Name() 函數。

同樣,這將按照您的要求執行,但我不建議這樣做。 最好將審計信息作為來自客戶端或通過存儲過程的基本插入/更新內容的一部分進行管理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM