范围触发器 - 员工工资
Range Triggers - Salary of Employess
我有一个 table 我叫 FUNC
我所有的员工都在那里,我有另一个 table 我可以注册不同的工作角色...每个员工必须有工作角色。
我的工作角色table有它的ID、角色名称、角色的最低工资和角色的最高工资。
我想创建一个触发器,如果加薪在范围内,每次我给某个员工 RAISE 时 CHECKS "Minimum Wage and Maximum Wage".
为了更容易理解,我将展示我到目前为止所做的...
CREATE TABLE FUNC(
IDFUNC INT IDENTITY,
NAME VARCHAR(30) NOT NULL,
SALARY MONEY NOT NULL,
ID_JOB INT,
IDGESTOR INT
)
GO
CREATE TABLE JOB(
IDJOB INT IDENTITY,
NAMEJOB VARCHAR(10) UNIQUE,
MINIMUM MONEY NOT NULL,
MAXIMUM MONEY NOT NULL,
)
/* CONSTRAINTS*/
ALTER TABLE FUNC ADD CONSTRAINT PK_FUNC
PRIMARY KEY(IDFUNC)
GO
ALTER TABLE JOB ADD CONSTRAINT PK_JOB
PRIMARY KEY(IDJOB)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_GESTOR
FOREIGN KEY(IDGESTOR) REFERENCES FUNC(IDFUNC)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_FUNC_JOB
FOREIGN KEY(ID_JOB) REFERENCES JOB(IDJOB)
GO
用这些值填充表格:
INSERT INTO JOB VALUES('MANAGER',5000,10000)
INSERT INTO JOB VALUES('SUPERVISOR',4000,7000)
INSERT INTO JOB VALUES('LEADER',2000,5000)
INSERT INTO JOB VALUES('ANALYST',1200,4000)
GO
IDJOB NAMEJOB MINIMUM MAXIMUM
----------- ---------- --------------------- ---------------------
1 MANAGER 5000,00 10000,00
2 SUPERVISOR 4000,00 7000,00
3 LEADER 2000,00 5000,00
4 ANALYST 1200,00 4000,00
//
INSERT INTO FUNC VALUES('Name1',7000,1,NULL)
INSERT INTO FUNC VALUES('Name2',5000,2,1)
INSERT INTO FUNC VALUES('Name3',5000,2,1)
INSERT INTO FUNC VALUES('Name4',3000,3,2)
INSERT INTO FUNC VALUES('Name5',3400,3,2)
INSERT INTO FUNC VALUES('Name6',2800,3,3)
INSERT INTO FUNC VALUES('Name7',3200,3,3)
INSERT INTO FUNC VALUES('Name8',2000,4,4)
INSERT INTO FUNC VALUES('Name9',1800,4,4)
INSERT INTO FUNC VALUES('Name10',1500,4,5)
INSERT INTO FUNC VALUES('Name11',1300,4,5)
INSERT INTO FUNC VALUES('Name12',3000,4,6)
INSERT INTO FUNC VALUES('Name13',2000,4,6)
INSERT INTO FUNC VALUES('Name14',1900,4,7)
INSERT INTO FUNC VALUES('Name15',2100,4,7)
GO
IDFUNC NAME SALARY ID_JOB IDGESTOR
------------- ------------------------------ --------------------- ----------- -----------
1 Name1 7000,00 1 NULL
2 Name2 5000,00 2 1
3 Name3 5000,00 2 1
4 Name4 3000,00 3 2
5 Name5 3400,00 3 2
6 Name6 2800,00 3 3
7 Name7 3200,00 3 3
8 Name8 2000,00 4 4
9 Name9 1800,00 4 4
10 Name10 1500,00 4 5
11 Name11 1300,00 4 5
12 Name12 3000,00 4 6
13 Name13 2000,00 4 6
14 Name14 1900,00 4 7
15 Name15 2100,00 4 7
最终创建了这个触发器:
CREATE TRIGGER TRG_Salary
ON FUNC
FOR INSERT, UPDATE
AS
DECLARE
@MINIMUM MONEY, @MAXIMUM MONEY, @SALARY MONEY, @IDCARGO INT
SELECT @IDJOB = IDJOB FROM JOB
INNER JOIN INSERTED I
ON IDJOB = I.ID_JOB
WHERE IDFUNC = I.IDFUNC
SELECT @MINIMUM = MINIMUM, @MAXIMUM = MAXIMUM
FROM JOB WHERE IDJOB = @IDJOB
SELECT @SALARY = I.SALARY FROM INSERTED I
IF(@SALARY <@MINIMUM)
BEGIN
RAISERROR ('Salary Must be Higher than Minimum',16,1)
ROLLBACK TRANSACTION
END
IF(@SALARY > @MAXIMUM)
BEGIN
RAISERROR ('SALARIO Must Be Lower than Maximum',16,1)
ROLLBACK TRANSACTION
END
GO
当我只更新一行时它工作正常....
前:
UPDATE FUNC SET SALARY = 15000 WHERE IDFUNC = 1
GO
它会显示错误,因为我的 IDFUNC=1 的员工应该收到 5000 到 10000 之间的信息,因为他是经理
我的问题是当我尝试一次更新所有行时...
就像我想给每个人加薪一样
UPDATE FUNC SET SALARY = SALARY*1.1
更新函数不检查我的触发器内的条件并更新薪水,无论它是在我的范围内还是在我的范围外....
问题是 inserted
包含多行。与大多数其他数据库不同,SQL 服务器不支持 每行 触发器(使用 for each row
子句实现)。
您需要一次检查所有插入的行,如果检查失败则全部拒绝。这是一种使用条件聚合的方法:
create trigger trg_salary
on func
for insert, update
as
declare @isfailed int
select @isfailed = max(
case when i.salary not between j.minimum and j.maximum
then 1
else 0
end
)
from inserted i
inner join job j on j.idjob = i.idjob
if(@isfailed = 1)
begin
raiserror ('salary must be belong to the minimum-maximum range',16,1)
rollback transaction
end
go
INSERTED
伪table包含0-N行,其中N是inserted/updated的行数(可以为零!)。因此,并且因为 SQL 针对 "set based operations" 进行了优化,您需要构建一个查询来测试您的错误情况。
但是正因为如此,除非您想要 return 错误列表,否则即使存在多个错误,您也只能 return 1 个错误。
最好使用 THROW
而不是 RAISERROR
。
CREATE TRIGGER TRG_Salary ON FUNC
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ERROR NVARCHAR(2048);
SELECT TOP 1 @ERROR = CASE WHEN I.SALARY > MAXIMUM THEN 'SALARIO Must Be Lower than Maximum.' WHEN I.SALARY < MAXIMUM THEN 'SALARIO Must Be Higher than Minimum.' END
FROM INSERTED I
INNER JOIN JOB J on J.IDJOB = I.ID_JOB
WHERE I.SALARY > MAXIMUM OR I.SALARY < MAXIMUM;
IF @ERROR IS NOT NULL BEGIN
ROLLBACK;
THROW 51000, @ERROR, 1;
END;
END
GO
MS SQL Server 2017 架构设置:
CREATE TABLE FUNC(
IDFUNC INT IDENTITY,
NAME VARCHAR(30) NOT NULL,
SALARY MONEY NOT NULL,
ID_JOB INT,
IDGESTOR INT
)
GO
CREATE TABLE JOB(
IDJOB INT IDENTITY,
NAMEJOB VARCHAR(10) UNIQUE,
MINIMUM MONEY NOT NULL,
MAXIMUM MONEY NOT NULL,
)
/* CONSTRAINTS*/
ALTER TABLE FUNC ADD CONSTRAINT PK_FUNC
PRIMARY KEY(IDFUNC)
GO
ALTER TABLE JOB ADD CONSTRAINT PK_JOB
PRIMARY KEY(IDJOB)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_GESTOR
FOREIGN KEY(IDGESTOR) REFERENCES FUNC(IDFUNC)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_FUNC_JOB
FOREIGN KEY(ID_JOB) REFERENCES JOB(IDJOB)
GO
INSERT INTO JOB VALUES('MANAGER',5000,10000)
INSERT INTO JOB VALUES('SUPERVISOR',4000,7000)
INSERT INTO JOB VALUES('LEADER',2000,5000)
INSERT INTO JOB VALUES('ANALYST',1200,4000)
GO
INSERT INTO FUNC VALUES('Name1',7000,1,NULL)
INSERT INTO FUNC VALUES('Name2',5000,2,1)
INSERT INTO FUNC VALUES('Name3',5000,2,1)
INSERT INTO FUNC VALUES('Name4',3000,3,2)
INSERT INTO FUNC VALUES('Name5',3400,3,2)
INSERT INTO FUNC VALUES('Name6',2800,3,3)
INSERT INTO FUNC VALUES('Name7',3200,3,3)
INSERT INTO FUNC VALUES('Name8',2000,4,4)
INSERT INTO FUNC VALUES('Name9',1800,4,4)
INSERT INTO FUNC VALUES('Name10',1500,4,5)
INSERT INTO FUNC VALUES('Name11',1300,4,5)
INSERT INTO FUNC VALUES('Name12',3000,4,6)
INSERT INTO FUNC VALUES('Name13',2000,4,6)
INSERT INTO FUNC VALUES('Name14',1900,4,7)
INSERT INTO FUNC VALUES('Name15',2100,4,7)
GO
CREATE TRIGGER TRG_Salary
ON FUNC
FOR INSERT, UPDATE
AS
IF EXISTS
(
SELECT 1
FROM JOB J
INNER JOIN INSERTED F
ON J.IDJOB = F.ID_JOB
WHERE F.Salary < J.Minimum OR F.Salary > J.Minimum
)
BEGIN
RAISERROR ('SALARIO Must Be Lower than Maximum and Greater than Minimum',16,1)
ROLLBACK TRANSACTION
END
GO
查询 1:
--UPDATE FUNC SET SALARY = 15000 WHERE IDFUNC = 1
UPDATE FUNC SET SALARY = SALARY*1.1
Results:
SALARIO 必须小于最大值且大于最小值
我有一个 table 我叫 FUNC
我所有的员工都在那里,我有另一个 table 我可以注册不同的工作角色...每个员工必须有工作角色。
我的工作角色table有它的ID、角色名称、角色的最低工资和角色的最高工资。
我想创建一个触发器,如果加薪在范围内,每次我给某个员工 RAISE 时 CHECKS "Minimum Wage and Maximum Wage".
为了更容易理解,我将展示我到目前为止所做的...
CREATE TABLE FUNC(
IDFUNC INT IDENTITY,
NAME VARCHAR(30) NOT NULL,
SALARY MONEY NOT NULL,
ID_JOB INT,
IDGESTOR INT
)
GO
CREATE TABLE JOB(
IDJOB INT IDENTITY,
NAMEJOB VARCHAR(10) UNIQUE,
MINIMUM MONEY NOT NULL,
MAXIMUM MONEY NOT NULL,
)
/* CONSTRAINTS*/
ALTER TABLE FUNC ADD CONSTRAINT PK_FUNC
PRIMARY KEY(IDFUNC)
GO
ALTER TABLE JOB ADD CONSTRAINT PK_JOB
PRIMARY KEY(IDJOB)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_GESTOR
FOREIGN KEY(IDGESTOR) REFERENCES FUNC(IDFUNC)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_FUNC_JOB
FOREIGN KEY(ID_JOB) REFERENCES JOB(IDJOB)
GO
用这些值填充表格:
INSERT INTO JOB VALUES('MANAGER',5000,10000)
INSERT INTO JOB VALUES('SUPERVISOR',4000,7000)
INSERT INTO JOB VALUES('LEADER',2000,5000)
INSERT INTO JOB VALUES('ANALYST',1200,4000)
GO
IDJOB NAMEJOB MINIMUM MAXIMUM
----------- ---------- --------------------- ---------------------
1 MANAGER 5000,00 10000,00
2 SUPERVISOR 4000,00 7000,00
3 LEADER 2000,00 5000,00
4 ANALYST 1200,00 4000,00
//
INSERT INTO FUNC VALUES('Name1',7000,1,NULL)
INSERT INTO FUNC VALUES('Name2',5000,2,1)
INSERT INTO FUNC VALUES('Name3',5000,2,1)
INSERT INTO FUNC VALUES('Name4',3000,3,2)
INSERT INTO FUNC VALUES('Name5',3400,3,2)
INSERT INTO FUNC VALUES('Name6',2800,3,3)
INSERT INTO FUNC VALUES('Name7',3200,3,3)
INSERT INTO FUNC VALUES('Name8',2000,4,4)
INSERT INTO FUNC VALUES('Name9',1800,4,4)
INSERT INTO FUNC VALUES('Name10',1500,4,5)
INSERT INTO FUNC VALUES('Name11',1300,4,5)
INSERT INTO FUNC VALUES('Name12',3000,4,6)
INSERT INTO FUNC VALUES('Name13',2000,4,6)
INSERT INTO FUNC VALUES('Name14',1900,4,7)
INSERT INTO FUNC VALUES('Name15',2100,4,7)
GO
IDFUNC NAME SALARY ID_JOB IDGESTOR
------------- ------------------------------ --------------------- ----------- -----------
1 Name1 7000,00 1 NULL
2 Name2 5000,00 2 1
3 Name3 5000,00 2 1
4 Name4 3000,00 3 2
5 Name5 3400,00 3 2
6 Name6 2800,00 3 3
7 Name7 3200,00 3 3
8 Name8 2000,00 4 4
9 Name9 1800,00 4 4
10 Name10 1500,00 4 5
11 Name11 1300,00 4 5
12 Name12 3000,00 4 6
13 Name13 2000,00 4 6
14 Name14 1900,00 4 7
15 Name15 2100,00 4 7
最终创建了这个触发器:
CREATE TRIGGER TRG_Salary
ON FUNC
FOR INSERT, UPDATE
AS
DECLARE
@MINIMUM MONEY, @MAXIMUM MONEY, @SALARY MONEY, @IDCARGO INT
SELECT @IDJOB = IDJOB FROM JOB
INNER JOIN INSERTED I
ON IDJOB = I.ID_JOB
WHERE IDFUNC = I.IDFUNC
SELECT @MINIMUM = MINIMUM, @MAXIMUM = MAXIMUM
FROM JOB WHERE IDJOB = @IDJOB
SELECT @SALARY = I.SALARY FROM INSERTED I
IF(@SALARY <@MINIMUM)
BEGIN
RAISERROR ('Salary Must be Higher than Minimum',16,1)
ROLLBACK TRANSACTION
END
IF(@SALARY > @MAXIMUM)
BEGIN
RAISERROR ('SALARIO Must Be Lower than Maximum',16,1)
ROLLBACK TRANSACTION
END
GO
当我只更新一行时它工作正常....
前:
UPDATE FUNC SET SALARY = 15000 WHERE IDFUNC = 1
GO
它会显示错误,因为我的 IDFUNC=1 的员工应该收到 5000 到 10000 之间的信息,因为他是经理
我的问题是当我尝试一次更新所有行时...
就像我想给每个人加薪一样
UPDATE FUNC SET SALARY = SALARY*1.1
更新函数不检查我的触发器内的条件并更新薪水,无论它是在我的范围内还是在我的范围外....
问题是 inserted
包含多行。与大多数其他数据库不同,SQL 服务器不支持 每行 触发器(使用 for each row
子句实现)。
您需要一次检查所有插入的行,如果检查失败则全部拒绝。这是一种使用条件聚合的方法:
create trigger trg_salary
on func
for insert, update
as
declare @isfailed int
select @isfailed = max(
case when i.salary not between j.minimum and j.maximum
then 1
else 0
end
)
from inserted i
inner join job j on j.idjob = i.idjob
if(@isfailed = 1)
begin
raiserror ('salary must be belong to the minimum-maximum range',16,1)
rollback transaction
end
go
INSERTED
伪table包含0-N行,其中N是inserted/updated的行数(可以为零!)。因此,并且因为 SQL 针对 "set based operations" 进行了优化,您需要构建一个查询来测试您的错误情况。
但是正因为如此,除非您想要 return 错误列表,否则即使存在多个错误,您也只能 return 1 个错误。
最好使用 THROW
而不是 RAISERROR
。
CREATE TRIGGER TRG_Salary ON FUNC
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ERROR NVARCHAR(2048);
SELECT TOP 1 @ERROR = CASE WHEN I.SALARY > MAXIMUM THEN 'SALARIO Must Be Lower than Maximum.' WHEN I.SALARY < MAXIMUM THEN 'SALARIO Must Be Higher than Minimum.' END
FROM INSERTED I
INNER JOIN JOB J on J.IDJOB = I.ID_JOB
WHERE I.SALARY > MAXIMUM OR I.SALARY < MAXIMUM;
IF @ERROR IS NOT NULL BEGIN
ROLLBACK;
THROW 51000, @ERROR, 1;
END;
END
GO
MS SQL Server 2017 架构设置:
CREATE TABLE FUNC(
IDFUNC INT IDENTITY,
NAME VARCHAR(30) NOT NULL,
SALARY MONEY NOT NULL,
ID_JOB INT,
IDGESTOR INT
)
GO
CREATE TABLE JOB(
IDJOB INT IDENTITY,
NAMEJOB VARCHAR(10) UNIQUE,
MINIMUM MONEY NOT NULL,
MAXIMUM MONEY NOT NULL,
)
/* CONSTRAINTS*/
ALTER TABLE FUNC ADD CONSTRAINT PK_FUNC
PRIMARY KEY(IDFUNC)
GO
ALTER TABLE JOB ADD CONSTRAINT PK_JOB
PRIMARY KEY(IDJOB)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_GESTOR
FOREIGN KEY(IDGESTOR) REFERENCES FUNC(IDFUNC)
GO
ALTER TABLE FUNC ADD CONSTRAINT FK_FUNC_JOB
FOREIGN KEY(ID_JOB) REFERENCES JOB(IDJOB)
GO
INSERT INTO JOB VALUES('MANAGER',5000,10000)
INSERT INTO JOB VALUES('SUPERVISOR',4000,7000)
INSERT INTO JOB VALUES('LEADER',2000,5000)
INSERT INTO JOB VALUES('ANALYST',1200,4000)
GO
INSERT INTO FUNC VALUES('Name1',7000,1,NULL)
INSERT INTO FUNC VALUES('Name2',5000,2,1)
INSERT INTO FUNC VALUES('Name3',5000,2,1)
INSERT INTO FUNC VALUES('Name4',3000,3,2)
INSERT INTO FUNC VALUES('Name5',3400,3,2)
INSERT INTO FUNC VALUES('Name6',2800,3,3)
INSERT INTO FUNC VALUES('Name7',3200,3,3)
INSERT INTO FUNC VALUES('Name8',2000,4,4)
INSERT INTO FUNC VALUES('Name9',1800,4,4)
INSERT INTO FUNC VALUES('Name10',1500,4,5)
INSERT INTO FUNC VALUES('Name11',1300,4,5)
INSERT INTO FUNC VALUES('Name12',3000,4,6)
INSERT INTO FUNC VALUES('Name13',2000,4,6)
INSERT INTO FUNC VALUES('Name14',1900,4,7)
INSERT INTO FUNC VALUES('Name15',2100,4,7)
GO
CREATE TRIGGER TRG_Salary
ON FUNC
FOR INSERT, UPDATE
AS
IF EXISTS
(
SELECT 1
FROM JOB J
INNER JOIN INSERTED F
ON J.IDJOB = F.ID_JOB
WHERE F.Salary < J.Minimum OR F.Salary > J.Minimum
)
BEGIN
RAISERROR ('SALARIO Must Be Lower than Maximum and Greater than Minimum',16,1)
ROLLBACK TRANSACTION
END
GO
查询 1:
--UPDATE FUNC SET SALARY = 15000 WHERE IDFUNC = 1
UPDATE FUNC SET SALARY = SALARY*1.1
Results: SALARIO 必须小于最大值且大于最小值