简体   繁体   English

SQLite更新触发器更改表中的所有行

[英]SQLite update trigger changes all rows in the table

Problem: a simplest possible update trigger writes a new value to all table rows instead of just the row being updated. 问题:最简单的更新触发器会将新值写入所有表行,而不仅仅是正在更新的行。 Here is the table: 这是表格:

[names] [名]

id INTEGER PRIMARY KEY
name TEXT
len INTEGER

Now I want to create triggers to update 'len' with the length of 'name'. 现在我想创建触发器以'name'的长度更新'len'。 This INSERT trigger seems to be doing the job corectly: 这个INSERT触发器似乎正在做核心工作:

CREATE TRIGGER 'namelen' AFTER INSERT ON 'names'
BEGIN
UPDATE 'names' SET len = length(NEW.name) WHERE (id=NEW.id);
END;

Problems begin when I add a similar UPDATE trigger: 添加类似的UPDATE触发器时出现问题:

CREATE TRIGGER 'namelenupd' AFTER UPDATE ON 'names'
BEGIN
UPDATE 'names' SET len = length(NEW.name) WHERE (OLD.id=NEW.id);
END;

The update trigger writes the new length to all rows of the table, despite the WHERE clause. 尽管有WHERE子句,update触发器会将新长度写入表的所有行 For example, if I say 例如,如果我说

UPDATE 'names' SET name='foo' where id=1;

then the value of 'len' becomes 3 for all rows of the table. 然后'len'的值对于表的所有行变为3。 I've looked at sqlite trigger examples and I can't see my error. 我看过sqlite触发器示例,我看不到我的错误。 What else must I do to make sure the trigger updates the 'len' column only in the row(s) that are actually updated? 还有什么办法可以确保触发器在实际更新的行中更新'len'列?

Both OLD.xxx and NEW.xxx refer to the table row that caused the trigger to run. OLD.xxx和NEW.xxx都引用导致触发器运行的表行。 The UPDATE statement inside the trigger runs independently; 触发器内的UPDATE语句独立运行; if you want to restrict it to one table row, you have to explicitly do this in its WHERE clause by filtering on that statement's table values, ie, names.id or just id . 如果要将其限制为一个表行,则必须通过对该语句的表值(即names.idid进行过滤,在其WHERE子句中显式执行此操作。

When the original UPDATE statement does not change the id column, the old and new id values are the same, and the expression OLD.id=NEW.id is true for all records in the table, as seen by the inner UPDATE statement. 当原始UPDATE语句不更改id列时,旧id和新id值相同,表达式OLD.id=NEW.id对于表中的所有记录为true,如内部UPDATE语句所示。

The correct trigger looks like this: 正确的触发器如下所示:

CREATE TRIGGER "namelenupd"
AFTER UPDATE OF name ON "names"
BEGIN
    UPDATE "names" SET len = length(NEW.name) WHERE id = NEW.id;
END;

Had the same issue, here's the syntax from my trigger 有同样的问题,这是我的触发器的语法

You would change "ALTER" to "CREATE" depending on what you already have (or not) 您可以将“ALTER”更改为“CREATE”,具体取决于您已经拥有(或不拥有)

You have "id" as your primary key 您有"id"作为主键

Your dbo is "names" 你的dbo是"names"

Obviously, this will set the name value to "foo" (not really what you wanted). 显然,这会将名称值设置为“foo”(不是你想要的)。 The key seems to be the last line, where you set inner join inserted on names.Id = inserted.Id . 键似乎是最后一行,您在其中设置inner join inserted on names.Id = inserted.Id

USE [yourDBname]
    ALTER TRIGGER [dbo].[yourTrigger]
       ON  [dbo].[names] 
       After INSERT, UPDATE 
    AS 

    BEGIN
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;

    Select id from inserted
        begin
         update [dbo].names
            set [dbo].names.name = 'foo' 
            from dbo.names 
               inner join inserted 
               on names.id = inserted.id
        END

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM