Sql server 我的扳机怎么了?不插入任何结果
下面的触发器从一个表employeeInOut中选择ID,将该表中与所有ID匹配的列中的int相加,并应在每个小时将其插入另一个表中。我不知道这是否是一个语法问题,intellisense中没有显示任何内容,它所说的只是触发器执行成功-没有插入任何内容 触发器->Sql server 我的扳机怎么了?不插入任何结果,sql-server,Sql Server,下面的触发器从一个表employeeInOut中选择ID,将该表中与所有ID匹配的列中的int相加,并应在每个小时将其插入另一个表中。我不知道这是否是一个语法问题,intellisense中没有显示任何内容,它所说的只是触发器执行成功-没有插入任何内容 触发器-> GO CREATE TRIGGER empTotalsHoursWorked ON employeeInOut FOR INSERT, DELETE, UPDATE AS BEGIN INSERT INTO monthlyHours(
GO
CREATE TRIGGER empTotalsHoursWorked
ON employeeInOut
FOR INSERT, DELETE, UPDATE
AS
BEGIN
INSERT INTO monthlyHours(employeeID, monthlyHours)
SELECT (SELECT employeeID FROM employeeInOut),
SUM(dailyHours) AS monthlyHours
FROM employeeInOut
WHERE employeeInOut.employeeID=(SELECT employeeID FROM monthlyHours)
END
GO
我已经多次重新操作过这个触发器,这是一个没有错误的触发器,但是没有插入任何内容,结果似乎没有任何内容。任何建议,答案,请欣赏。我真的建议不要触发这样一个简单的运行总数,您最好的选择是创建一个视图。比如:
CREATE VIEW dbo.MonthlyHours
AS
SELECT EmployeeID,
monthlyHours = SUM(dailyHours)
FROM dbo.employeeInOut
GROUP BY EmployeeID;
GO
然后,您可以使用与表相同的方式访问它:
SELECT *
FROM dbo.MonthlyHours;
如果您特别担心性能,那么您可以始终:
现在,无论何时从employeeInOut中添加或删除记录,SQL Server都会自动更新视图的聚集索引,您只需使用WITH NOEXPAND查询提示,以确保不在视图后面运行查询:
SELECT *
FROM dbo.MonthlyHours WITH (NOEXPAND);
最后,基于表名为monthly hours的事实,我猜它应该是按月计算的,因此我假设employeeInOut中也有一个日期字段,在这种情况下,您的视图可能更像:
CREATE VIEW dbo.MonthlyHours
WITH SCHEMABINDING
AS
SELECT EmployeeID,
FirstDayOfMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, [YourDateField]), 0),
monthlyHours = SUM(dailyHours),
RecordCount = COUNT_BIG(*)
FROM dbo.employeeInOut
GROUP BY EmployeeID, DATEADD(MONTH, DATEDIFF(MONTH, 0, [YourDateField]), 0);
GO
CREATE UNIQUE CLUSTERED INDEX UQ_MonthlyHours__EmployeeID_FirstDayOfMonth
ON dbo.MonthlyHours(EmployeeID, FirstDayOfMonth);
您可以用上述相同的方式使用视图
附录
值得注意的是,为了使你的触发器正常工作,你需要考虑所有的情况:
在该员工已存在的位置插入一条记录在每月小时内更新现有记录。
插入一个员工在一个月内不存在的记录插入新记录。
更新记录更新现有
删除现有记录更新,或删除
要处理所有这些情况,可以使用“合并”:
这里有两个假设,一个是monthlyHours表包含employeeID和monthlyHours 话虽如此,我认为你需要根据动作的不同,使用多个触发器。下面是一个基于插入employeeInOut表的示例
GO
CREATE TRIGGER empTotalsHoursWorked
ON employeeInOut
AFTER INSERT
AS
BEGIN
DECLARE @employeeID INT
DECLARE @monthlyHours INT
SELECT @employeeID = INSERTED.employeeID
FROM INSERTED
SELECT @monthlyHours = SUM(dailyHours)
FROM employeeInOut
WHERE employeeInOut.employeeID = @employeeID
INSERT INTO monthlyHours(employeeID,monthlyHours)
values (@employeeID, @monthlyHours)
END
GO
当然,这将插入一个新行。如果该员工的monthlyHours表中已经存在该行,则可能需要修改该行以更新该行 如果表monthlyHours开始时为空,则employeeInOut.employeeID=从monthlyHours选择employeeID的谓词将意味着不返回任何结果。如果表包含多行,则会出现一个错误,表示子查询返回了多条记录,这在使用=运算符时无效。这个月小时的桌子到底是干什么用的?我真的不知道你想要达到什么。嗨,谢谢你的回复。基本上,我只是尝试在两个表中匹配employeeID的monthlyHours,employeeInOut,总结employeeInOutdailyHours的每日小时数,并将其放入MonthlyHoursMonthlyHours是否有employeeID列,因为您没有插入到其中。您也从不引用插入或删除的内存驻留表,因此触发器与插入、删除或更新的记录根本不相关。是否有任何原因需要第二个表来记录此操作,并且不能仅使用查询来获取总和-选择EmployeeID,按EmployeeID从employeeInOut组调用小时数;是的。我编辑了你的建议,但仍然没有插入。说实话,我把它放在一个totals表中可能更美观,任何人都可以很容易地访问它,而不是运行查询。还有,为什么除了执行成功之外,我不能在结果窗格中看到结果?尽管有人说@GarethD的方法是正确的。不要在触发器中使用标量变量,例如:选择@employeeID=INSERTED.employeeID FROM INSERTED-如果INSERTED中有多条记录,那么您只处理其中一条,更糟糕的是,没有实际的错误告诉你这一点,触发器工作正常,你可能暂时没有意识到触发器没有完成全部工作。始终基于插入和删除的表将包含多行的假设编写触发器,即使您认为这永远不会发生。
CREATE TRIGGER empTotalsHoursWorked
ON employeeInOut
FOR INSERT, DELETE, UPDATE
AS
BEGIN
WITH ChangesToMake AS
( SELECT EmployeeID, SUM(dailyHours) AS MonthlyHours
FROM ( SELECT EmployeeID, dailyHours
FROM Inserted
UNION ALL
SELECT EmployeeID, -dailyHours
FROM deleted
) AS t
GROUP BY EmployeeID
)
MERGE INTO monthlyHours AS m
USING ChangesToMake AS c
ON c.EmployeeID = m.EmployeeID
WHEN MATCHED THEN UPDATE
SET MonthlyHours = c.MonthlyHours
WHEN NOT MATCHED BY TARGET THEN
INSERT (EmployeeID, MonthlyHours)
VALUES (c.EmployeeID, c.MonthlyHours)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
END
GO
GO
CREATE TRIGGER empTotalsHoursWorked
ON employeeInOut
AFTER INSERT
AS
BEGIN
DECLARE @employeeID INT
DECLARE @monthlyHours INT
SELECT @employeeID = INSERTED.employeeID
FROM INSERTED
SELECT @monthlyHours = SUM(dailyHours)
FROM employeeInOut
WHERE employeeInOut.employeeID = @employeeID
INSERT INTO monthlyHours(employeeID,monthlyHours)
values (@employeeID, @monthlyHours)
END
GO