我希望创建一个SQL Server触发器,如果记录符合特定条件,则会将记录从一个表移动到相同的副本表。
问题:我是否需要指定每列,还是可以使用通配符?
我可以使用类似的东西:
SET @RecID = (SELECT [RecoID] FROM Inserted)
IF NULLIF(@RecID, '') IS NOT NULL
(then insert....)
谢谢!
答案 0 :(得分:1)
你在触发器中“可以”做很多事情,但这并不意味着你应该这样做。我会敦促不惜一切代价避免在触发器中设置标量变量。即使你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;
答案 1 :(得分:0)
你可以,但我建议不要这样做。如果你的源表发生了变化,事情就会开始失败。
此外,在您的示例中,如果您一次插入多行,则会引发错误(或者具有不可预测的结果)。我建议采用更基于集合的方法:
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;
instead of
如果您不想实际插入插件,将停止插入,因此您需要自己执行此操作(第二个插入语句)。
请注意我已将部分nulls
更改为not nulls
,并在某些情况下保留了我们要加入的表格。