- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的应用程序的 SQL Server 后端中,我想为一堆关键表创建历史表,它将跟踪行更改的历史记录。
我的整个应用程序都使用存储过程,没有嵌入 SQL。修改这些表的唯一数据库连接将通过应用程序和 SP 接口(interface)进行。传统上,我合作过的商店都是使用触发器执行此任务。
如果我可以在存储过程和触发器之间进行选择,哪个更好?哪个更快?
最佳答案
触发器。
我们编写了一个 GUI(内部称为“Red Matrix Reloaded”),以便轻松创建/管理审核日志记录触发器。
这是所使用的一些 DDL:
<小时/>CREATE TABLE [AuditLog] (
[AuditLogID] [int] IDENTITY (1, 1) NOT NULL ,
[ChangeDate] [datetime] NOT NULL CONSTRAINT [DF_AuditLog_ChangeDate] DEFAULT (getdate()),
[RowGUID] [uniqueidentifier] NOT NULL ,
[ChangeType] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[TableName] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[FieldName] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[OldValue] [varchar] (8000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[NewValue] [varchar] (8000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Username] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Hostname] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[AppName] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[UserGUID] [uniqueidentifier] NULL ,
[TagGUID] [uniqueidentifier] NULL ,
[Tag] [varchar] (8000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
)
<小时/>
CREATE TRIGGER LogInsert_Nodes ON dbo.Nodes
FOR INSERT
AS
/* Load the saved context info UserGUID */
DECLARE @SavedUserGUID uniqueidentifier
SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
FROM master.dbo.sysprocesses
WHERE spid = @@SPID
DECLARE @NullGUID uniqueidentifier
SELECT @NullGUID = '{00000000-0000-0000-0000-000000000000}'
IF @SavedUserGUID = @NullGUID
BEGIN
SET @SavedUserGUID = NULL
END
/*We dont' log individual field changes Old/New because the row is new.
So we only have one record - INSERTED*/
INSERT INTO AuditLog(
ChangeDate, RowGUID, ChangeType,
Username, HostName, AppName,
UserGUID,
TableName, FieldName,
TagGUID, Tag,
OldValue, NewValue)
SELECT
getdate(), --ChangeDate
i.NodeGUID, --RowGUID
'INSERTED', --ChangeType
USER_NAME(), HOST_NAME(), APP_NAME(),
@SavedUserGUID, --UserGUID
'Nodes', --TableName
'', --FieldName
i.ParentNodeGUID, --TagGUID
i.Caption, --Tag
null, --OldValue
null --NewValue
FROM Inserted i
<小时/>
CREATE TRIGGER LogUpdate_Nodes ON dbo.Nodes
FOR UPDATE AS
/* Load the saved context info UserGUID */
DECLARE @SavedUserGUID uniqueidentifier
SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
FROM master.dbo.sysprocesses
WHERE spid = @@SPID
DECLARE @NullGUID uniqueidentifier
SELECT @NullGUID = '{00000000-0000-0000-0000-000000000000}'
IF @SavedUserGUID = @NullGUID
BEGIN
SET @SavedUserGUID = NULL
END
/* ParentNodeGUID uniqueidentifier */
IF UPDATE (ParentNodeGUID)
BEGIN
INSERT INTO AuditLog(
ChangeDate, RowGUID, ChangeType,
Username, HostName, AppName,
UserGUID,
TableName, FieldName,
TagGUID, Tag,
OldValue, NewValue)
SELECT
getdate(), --ChangeDate
i.NodeGUID, --RowGUID
'UPDATED', --ChangeType
USER_NAME(), HOST_NAME(), APP_NAME(),
@SavedUserGUID, --UserGUID
'Nodes', --TableName
'ParentNodeGUID', --FieldName
i.ParentNodeGUID, --TagGUID
i.Caption, --Tag
d.ParentNodeGUID, --OldValue
i.ParentNodeGUID --NewValue
FROM Inserted i
INNER JOIN Deleted d
ON i.NodeGUID = d.NodeGUID
WHERE (d.ParentNodeGUID IS NULL AND i.ParentNodeGUID IS NOT NULL)
OR (d.ParentNodeGUID IS NOT NULL AND i.ParentNodeGUID IS NULL)
OR (d.ParentNodeGUID <> i.ParentNodeGUID)
END
/* Caption varchar(255) */
IF UPDATE (Caption)
BEGIN
INSERT INTO AuditLog(
ChangeDate, RowGUID, ChangeType,
Username, HostName, AppName,
UserGUID,
TableName, FieldName,
TagGUID, Tag,
OldValue, NewValue)
SELECT
getdate(), --ChangeDate
i.NodeGUID, --RowGUID
'UPDATED', --ChangeType
USER_NAME(), HOST_NAME(), APP_NAME(),
@SavedUserGUID, --UserGUID
'Nodes', --TableName
'Caption', --FieldName
i.ParentNodeGUID, --TagGUID
i.Caption, --Tag
d.Caption, --OldValue
i.Caption --NewValue
FROM Inserted i
INNER JOIN Deleted d
ON i.NodeGUID = d.NodeGUID
WHERE (d.Caption IS NULL AND i.Caption IS NOT NULL)
OR (d.Caption IS NOT NULL AND i.Caption IS NULL)
OR (d.Caption <> i.Caption)
END
...
/* ImageGUID uniqueidentifier */
IF UPDATE (ImageGUID)
BEGIN
INSERT INTO AuditLog(
ChangeDate, RowGUID, ChangeType,
Username, HostName, AppName,
UserGUID,
TableName, FieldName,
TagGUID, Tag,
OldValue, NewValue)
SELECT
getdate(), --ChangeDate
i.NodeGUID, --RowGUID
'UPDATED', --ChangeType
USER_NAME(), HOST_NAME(), APP_NAME(),
@SavedUserGUID, --UserGUID
'Nodes', --TableName
'ImageGUID', --FieldName
i.ParentNodeGUID, --TagGUID
i.Caption, --Tag
(SELECT Caption FROM Nodes WHERE NodeGUID = d.ImageGUID), --OldValue
(SELECT Caption FROM Nodes WHERE NodeGUID = i.ImageGUID) --New Value
FROM Inserted i
INNER JOIN Deleted d
ON i.NodeGUID = d.NodeGUID
WHERE (d.ImageGUID IS NULL AND i.ImageGUID IS NOT NULL)
OR (d.ImageGUID IS NOT NULL AND i.ImageGUID IS NULL)
OR (d.ImageGUID <> i.ImageGUID)
END
<小时/>
CREATE TRIGGER LogDelete_Nodes ON dbo.Nodes
FOR DELETE
AS
/* Load the saved context info UserGUID */
DECLARE @SavedUserGUID uniqueidentifier
SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
FROM master.dbo.sysprocesses
WHERE spid = @@SPID
DECLARE @NullGUID uniqueidentifier
SELECT @NullGUID = '{00000000-0000-0000-0000-000000000000}'
IF @SavedUserGUID = @NullGUID
BEGIN
SET @SavedUserGUID = NULL
END
/*We dont' log individual field changes Old/New because the row is new.
So we only have one record - DELETED*/
INSERT INTO AuditLog(
ChangeDate, RowGUID, ChangeType,
Username, HostName, AppName,
UserGUID,
TableName, FieldName,
TagGUID, Tag,
OldValue,NewValue)
SELECT
getdate(), --ChangeDate
d.NodeGUID, --RowGUID
'DELETED', --ChangeType
USER_NAME(), HOST_NAME(), APP_NAME(),
@SavedUserGUID, --UserGUID
'Nodes', --TableName
'', --FieldName
d.ParentNodeGUID, --TagGUID
d.Caption, --Tag
null, --OldValue
null --NewValue
FROM Deleted d
<小时/>
为了了解软件中的哪个用户进行了更新,每个连接都通过调用存储过程“将自身登录到 SQL Server”:
CREATE PROCEDURE dbo.SaveContextUserGUID @UserGUID uniqueidentifier AS
/* Saves the given UserGUID as the session's "Context Information" */
IF @UserGUID IS NULL
BEGIN
PRINT 'Emptying CONTEXT_INFO because of null @UserGUID'
DECLARE @BinVar varbinary(128)
SET @BinVar = CAST( REPLICATE( 0x00, 128 ) AS varbinary(128) )
SET CONTEXT_INFO @BinVar
RETURN 0
END
DECLARE @UserGUIDBinary binary(16) --a guid is 16 bytes
SELECT @UserGUIDBinary = CAST(@UserGUID as binary(16))
SET CONTEXT_INFO @UserGUIDBinary
/* To load the guid back
DECLARE @SavedUserGUID uniqueidentifier
SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
FROM master.dbo.sysprocesses
WHERE spid = @@SPID
select @SavedUserGUID AS UserGUID
*/
<小时/>
注释
有时,“OldValue”和“NewValue”值会写为子选择 - 以获得有意义的字符串。即”
旧值:{233d-ad34234..}新值:{883-sdf34...}
在审计跟踪中的用处不如:
OldValue: Daimler Chrysler
NewValue: Cerberus Capital Management
最后说明:请随意不做我们所做的事情。这对我们来说很好,但其他人可以自由地不使用它。
关于sql-server - SQL Server 历史表 - 通过 SP 或触发器填充?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/349524/
我正在尝试使用 JSOM 更新 SP.Listitem,以保留另一个用户的 spUser。请参阅下面的代码片段 // Query the picker for user information. $.
虽然我环顾四周但还没有运气 我正在使用 SQL Server。这是整个场景。 我有一个旧的遗留 sp(由于很多依赖关系和其他问题我无法更改)它不返回任何值也不接受任何输出参数,它只是选择一个值作为 C
虽然我环顾四周但还没有运气 我正在使用 SQL Server。这是整个场景。 我有一个旧的遗留 sp(由于很多依赖关系和其他问题我无法更改)它不返回任何值也不接受任何输出参数,它只是选择一个值作为 C
我正在研究使用过程的MIPS代码,但无法理解堆栈(sp)和帧指针(fp)的目的。 例如,我研究的代码如下。它会在您输入的号码之前打印所有号码,例如3. 3,2,1,0,并显示它使用了多少堆栈大小。在此
我已成功创建以下 MySQL SP.. CREATE DEFINER=`root`@`%` PROCEDURE `Common_Proc_Create_NewId` ( TableName VARC
我尝试使用链接的数据库代码中的另一个 SP 执行存储过程(SP),工作顺利,没有错误,但它不会在我的表中插入数据。 这是存储过程的代码 USE [MYDB] GO SET ANSI_NULLS ON
我有一个包含许多存储过程的生产 SQL-Server 数据库(报告)。SP以不同的方式向外界公开 - 一些用户可以直接访问 SP, - 一些通过 WebService 公开 - 而其他的则通过 DCO
我是 SQL DBA 角色的新手。我有一个可能每天运行多次的存储过程 (SP1)。它在 table1 上运行昂贵的 SELECT,可能需要 15 分钟才能完成。我有另一个存储过程 (SP2),它在 t
自从更新了 sp 软件包后,我收到了以前没有收到的警告: 1: In showSRID(uprojargs, format = "PROJ", multiline = "NO") : Disca
问题 我们试图理解为什么通过调用存储过程执行相同的代码与在查询窗口中执行存储过程内容显示出截然不同的执行时间,但返回完全相同的 183 行结果集。 测试1 从 SSMS 执行以下 SP 需要 5 分钟
为什么在0(SP)处传递的值只能在4(SP)处访问?例如,我需要通过 0(SP) 而不是 4(SP) 将数字传递给 printn (因为它在例程中使用)否则它不会起作用。我错过了什么? MOVE #1
在 MySql 存储过程中,我想捕获并记录可能发生的任何错误,然后停止/终止/退出调用存储过程的进程。该进程是另一个存储过程,其上一级或可能上两级,由计划事件执行。 目前我有第一部分,但没有第二部分:
这个问题在这里已经有了答案: scipy.special import issue (1 个回答) 关闭 7 年前。 我想使用 scipy.signal.lti 和 scipy.signal.imp
在制作 LINQ to SQL 和实体的 POC 时,我遇到了一个卡在死胡同里的问题。问题是,我正在使用 LINQ to SP,一切都运行良好,我制作了很酷的编辑、添加和删除方法。然后在我的矿井中点击
我最近开始使用 TST (tst.codeplex.com) 测试存储过程,并发现它非常有用 - 但一个缺点是我们无法隔离依赖项并“模拟”其他 SP/函数调用(就像我们对 C# 所做的那样)对象依赖关
您好,我已经创建了一个每天触发 sp 的 mysql 事件,但它触发 sp 的时间间隔为一天。我创建的事件是: CREATE DEFINER=`root`@`localhost` EVENT `Job
我想知道是否可以在 Sql Server Profiler 中查看其他存储过程正在执行的存储过程,是否可以,如果可以,如何实现? 最佳答案 如果您使用 SP::Starting 事件进行分析,您可以看
我的场景 我正在开发一个数据库,该数据库将包含整个服务器上不同数据库中各种存储过程的许多详细信息。我现在试图收集的信息是“SP 输出什么?” 在搜索中我发现答案就在 OPENROWSET 中。我的初步
在 python 中,我们有包含 sp.linalg.norm、sp.cross 的库 scipy。 C++ boost 库中有没有类似的函数? 最佳答案 好像没有。 但是,OpenCV 有您需要的!
将 scipy 导入 Python 时出现错误。当我写: import scipy as sp x2 = lambda x: x**2 print sp.integrate.quad(x2, 0, 4
我是一名优秀的程序员,十分优秀!