如何在不使用大量变量的情况下重写此更新触发器?
我编写了我的第一个SQL Server触发器,它工作正常,但我认为,必须有一个更简单的解决方案。
如果更改了5列中的最小值,我会在另一个表中写入两个新行。 第1行=旧的Fahrer(=驱动程序)和旧的dispodate和更新时间 第2行=新的Fahrer和新的dispodate和updatedatetime 我的解决方案只是foxpro-trigger的一个副本,但是在T-SQL中必须有一个更简单的解决方案来检查一个列是否被更改。
ALTER TRIGGER [dbo].[MyTrigger]
ON [dbo].[tbldisposaetze]
AFTER UPDATE
AS
SET NOCOUNT ON;
/*SET XACT_ABORT ON
SET ARITHABORT ON
*/
DECLARE @oldfahrer varchar(10)
DECLARE @oldbus varchar(10)
DECLARE @olddispodat date
DECLARE @oldvzeit decimal(4,0)
DECLARE @oldbzeit decimal(4,0)
DECLARE @oldbeschreibk varchar(255)
DECLARE @newfahrer varchar(10)
DECLARE @newbus varchar(10)
DECLARE @newdispodat date
DECLARE @newvzeit decimal(4,0)
DECLARE @newbzeit decimal(4,0)
DECLARE @newbeschreibk varchar(255)
SELECT @oldfahrer = fahrer,@oldbeschreibk=beschreibk,@oldbus=bus,@oldbzeit=bzeit,@olddispodat=dispodat,@oldvzeit=vzeit
FROM DELETED D
SELECT @newfahrer = fahrer,@newbeschreibk=beschreibk,@newbus=bus,@newbzeit=bzeit,@newdispodat=dispodat,@newvzeit=vzeit
FROM inserted I
if @oldbeschreibk <> @newbeschreibk or @oldbus <> @newbus or @oldbzeit <> @newbzeit or @oldfahrer <> @newfahrer or @oldvzeit <> @newvzeit
begin
IF (SELECT COUNT(*) FROM tbldispofahrer where fahrer=@oldfahrer and dispodat=@olddispodat) > 0
update tbldispofahrer set laenderung = GETDATE() where fahrer=@oldfahrer and dispodat=@olddispodat
else
INSERT into tbldispofahrer (fahrer,dispodat,laenderung) VALUES (@oldfahrer,@olddispodat,getdate())
IF (SELECT COUNT(*) FROM tbldispofahrer where fahrer=@newfahrer and dispodat=@newdispodat) > 0
update tbldispofahrer set laenderung = GETDATE() where fahrer=@newfahrer and dispodat=@newdispodat
else
INSERT into tbldispofahrer (fahrer,dispodat,laenderung) VALUES (@newfahrer,@newdispodat,getdate())
end
答案 0 :(得分:4)
我假设你有SQL Server 2008或更高版本。你可以在一个语句中完成所有操作而不需要任何变量。
除了完成所有工作以首先获取变量并查看它们是否匹配之外,您可以轻松地将其作为where
子句的一部分来完成。正如大家在评论中所说,您可以将多行作为插入和删除的一部分。为了确保您使用相同的更新行,您需要使用主键进行匹配。
为了插入或更新行,我使用MERGE
语句。合并的来源是与上面的where子句的联合,联合中的顶级表具有较旧的fahrer,而底部具有新的farher。就像你的内部IF一样,现有的行在farher和dispodat上匹配,并适当地插入或更新。
我注意到的一件事是,在你的例子中,newfahrer和oldfahrer可能完全相同,因此只应进行一次插入或更新(即如果只有bzeit不同)。联合应防止重复数据尝试插入。如果有的话,我确实认为合并会出错。
MERGE tbldispofahrer AS tgt
USING (
SELECT d.farher, d.dispodat, GETDATE() [laenderung]
INNER JOIN inserted i ON i.PrimaryKey = d.PrimaryKey
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreik ... )
UNION
SELECT i.farher, i.dispodat, GETDATE() [laenderung]
INNER JOIN inserted i ON i.PrimaryKey = d.PrimaryKey
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreik ... )
) AS src (farher, dispodat, laenderung)
ON tgt.farher = src.farher AND tgt.dispodat = src.dispodat
WHEN MATCHED THEN UPDATE SET
laenderung = GETDATE()
WHEN NOT MATCHED THEN
INSERT (fahrer,dispodat,laenderung)
VALUES (src.fahrer, src.dispodat, src.laenderung)
答案 1 :(得分:1)
Daniel的答案中有一些语法错误。 以下代码运行正常:
MERGE tbldispofahrer AS tgt
USING (
SELECT d.fahrer, d.dispodat, GETDATE() [laenderung] from deleted d
INNER JOIN inserted i ON i.satznr = d.satznr
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreibk or i.bus <> d.bus or i.bzeit <> d.bzeit or i.vzeit <> d.vzeit)
UNION
SELECT i.fahrer, i.dispodat, GETDATE() [laenderung] from inserted i
INNER JOIN deleted d ON i.satznr = d.satznr
AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreibk or i.bus <> d.bus or i.bzeit <> d.bzeit or i.vzeit <> d.vzeit)
) AS src (fahrer, dispodat, laenderung)
ON tgt.fahrer = src.fahrer AND tgt.dispodat = src.dispodat
WHEN MATCHED THEN UPDATE SET
laenderung = GETDATE()
WHEN NOT MATCHED THEN
INSERT (fahrer,dispodat,laenderung)
VALUES (src.fahrer, src.dispodat, src.laenderung);
&#13;