2009-09-30 7 views
2

J'utilise mysql5.1 et j'ai écrit trigger après update.am en utilisant la même table pour insérer et updae. table contient .id de champ, itemid, valeur1 tous sont entier ..mysql trigger dans la même table

mon déclencheur est:

CREATE DEFINER = 'root'@'%' TRIGGER `trig_same` 
    AFTER UPDATE 
    ON `vote` 
    FOR EACH ROW 
BEGIN 
    insert into vote values(10,1,100); 
END| 

... mais quand j'excute commande update i eu erreur:

SQL Error: Can't update table 'vote' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. 

Répondre

1

Tel que défini, le déclencheur crée une référence circulaire . Il insère encore une autre ligne, ce qui nécessiterait alors l'appel du déclencheur, et insère une autre ligne, ce qui entraînerait une nouvelle invocation ....

Si SQL n'avait pas détecté cela, la table des votes aurait fini par être plein de ces (10,1,100) enregistrements, à moins de manquer d'espace pour la base de données ou sur le disque dur tout à fait.

Je suppose que vous souhaitez seulement ajouter un enregistrement supplémentaire pour chaque insertion d'enregistrement 'normale'. Ceci pourrait être réalisé en modifiant la logique qui effectue l'insertion elle-même (ajoutez le deuxième INSERT à ce niveau si possible).
EDIT [17 avril 2011]: Comme indiqué par Johan, le "contraption" suivant échouerait avec la même erreur. Je ne m'inquiète pas de la réparer étant donné le cas d'utilisation sous-jacent plutôt étrange ...
Une autre façon serait avec une table séparée avec son propre après INSERT Trigger; le déclencheur de la table de vote devrait tester les valeurs (10,1,100) et retourner (ne rien faire d'autre) dans ce cas, et sinon insérer un enregistrement sur l'autre table; cette autre table aurait son déclencheur insérer cet enregistrement sur la table 'vote'. (Tout à fait artificiel pour un cas d'utilisation relativement étrange!)

+0

lorsque j'utilise la même table pour toutes les opérations de déclenchement j'ai eu cette erreur. – maxy

+0

@maxy, à droite, je m'en rends compte. C'est ce que j'essaie d'expliquer dans ma réponse; Vous ne pouvez pas avoir une référence circulaire directe, et, vous devez casser la récursivité ... – mjv

+0

comment puis-je casser cela..avoir une autre solution pour cela .. – maxy

0

Briser référence circulaire nécessaire une autre table par exemple:

CREATE TABLE `trigger_semaphore` (
    `id` INTEGER(11) NOT NULL, 
    `semaphore` INTEGER(11) DEFAULT NULL, 
    `actions` VARCHAR(20) COLLATE utf8_general_ci DEFAULT NULL, 
    `random` INTEGER(11) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
)ENGINE=MyISAM 
CHARACTER SET 'latin1' COLLATE 'latin1_swedish_ci'; 

CREATE DEFINER = 'root'@'localhost' TRIGGER `trigger_semaphore_before_upd_tr` 
BEFORE UPDATE ON `trigger_semaphore` 
    FOR EACH ROW 
BEGIN 
DECLARE semaphore int; 
    set New.random=RAND()*1000; 
    if New.actions='++' then 
    set New.semaphore=COALESCE(New.semaphore,0)+1; 
    elseif New.actions='--' then 
    set semaphore= COALESCE(New.semaphore,0); 
    if semaphore<=0 then 
     set New.semaphore=semaphore; 
    else 
    set New.semaphore=semaphore-1; 
    end if; 
    end if; 
END; 

Dans les déclencheurs pour les tableaux qui mettent à jour chaque autre table utilisation de trigger_semaphore ainsi:

update trigger_semaphore set actions='++' where id=1; 

    select semaphore into _semaphore from trigger_semaphore where id=1; 

    if _semaphore=1 then 

    # ...... Here goes the code without circular reference.......... 

    end if; 

Relâchez le sémaphores maintenant à la fin du déclencheur

update trigger_semaphore set actions='--' where id=1; 

En bref, la table qui définit le premier sémaphore (1) ne pourra exécuter que certaines instructions . Vous pouvez utiliser une méthode simple une fois que vous avez l'idée;)

+0

J'ai vérifié votre solution et cela ne fonctionne pas OU pourriez-vous expliquer plus et fournir des codes de source plus spécifiques? – Marecky

+0

c'est tout le code que j'utilise dans les triggers, peut-être pourriez-vous poster tout votre code quelque part (pastbin?) Que je pourrais vérifier. Vous devez vous rappeler que cette solution ne fournit pas une solution parfaite. Vous pouvez utiliser simplement des gestionnaires d'exceptions/erreurs pour gérer le problème de référence circulaire de sorte que, chaque fois que vous les avez, vous quittez simplement le déclencheur – sakhunzai

Questions connexes