2014-04-13 14 views
5

Problem: najprostszy możliwy wyzwalacz aktualizacji zapisuje nową wartość we wszystkich wierszach tabeli zamiast tylko aktualizowanego wiersza. Oto tabela:Wyzwalacz aktualizacji SQLite zmienia wszystkie wiersze w tabeli

[nazwy]

id INTEGER PRIMARY KEY 
name TEXT 
len INTEGER 

Teraz chcę tworzyć wyzwalacze zaktualizować 'len' z długością 'name'. Ten INSERT wyzwalacz zdaje się robić zadania corectly:

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

Problemy zaczynają się, gdy dodam podobny spust UPDATE:

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

Spust aktualizacja pisze nową długość do wszystkie wiersze tabeli pomimo klauzuli WHERE. Na przykład, jeśli powiem

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

wówczas wartość „len” staje 3 dla wszystkich wierszy tabeli. Przyjrzałem się przykładom wyzwalacza SQL i nie widzę mojego błędu. Co jeszcze należy zrobić, aby upewnić się, że wyzwalacz aktualizuje kolumnę "len" w wierszu (wersjach), które są rzeczywiście aktualizowane?

+0

próbowałaś ** SET UPDATE 'names' len = length (NEW.name) WHERE (id = OLD.id); ** – sqlab

+0

Jak rozwiązać ten problem? – Anima

Odpowiedz

9

Zarówno OLD.xxx, jak i NEW.xxx odnoszą się do wiersza tabeli, który spowodował uruchomienie wyzwalacza. Instrukcja UPDATE wewnątrz wyzwalacza działa niezależnie; Jeśli chcesz ograniczyć go do jednego wiersza tabeli, musisz to zrobić jawnie w klauzuli WHERE, filtrując wartości tabeli wartości instrukcji , tj. names.id lub po prostu id.

Gdy oryginalna instrukcja UPDATE nie zmienia kolumnę id, stare i nowe id wartości są takie same, a wyrażenie OLD.id=NEW.id jest prawdziwe dla wszystkich rekordów w tabeli, z punktu widzenia wewnętrznej instrukcji UPDATE.

Prawidłowe spust wygląda następująco:

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

Jeśli oryginalna instrukcja UPDATE nie zmienia identyfikatora, to id = NEW.id jest prawdziwe dla wszystkich wierszy w prawo? – Anima

+0

@ Amina No; "id" ma inną wartość dla każdego wiersza, ale 'NEW.id' jest wartością * pojedynczą * podczas jednego uruchomienia wyzwalacza. –

+0

aa, widzę. dzięki!! – Anima

0

miał ten sam problem, oto składnia z mojego spustu

byś zmienił „alter”, aby „stworzyć” w zależności od tego, co już masz (lub nie)

masz "id" jako podstawowego klucza

swojej dbo jest "names"

Oczywiście ustawi to nazwę na "foo" (niezupełnie to, czego chciałeś). Klucz wydaje się być ostatnim wierszem, w którym ustawiono 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 
+0

SQLite nie ma WYKORZYSTANIA ani ALTER TRIGGER. –

+0

@CL Podatność na drobiazgi. – Terri

+0

W przypadku pytania na temat SQLite ta odpowiedź w ogóle nie jest użyteczna *. Właśnie do tego służą downvotes. –

Powiązane problemy