SQL Server在插入时使用触发器删除行
我有两张桌子 评估表 id|ch int | id|abonne int外键引用abonne |求值int| 阿本表 我必须在插入时向evaluer表添加一个触发器。如果该idabonne已有超过5条记录,则触发器应停止插入。我可以编写用于逐行插入的代码,但我希望它也适用于多行,而且我不想使用光标。我用过join,但没用SQL Server在插入时使用触发器删除行,sql,sql-server,Sql,Sql Server,我有两张桌子 评估表 id|ch int | id|abonne int外键引用abonne |求值int| 阿本表 我必须在插入时向evaluer表添加一个触发器。如果该idabonne已有超过5条记录,则触发器应停止插入。我可以编写用于逐行插入的代码,但我希望它也适用于多行,而且我不想使用光标。我用过join,但没用 create trigger eval on evaluer instead of insert as begin insert into evaluer(id_ch,
create trigger eval
on evaluer
instead of insert
as
begin
insert into evaluer(id_ch, id_abonne, evaluation)
select *
from inserted i
join (select ev.id_abonne
from evaluer ev
join inserted ins on ins.id_abonne = ev.id_abonne
group by ev.id_abonne
having count(*) <= 5) tc on i.id_abonne = tc.id_abonne
end
有没有一种不用光标的方法?类似这样的方法
create trigger eval
on evaluer
instead of insert
as
begin
if (select count(*) from inserted)<6
insert into evaluer(id_ch,id_abonne,evaluation)
select * from inserted;
end
像这样的
create trigger eval
on evaluer
instead of insert
as
begin
if (select count(*) from inserted)<6
insert into evaluer(id_ch,id_abonne,evaluation)
select * from inserted;
end
所以我有一个不同的方法,5是一个任意的数字,当有人决定数字应该改变时,改变触发器可能会很麻烦。我建议创建第三个名为EvaluerLimit的表,它只是一个标识/主键,然后插入5次。然后在Evaluer中创建一个非空外键,您的INSTEAD OF INSERT触发器将管理该id。这将使限制数据驱动,当出现错误时,未来的维护人员/编码人员将能够更容易地解决问题 我还想指出的是,您提到删除旧记录,您有一个数据库,在当今世界,您不应该删除记录您想删除它们不是因为您只需要五条记录,如果是这种情况,您应该将select查询更改为按insert date desc排序的前五位,而不是创建触发器 下面是我如何设定的限制,这是一个你可以看到它的行动
CREATE TABLE EvaluerLimit(
Id TINYINT IDENTITY(1,1) PRIMARY KEY
);
CREATE TABLE Evaluer(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
AbonneId INT NOT NULL
CONSTRAINT FK_Evaluer_Abonne_Id
FOREIGN KEY REFERENCES Abonne(Id),
EvaluerLimitId TINYINT NOT NULL
CONSTRAINT FK_Evaluer_EvaluerLimit_Id
FOREIGN KEY REFERENCES EvaluerLimit(Id),
CONSTRAINT UQ_Evaluer_AbonneId_EvaluerLimitId
UNIQUE(AbonneId, EvaluerLimitId)
);
DECLARE @i TINYINT = 0
WHILE @i < 5 BEGIN
INSERT INTO EvaluerLimit DEFAULT VALUES
SET @i = @i + 1
END;
CREATE TRIGGER TR_EvaluerInsert ON Evaluer
INSTEAD OF INSERT
AS BEGIN
DECLARE @limit TINYINT
SELECT @limit = ISNULL(MAX(e.EvaluerLimitId),0)+1
FROM Evaluer e
INNER JOIN inserted
ON e.AbonneId = inserted.AbonneId
INSERT INTO Evaluer(AbonneId, EvaluerLimitId)
SELECT inserted.AbonneId, @limit
FROM inserted
END;
所以我有一个不同的方法,5是一个任意的数字,当有人决定数字应该改变时,改变触发器可能会很麻烦。我建议创建第三个名为EvaluerLimit的表,它只是一个标识/主键,然后插入5次。然后在Evaluer中创建一个非空外键,您的INSTEAD OF INSERT触发器将管理该id。这将使限制数据驱动,当出现错误时,未来的维护人员/编码人员将能够更容易地解决问题 我还想指出的是,您提到删除旧记录,您有一个数据库,在当今世界,您不应该删除记录您想删除它们不是因为您只需要五条记录,如果是这种情况,您应该将select查询更改为按insert date desc排序的前五位,而不是创建触发器 下面是我如何设定的限制,这是一个你可以看到它的行动
CREATE TABLE EvaluerLimit(
Id TINYINT IDENTITY(1,1) PRIMARY KEY
);
CREATE TABLE Evaluer(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
AbonneId INT NOT NULL
CONSTRAINT FK_Evaluer_Abonne_Id
FOREIGN KEY REFERENCES Abonne(Id),
EvaluerLimitId TINYINT NOT NULL
CONSTRAINT FK_Evaluer_EvaluerLimit_Id
FOREIGN KEY REFERENCES EvaluerLimit(Id),
CONSTRAINT UQ_Evaluer_AbonneId_EvaluerLimitId
UNIQUE(AbonneId, EvaluerLimitId)
);
DECLARE @i TINYINT = 0
WHILE @i < 5 BEGIN
INSERT INTO EvaluerLimit DEFAULT VALUES
SET @i = @i + 1
END;
CREATE TRIGGER TR_EvaluerInsert ON Evaluer
INSTEAD OF INSERT
AS BEGIN
DECLARE @limit TINYINT
SELECT @limit = ISNULL(MAX(e.EvaluerLimitId),0)+1
FROM Evaluer e
INNER JOIN inserted
ON e.AbonneId = inserted.AbonneId
INSERT INTO Evaluer(AbonneId, EvaluerLimitId)
SELECT inserted.AbonneId, @limit
FROM inserted
END;
虽然我重申了我在上述评论中提出的担忧,但如果我必须这样做,我可能会使用以下内容:
create trigger eval
on evaluer
instead of insert
as
begin
insert into evaluer(id_ch, id_abonne, evaluation)
select i.*
from (select i.*,
row_number() over(partition by i.id_abonne order by (select null)) as iRowCount
from inserted i) i
join (select ev.id_abonne, count(id_abonne) as evCount
from evaluer ev
group by ev.id_abonne) ev ON ev.id_abonne = i.id_abonne
And evCount < 5
And iRowCount <= 5 - evCount
end
这将向inserted添加一列,该列保留每个id_abonne的新行的运行计数,并从evaluer按表汇总每个id_abonne的现有行总数。然后它在id_abonne上连接它们,过滤掉任何插入的行,这些行将使id_abonne行计数超过5,并将剩余的内容插入表中。当我重申我在上面的评论中提出的问题时,如果我必须这样做,我可能会使用类似这样的方法:
create trigger eval
on evaluer
instead of insert
as
begin
insert into evaluer(id_ch, id_abonne, evaluation)
select i.*
from (select i.*,
row_number() over(partition by i.id_abonne order by (select null)) as iRowCount
from inserted i) i
join (select ev.id_abonne, count(id_abonne) as evCount
from evaluer ev
group by ev.id_abonne) ev ON ev.id_abonne = i.id_abonne
And evCount < 5
And iRowCount <= 5 - evCount
end
这将向inserted添加一列,该列保留每个id_abonne的新行的运行计数,并从evaluer按表汇总每个id_abonne的现有行总数。然后,它在id_abonne上连接它们,过滤掉任何插入的行,这些行将使id_abonne行计数超过5,并将剩余的内容插入表中。因此,如果应用程序插入5行以上,而您只需忽略第五行之后的所有内容,您认为在不向应用程序提供任何反馈的情况下,简单地在不可见的情况下删除额外的内容是明智的吗?或者停止插入实际上意味着应该引发一个错误,然后应用程序可以以某种方式响应该错误吗?我必须同意@SMor的观点,数据库服务器的无声故障通常是一个坏主意,以后会导致很多问题。例如,插入的伪表没有隐式顺序,因此如果插入五行以上,无法保证实际会插入哪些记录。我想在停止插入后显示一条消息,触发器应该先插入5条记录,然后停止添加更多记录。因此,如果应用程序插入的行数超过5行,而您只是忽略了第五行之后的所有内容,您认为在不向应用程序提供任何反馈的情况下,简单地在不可见的情况下删除额外的内容是明智的吗?或者停止插入实际上意味着应该引发一个错误,然后应用程序可以以某种方式响应该错误吗?我必须同意@SMor的观点,数据库服务器的无声故障通常是一个坏主意,以后会导致很多问题。例如,插入的伪表没有隐式顺序,因此如果插入的行数超过五行,则无法保证实际插入的是哪一行。我希望在停止插入后显示一条消息,触发器应插入前5条记录,然后停止添加更多记录