Sql server 插入和更新时的SQL Server触发器
我希望创建一个SQL Server触发器,如果记录符合特定条件,它会将记录从一个表移动到相同的副本表 问题:我需要指定每一列,还是可以使用通配符 我可以使用类似于:Sql server 插入和更新时的SQL Server触发器,sql-server,Sql Server,我希望创建一个SQL Server触发器,如果记录符合特定条件,它会将记录从一个表移动到相同的副本表 问题:我需要指定每一列,还是可以使用通配符 我可以使用类似于: SET @RecID = (SELECT [RecoID] FROM Inserted) IF NULLIF(@RecID, '') IS NOT NULL (then insert....) 谢谢 你可以,但我建议你不要这样做。如果您的源表发生了更改,那么将开始失败 此外,在您的示例中,如果一次插入多行,您将抛出一个错
SET @RecID = (SELECT [RecoID] FROM Inserted)
IF NULLIF(@RecID, '') IS NOT NULL
(then insert....)
谢谢 你可以,但我建议你不要这样做。如果您的源表发生了更改,那么将开始失败 此外,在您的示例中,如果一次插入多行,您将抛出一个错误(或产生不可预测的结果)。我推荐一种更基于集合的方法:
INSERT table2 ( user_id ,
user_name ,
RecoID
)
SELECT user_id ,
user_name ,
RecoID
FROM inserted i
LEFT JOIN table2 t ON i.RecoID = t.RecoID
WHERE t.RecoID IS NULL;
编辑:
如果要停止在原始表上进行插入,则需要执行以下操作:
CREATE TRIGGER trigger_name
ON table_orig
INSTEAD OF INSERT
AS
BEGIN
-- make sure we aren't triggering from ourselves from another trigger
IF TRIGGER_NESTLEVEL() <= 1
return;
-- insert into the table_copy if the inserted row is already in table_orig (not null)
INSERT table_copy ( user_id ,
user_name ,
RecoID
)
SELECT user_id ,
user_name ,
RecoID
FROM inserted i
LEFT JOIN table_orig c ON i.RecoID = c.RecoID
WHERE t.RecoID IS NOT NULL;
-- insert into table_orig if the inserted row is not already in table_orig (null)
INSERT table_orig ( user_id ,
user_name ,
RecoID
)
SELECT user_id ,
user_name ,
RecoID
FROM inserted i
LEFT JOIN table_orig c ON i.RecoID = c.RecoID
WHERE t.RecoID IS NULL;
END;
创建触发器\u名称
在桌上
而不是插入
作为
开始
--确保我们没有从另一个触发器触发我们自己
如果TRIGGER_NESTLEVEL()你可以在触发器中“做”很多事情,但这并不意味着你应该这样做。我强烈要求不惜一切代价避免在触发器中设置标量变量。即使您100%确定您的表中每个事务插入的行数永远不会超过1行,因为应用程序就是这样设计的。。。当您发现并非所有事务都通过应用程序进行时,您将被非常粗鲁的唤醒
下面是两种触发器的快速演示
USE tempdb;
GO
IF OBJECT_ID('tempdb.dbo.PrimaryTable', 'U') IS NOT NULL
DROP TABLE dbo.PrimaryTable;
GO
IF OBJECT_ID('tempdb.dbo.TriggerScalarLog', 'U') IS NOT NULL
DROP TABLE dbo.TriggerScalarLog;
GO
IF OBJECT_ID('tempdb.dbo.TriggerMultiRowLog', 'U') IS NOT NULL
DROP TABLE dbo.TriggerMultiRowLog;
GO
CREATE TABLE dbo.PrimaryTable (
Pt_ID INT NOT NULL IDENTITY (1,1) PRIMARY KEY CLUSTERED,
Col_1 INT NULL,
Col_2 DATE NOT NULL
CONSTRAINT df_Col2 DEFAULT (GETDATE())
);
GO
CREATE TABLE dbo.TriggerScalarLog (
Pt_ID INT,
Col1_Old INT,
Col1_New INT,
Col2_Old DATE,
Col2_New DATE
);
GO
CREATE TABLE dbo.TriggerMultiRowLog (
Pt_ID INT,
Col1_Old INT,
Col1_New INT,
Col2_Old DATE,
Col2_New DATE
);
GO
--=======================================================
CREATE TRIGGER dbo.PrimaryCrudScalar ON dbo.PrimaryTable
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
DECLARE
@Pt_ID INT,
@Col1_Old INT,
@Col1_New INT,
@Col2_Old DATE,
@Col2_New DATE;
SELECT
@Pt_ID = ISNULL(i.Pt_ID, d.Pt_ID),
@Col1_Old = d.Col_1,
@Col1_New = i.Col_1,
@Col2_Old = d.Col_2,
@Col2_New = i.Col_2
FROM
Inserted i
FULL JOIN Deleted d
ON i.Pt_ID = d.Pt_ID;
INSERT dbo.TriggerScalarLog (Pt_ID, Col1_Old, Col1_New, Col2_Old, Col2_New)
VALUES (@Pt_ID, @Col1_Old, @Col1_New, @Col2_Old, @Col2_New);
GO -- DROP TRIGGER dbo.PrimaryCrudScalar;
CREATE TRIGGER PrimaryCrudMultiRow ON dbo.PrimaryTable
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
INSERT dbo.TriggerMultiRowLog (Pt_ID, Col1_Old, Col1_New, Col2_Old, Col2_New)
SELECT
ISNULL(i.Pt_ID, d.Pt_ID),
d.Col_1,
i.Col_1,
d.Col_2,
i.Col_2
FROM
Inserted i
FULL JOIN Deleted d
ON i.Pt_ID = d.Pt_ID;
GO -- DROP TRIGGER dbo.TriggerMultiRowLog;
--=======================================================
--=======================================================
-- --insert test...
INSERT dbo.PrimaryTable (Col_1)
SELECT TOP 100
o.object_id
FROM
sys.objects o;
SELECT 'INSERT Scarar results';
SELECT * FROM dbo.TriggerScalarLog tsl;
SELECT 'INSERT Multi-Row results';
SELECT * FROM dbo.TriggerMultiRowLog tmrl;
UPDATE pt SET
pt.Col_1 = pt.Col_1 + rv.RandomVal,
pt.Col_2 = DATEADD(DAY, rv.RandomVal, pt.Col_2)
FROM
dbo.PrimaryTable pt
CROSS APPLY ( VALUES (ABS(CHECKSUM(NEWID())) % 10000 + 1) ) rv (RandomVal);
SELECT 'UPDATE Scarar results';
SELECT * FROM dbo.TriggerScalarLog tsl;
SELECT 'UPDATE Multi-Row results';
SELECT * FROM dbo.TriggerMultiRowLog tmrl;
DELETE pt
FROM
dbo.PrimaryTable pt;
SELECT 'DELETE Scarar results';
SELECT * FROM dbo.TriggerScalarLog tsl;
SELECT 'DELETE Multi-Row results';
SELECT * FROM dbo.TriggerMultiRowLog tmrl;
使用标量选项,我如何简单地移动记录,它不需要保留在源表中。另外,你能解释一下ISNULL(i.Pt\u ID,d.Pt\u ID)吗?无论如何,我都不会使用标量选项。。。如果要从源表中删除,我将在存储过程中处理,而不是在触发器中处理。我不希望一个表上的临时维护会导致另一个表中的数据被意外删除。事实上,我主张使用触发器的用例很少。。。比如维护审核历史记录,或者确保两个不同环境中的两个表与其中一个保持同步。就是这样。至于ISNULL(i.Pt\u ID,d.Pt\u ID)。。。UPDATE语句生成2个表(插入和删除)。。。在我的示例中,我只想为每个ID生成一个审计行,所以我在插入的ID和删除的ID上使用了完全连接(在I.Pt_ID=d.Pt_ID上使用了完全连接删除的d),而ISNULL(I.Pt_ID,d.Pt_ID)只是说,“如果这是一个插入,请使用i.Pt_ID;如果这是一个删除,请使用d.Pt_ID;如果这是一个更新,我不在乎哪一个,因为它们的值相同“。第一个表被用作暂存表,发生的情况是插入一条记录,然后进行多次更新。在最终更新时,想法是将该记录移动到主DB表中,并将其从暂存表中删除。这是因为主表有超过1亿条记录,并且每次更新记录都会产生其他副作用。因此,总之,我们希望确保记录在移动到主表之前是“最终的”。@user3255066-即使在这种情况下,我仍然不相信装配工中的标量变量。您对该过程的假设可能在99%的时间内有效,但墨菲定律将找到执行多行多行事务的方法。一旦发生这种情况,您要么丢失了数据,要么在系统中引入了异常行为。你为什么要冒险?标量触发器绝对没有优势。多行版本可以处理单行DML,就像处理标量版本一样,并且将在那里。如果想法是移动记录,是否需要左连接?您建议如何删除插入的\更新的记录?