如何在SQL Server中创建接受外部参数的触发器?

时间:2012-03-21 11:43:35

标签: c# sql sql-server

是否可以编写一个接受外部参数的触发器?

主要原因是,我只能使用 ONE 数据库用户连接到数据库。现在我正在开发一个数据库应用程序,并为每个表创建了触发器以存储历史记录。

在存储历史数据时,我想存储已完成InsertUpdateDelete应用用户名。我想使用User_Name(),但后来才知道,它只返回数据库用户 NOT 应用程序用户。

因此,我正在寻找有关使用外部参数创建触发器的一些建议,以便我可以将应用程序用户的id传递给此触发器。认为我已经清楚地解释了我的需求。提前致谢 !

修改
外部参数应该与存储过程参数类似,我们可以传递值

EDIT2
可能是我的描述不够明确。所以我给你举个例子 我正在开发的Web应用程序是与帐户相关的。因此要跟踪所需的数据变化。例如,帐户人员可以更改员工的薪资和佣金信息。如果输入/更新了错误的信息,那么整体财务结果将产生很大的负面影响。现在在系统中,用户使用userid&amp ;;登录到系统。密码,然后对员工信息进行一些更改。在这个阶段,我希望保留已更改员工信息的跟踪,更改完成之前的更改时间以及更改完成后的值。所以,将来如果出现任何问题,我可以找出用PROOF做错的用户 不一定应该使用触发器,但也欢迎任何其他替代方案。

5 个答案:

答案 0 :(得分:5)

您需要重新设计自己的方法。数据库无法只知道有关您的应用程序用户信息的任何信息。并且,不,您不能将参数传递给触发器。但是您可以使用触发器引用自己的表,因此有一种方法......


当您连接到数据库时,每个连接都会获得它自己的进程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之外的任何其他信息。

答案 1 :(得分:1)

将用户名存储在每个表中,并在数据更改期间将其作为参数传递。从那里,触发器可以将数据存档到另一个表。

答案 2 :(得分:1)

在你的位置我将使用这个例子,如果你在yor数据库中有人会做事件更新或选择你可以添加一些你想要的信息。

示例表:

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

答案 3 :(得分:0)

我做了你描述的事情。我不能说我对结果感到满意,因为解决方案可能相当脆弱 - 当发生类似连接共享的奇怪事情时会破坏。它也只是感觉不对,但如果你愿意,可以尝试一下。

  1. 在应用程序端,将用户名填入ConnectionString的AppName属性。
  2. 在触发器中,引用App_Name()函数。
  3. 同样,这会做你要求的,但我不推荐它。最好只管理审计信息,作为客户端或存储过程的基本插入/更新内容的一部分。

答案 4 :(得分:0)

由于触发器是根据设计的 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中添加的。