SQL Server在插入时使用触发器删除行

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,

我有两张桌子

评估表

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, 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条记录,然后停止添加更多记录