我正在研究SQL Server
。我要记录一些我的Table活动。所以我创建了一个审计表,如下所示:
IF NOT EXISTS
(SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[dbo].[Audit]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
CREATE TABLE Audit
(Type CHAR(1),
TableName VARCHAR(128),
PK VARCHAR(1000),
FieldName VARCHAR(128),
OldValue VARCHAR(1000),
NewValue VARCHAR(1000),
UpdateDate datetime,
UserName VARCHAR(128))
GO
我有一张表'位置'我创建了触发器来捕获表中的所有活动,如下所示:
ALTER TRIGGER [dbo].[TR_lOCATION_AUDIT]
ON [dbo].[lOCATION] FOR UPDATE,INSERT,DELETE
AS
DECLARE @bit INT ,
@field INT ,
@maxfield INT ,
@char INT ,
@fieldname VARCHAR(128) ,
@TableName VARCHAR(128) ,
@PKCols VARCHAR(1000) ,
@sql VARCHAR(2000),
@UpdateDate VARCHAR(21) ,
@UserName VARCHAR(128) ,
@Type CHAR(1) ,
@PKSelect VARCHAR(1000)
--You will need to change @TableName to match the table to be audited.
-- Here we made GUESTS for your example.
SELECT @TableName = 'lOCATION'
-- date and user
SELECT @UserName = SYSTEM_USER ,
@UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112)
+ ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)
-- Action
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT @Type = 'U'
ELSE
SELECT @Type = 'I'
ELSE
SELECT @Type = 'D'
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT @PKCols = COALESCE(@PKCols + ' and', ' on')
+ ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT @PKSelect = COALESCE(@PKSelect+'+','')
+ '''<' + COLUMN_NAME
+ '=''+convert(varchar(100),
coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''>'''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF @PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, @TableName)
RETURN
END
SELECT @field = 0,
@maxfield = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName
WHILE @field < @maxfield
BEGIN
SELECT @field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION > @field
SELECT @bit = (@field - 1 )% 8 + 1
SELECT @bit = POWER(2,@bit - 1)
SELECT @char = ((@field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0
OR @Type IN ('I','D')
BEGIN
SELECT @fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION = @field
SELECT @sql = '
insert Audit ( Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName)
select ''' + @Type + ''','''
+ @TableName + ''',' + @PKSelect
+ ',''' + @fieldname + ''''
+ ',convert(varchar(1000),d.' + @fieldname + ')'
+ ',convert(varchar(1000),i.' + @fieldname + ')'
+ ',''' + @UpdateDate + ''''
+ ',''' + @UserName + ''''
+ ' from #ins i full outer join #del d'
+ @PKCols
+ ' where i.' + @fieldname + ' <> d.' + @fieldname
+ ' or (i.' + @fieldname + ' is null and d.'
+ @fieldname
+ ' is not null)'
+ ' or (i.' + @fieldname + ' is not null and d.'
+ @fieldname
+ ' is null)'
EXEC (@sql)
END
END
这很好用。但是我的最后一列是username.here我想从我的应用程序中获取价值。(谁登录了应用程序)。这个应用程序安装了几台计算机并在同一个数据库上工作,同时记录应用程序我我拿他的用户名......实际上我想在这里显示那个用户名..我怎么能把这个值传递到这里
如何将c#应用程序中的一个值传递给此.username列我想显示此传递的值
任何帮助都非常明显..
答案 0 :(得分:1)
有两种方法可以做到。
方式:1
只需使用新列UserName更改表,并在访问表时插入/更新列。可以从触发器访问表中插入/更新的值。
方式:2(看起来很疯狂)
首先创建一个附加表来保存可在Trigger中访问的数据。
CREATE TABLE [dbo].[TriggerData](
[GUID] [uniqueidentifier] NOT NULL,
[USERNAME] [nvarchar](max) NULL
) ON [PRIMARY]
然后,在将数据更新到实际表的Sql查询之前,将所需的附加信息存储在触发器中以便可访问此表。
DECLARE @id uniqueidentifier;
SET @id = NEWID();
INSERT INTO TriggerData VALUES (@id, 'USER NAME');
接下来,将唯一ID与当前会话相关联。
DECLARE @context_info varbinary(100);
SET @context_info = cast(@id as varbinary(100));
SET CONTEXT_INFO @context_info;
现在,进入Trigger,以下是如何在Trigger中访问此信息:
CREATE TRIGGER [dbo].[TriggerName]
ON [dbo].[Reservations]
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE @id uniqueidentifier;
SELECT @id = CAST(CONTEXT_INFO() as uniqueidentifier);
DECLARE @USERNAMEnvarchar(MAX);
SELECT @USERNAME= USERNAME
FROM TriggerData
WHERE [GUID] = @id;
-- More sql statements, use @USERNAME for the external information.
DELETE FROM TriggerData WHERE [GUID] = @id;
END
将代码放在insert / update和delete命令之前。
DECLARE @id uniqueidentifier;
SET @id = NEWID();
INSERT INTO TriggerData VALUES (@id, 'USER NAME');
DECLARE @context_info varbinary(100);
SET @context_info = cast(@id as varbinary(100));
SET CONTEXT_INFO @context_info;
答案 1 :(得分:0)
@Veera的答案非常适合使用SQL Server
进行使用唯一ID进行审核,但正如您提到C#
应用程序,您可以创建一个包含用户名的Static class
和应用程序中需要的任何其他变量。
在你的情况下,它会是这样的:
public static class UserInfo
{
public static string UserID;
}
现在使用登录表单
在用户登录期间获取UserIDUserInfo.UserID=Textbox1.Text;
然后您可以从代码中的任何位置访问UserID:
string UserID="";
UserID= UserInfo.UserID
我已经显示了使用和不使用SP的两种情况来从C#
应用程序传递UserID并将其存储在数据库中
没有SP
Using (SqlConnection sqlconn=new
SqlConnection(ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
DataSet ds=new DataSet()
byte[] Context_Info;
sqlconn.open();
string sql1 = "Select cast('UserID='+CONVERT(varchar(10),@UserID)
+REPLICATE(' ',128) as varbinary(128)) Context_Info";
string sql2 = "do Insert / Update / Delete that will fire the trigger";
using (SqlCommand command = new SqlCommand(sql1,sqlconn))
{
//Command 1
using (SqlDataAdapter da = new SqlDataAdapter(command))
{
da.Fill(ds);
Context_Info=(byte[])ds.Tables[0].Rows[0]["Context_Info"];
}
}
using (Sqlcommand cmd=new Sqlcommand(sql1,sqlConn))
{
//Pass both context info and User id
cmd.Parameters.AddWithValue("@ContextInfo ",ContextInfo);
cmd.Parameters.AddWithValue("@UserID",UserID);
cmd.ExceuteNonQuery();
}
}
使用SP
Using (SqlConnection Sqlconn=new
SqlConnection(ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
Sqlconn.open();
Using (Sqlcommand cmd=new Sqlcommand())
{
cmd.CommandType=CommandType.StoredProcedure;
cmd.CommandText="Data_Ins_Upd_Del";
cmd.Parameters.AddWithValue("@UserID",UserID);
cmd.ExceuteNonQuery();
cmd.Parameters.Clear();
}
}
并在SQL Server
创建类似SP的
Create Procedure Data_Ins_Upd_Del
(
@UserID Varchar(50)
)
AS
Begin
Begin Try
Declare @CONTEXT_INFO Varbinary(max)
SET @CONTEXT_INFO =cast('UserID='+CONVERT(varchar(10),@UserID)
+REPLICATE(' ',128) as varbinary(128))
SET CONTEXT_INFO @CONTEXT_INFO
/* Do Insert / Update / Delete that will fire the trigger */
SET CONTEXT_INFO 0x0
End Try
Begin Catch
Declare @Errmsg Varchar(max),@ErrSeverity int
Set @Errmsg=ERROR_MESSAGE()
Set @ErrSeverity=ERROR_SEVERITY()
Raiserror(@Errmsg,@ErrSeverity,1)
End Catch
End
并在Trigger中添加以下行
ALTER TRIGGER [dbo].[TR_lOCATION_AUDIT]
ON [dbo].[lOCATION] FOR UPDATE,INSERT,DELETE
AS
DECLARE @bit INT ,
@field INT ,
@maxfield INT ,
@char INT ,
@fieldname VARCHAR(128) ,
@TableName VARCHAR(128) ,
@PKCols VARCHAR(1000) ,
@sql VARCHAR(2000),
@UpdateDate VARCHAR(21) ,
@UserName VARCHAR(128) ,
@Type CHAR(1) ,
@PKSelect VARCHAR(1000),
@UserID varchar(50), //New Line
@sCONTEXT_INFO varchar(128)//New Line
//Start of new Line in Trigger
SELECT @sCONTEXT_INFO=CAST(CONTEXT_INFO() AS VARCHAR) FROM master.dbo.SYSPROCESSES WHERE SPID=@@SPID
IF Substring(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-15,8) like '%UserID%'
BEGIN
SET @UserID=RIGHT(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-7) //New Line
END
ELSE
BEGIN
RAISERROR('@UserID was not specified',16,1)
ROLLBACK TRAN
RETURN
END
//End of new Line in Trigger
--You will need to change @TableName to match the table to be audited.
-- Here we made GUESTS for your example.
SELECT @TableName = 'lOCATION'
-- date and user
SELECT @UserName = @UserID,
@UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112)
+ ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)
-- Action
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT @Type = 'U'
ELSE
SELECT @Type = 'I'
ELSE
SELECT @Type = 'D'
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT @PKCols = COALESCE(@PKCols + ' and', ' on')
+ ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT @PKSelect = COALESCE(@PKSelect+'+','')
+ '''<' + COLUMN_NAME
+ '=''+convert(varchar(100),
coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''>'''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF @PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, @TableName)
RETURN
END
SELECT @field = 0,
@maxfield = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName
WHILE @field < @maxfield
BEGIN
SELECT @field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION > @field
SELECT @bit = (@field - 1 )% 8 + 1
SELECT @bit = POWER(2,@bit - 1)
SELECT @char = ((@field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0
OR @Type IN ('I','D')
BEGIN
SELECT @fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION = @field
SELECT @sql = '
insert Audit ( Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName)
select ''' + @Type + ''','''
+ @TableName + ''',' + @PKSelect
+ ',''' + @fieldname + ''''
+ ',convert(varchar(1000),d.' + @fieldname + ')'
+ ',convert(varchar(1000),i.' + @fieldname + ')'
+ ',''' + @UpdateDate + ''''
+ ',''' + @UserID + ''''
+ ' from #ins i full outer join #del d'
+ @PKCols
+ ' where i.' + @fieldname + ' <> d.' + @fieldname
+ ' or (i.' + @fieldname + ' is null and d.'
+ @fieldname
+ ' is not null)'
+ ' or (i.' + @fieldname + ' is not null and d.'
+ @fieldname
+ ' is null)'
EXEC (@sql)
END
END
注意:我输入的Substring
长度是根据我的测试数据根据您的参数长度更改
已编辑SP
ALTER Procedure [dbo].[Data_Ins_Upd_Del]
(
@UserID Varchar(50),
@state varchar(100),
@dist varchar(100)
)
AS
Begin
Begin Try
Declare @CONTEXT_INFO Varbinary(max)
SET @CONTEXT_INFO =cast('UserID='+CONVERT(varchar(10),@UserID)
+REPLICATE(' ',128) as varbinary(128))
SET CONTEXT_INFO @CONTEXT_INFO
/* Do Insert / Update / Delete that will fire the trigger */
insert into State_tbl(StateName,District)values(@State,@dist)
SET CONTEXT_INFO 0x0
End Try
Begin Catch
Declare @Errmsg Varchar(max),@ErrSeverity int
Set @Errmsg=ERROR_MESSAGE()
Set @ErrSeverity=ERROR_SEVERITY()
Raiserror(@Errmsg,@ErrSeverity,1)
End Catch
End
以下是我用来测试场景的查询和触发器
Declare @UserID varchar(50)='Usr-120',
@CONTEXT_INFO Varbinary(max)
SET @CONTEXT_INFO =cast('UserID='+CONVERT(varchar(10),@UserID)
+REPLICATE(' ',128) as varbinary(128))
SET CONTEXT_INFO @CONTEXT_INFO
Insert into existing(UserName) Values(@UserID)
SET CONTEXT_INFO 0x0
<强>触发强>
Alter Trigger trgExisting
on Existing for Insert,Update,Delete
as
DECLARE @UserID varchar(50)
,@sCONTEXT_INFO varchar(128)
SELECT @sCONTEXT_INFO=CAST(CONTEXT_INFO() AS VARCHAR)
FROM master.dbo.SYSPROCESSES WHERE SPID=@@SPID
IF Substring(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-15,8) like '%UserID%'
BEGIN
SET @UserID=RIGHT(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-7)
END
ELSE
BEGIN
RAISERROR('@UserID was not specified',16,1)
ROLLBACK TRAN
RETURN
END
以下是我通过测试获得的结果,例如带有触发器的State_Tbl
表
注意:此概念仅适用于Insert
和Update
而不是Delete
触发已使用
Create TRIGGER [dbo].[TR_lOCATION_AUDIT]
ON [dbo].[State_Tbl] FOR UPDATE,INSERT,DELETE
AS
DECLARE @bit INT ,
@field INT ,
@maxfield INT ,
@char INT ,
@fieldname VARCHAR(128) ,
@TableName VARCHAR(128) ,
@PKCols VARCHAR(1000) ,
@sql VARCHAR(2000),
@UpdateDate VARCHAR(21) ,
@UserName VARCHAR(128) ,
@Type CHAR(1) ,
@PKSelect VARCHAR(1000),
@UserID varchar(50),
@sCONTEXT_INFO varchar(128)
SELECT @sCONTEXT_INFO=CAST(CONTEXT_INFO() AS VARCHAR) FROM master.dbo.SYSPROCESSES WHERE SPID=@@SPID
IF Substring(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-15,8) like '%UserID%'
BEGIN
SET @UserID=RIGHT(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-7)
END
ELSE
BEGIN
RAISERROR('@UserID was not specified',16,1)
ROLLBACK TRAN
RETURN
END
--You will need to change @TableName to match the table to be audited.
-- Here we made GUESTS for your example.
SELECT @TableName = 'State_Tbl'
-- date and user
SELECT @UserName = @UserID,
@UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112)
+ ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)
-- Action
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT @Type = 'U'
ELSE
SELECT @Type = 'I'
ELSE
SELECT @Type = 'D'
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT @PKCols = COALESCE(@PKCols + ' and', ' on')
+ ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT @PKSelect = COALESCE(@PKSelect+'+','')
+ '''<' + COLUMN_NAME
+ '=''+convert(varchar(100),
coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''>'''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF @PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, @TableName)
RETURN
END
SELECT @field = 0,
@maxfield = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName
WHILE @field < @maxfield
BEGIN
SELECT @field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION > @field
SELECT @bit = (@field - 1 )% 8 + 1
SELECT @bit = POWER(2,@bit - 1)
SELECT @char = ((@field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0
OR @Type IN ('I','D')
BEGIN
SELECT @fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION = @field
IF Not EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Audit]') AND type in (N'U'))
Create TABLE [dbo].[Audit]
(
TranType Varchar(150),
TableName Varchar(150),
PK Varchar(150),
FieldName Varchar(150),
OldValue Varchar(150),
NewValue Varchar(150),
UpdateDate Varchar(150),
UserName Varchar(150)
)
SELECT @sql = '
insert Audit ( TranType,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName)
select ''' + @Type + ''','''
+ @TableName + ''',' + @PKSelect
+ ',''' + @fieldname + ''''
+ ',convert(varchar(1000),d.' + @fieldname + ')'
+ ',convert(varchar(1000),i.' + @fieldname + ')'
+ ',''' + @UpdateDate + ''''
+ ',''' + @UserID + ''''
+ ' from #ins i full outer join #del d'
+ @PKCols
+ ' where i.' + @fieldname + ' <> d.' + @fieldname
+ ' or (i.' + @fieldname + ' is null and d.'
+ @fieldname
+ ' is not null)'
+ ' or (i.' + @fieldname + ' is not null and d.'
+ @fieldname
+ ' is null)'
EXEC (@sql)
END
END