2009-07-31 5 views
15

Je voudrais avoir un déclencheur pour effectuer l'opération suivante pour les enregistrements insérés:déclencheur MySQL pour mettre à jour un champ à la valeur id

# pseudocode 
if new.group_id is null 
    set new.group_id = new.id 
else 
    # don't touch it 
end 

Plus clairement: dire que j'ai une table avec trois colonnes: id primaire clé, group_id int, value varchar.

Lorsque j'insère avec group_id comme ça:

INSERT INTO table(value, group_id) VALUES ('a', 10) 

Je voudrais avoir:

id | group_id | value 
---+----------+------ 
1 |  10 | a 

mais quand j'omets group_id:

INSERT INTO table(value) VALUES ('b') 

il devrait être automatiquement mis à id de cette fiche:

id | group_id | value 
---+----------+------ 
2 |  2 | b 

Est-ce possible avec un déclencheur? (Je sais que je peux mettre à jour le dossier après l'insertion, mais ayant le déclencheur serait plus agréable.)

Répondre

25

Je ne connais aucun moyen de le faire dans une déclaration, même en utilisant un déclencheur.

La solution de déclenchement qui @Lucky suggéré ressemblerait à ceci dans MySQL:

CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable 
FOR EACH ROW BEGIN 
    SET NEW.group_id = COALESCE(NEW.group_id, NEW.id); 
END 

Cependant, il y a un problème. Dans la phase BEFORE INSERT, la valeur id générée automatiquement n'a pas encore été générée. Donc, si group_id est nulle, sa valeur par défaut NEW.id qui est toujours 0.

Mais si vous changez ce déclencheur au feu pendant la phase AFTER INSERT, vous avez accès à la valeur générée de NEW.id, vous ne pouvez pas modifier les valeurs de la colonne .

MySQL ne prend pas en charge les expressions pour le DEFAULT d'une colonne, vous ne pouvez donc pas non plus déclarer ce comportement dans la définition de la table.

La seule solution est de faire le INSERT, puis immédiatement faire un UPDATE pour changer le group_id s'il n'est pas défini.

INSERT INTO MyTable (group_id, value) VALUES (NULL, 'a'); 
UPDATE MyTable SET group_id = COALESCE(group_id, id) WHERE id = LAST_INSERT_ID(); 
+0

Ça craint. Même en 2016 –

+0

@AA_PV, cela pourrait être résolu par un objet de séquence indépendant, comme ils le font dans Oracle. Cela a été une demande de fonctionnalité ouverte dans MySQL depuis 2003: https://bugs.mysql.com/bug.php?id=1625 Mais dans Oracle, pour utiliser la séquence, vous devez * l'appeler * dans le code de l'application, qui signifie écrire le code pour * chaque * INSERT dans une table que vous voulez avoir une clé primaire auto-inc. Ou bien écrire un déclencheur pour * chaque * table. Les utilisateurs de MySQL aiment pouvoir écrire autant de déclencheurs, et déclarent simplement AUTO_INCREMENT comme option de colonne. –

+0

oui mais deux colonnes AUTO_INCREMENT ne sont pas autorisées dans MySQL, non? Bien que je pense que quelque chose de similaire à http://stackoverflow.com/a/7345183/4411645 peut être fait. Et pour éviter la requête imbriquée, peut-être que cela peut être maintenu dans le code de l'application, bien que cela puisse être encore plus dangereux, pas sûr. –

0

Je crois que cela va fonctionner pour vous

J'ai deux tables

test_b: a_id, value 
test_c: a_id, value 

Et voici une déclencher sur l'insert du test b. Il vérifie pour voir si a_id est nul et si c'est il insère 0

CREATE TRIGGER test_b AFTER INSERT ON test_b 
    FOR EACH ROW 
    INSERT INTO test_c (a_id, value) VALUES (IFNULL(NEW.a_id, 0),NEW.value) 
+0

Si vous m'en dire plus sur la structure de vos tables, je peux modifier cette requête pour travailler pour vous. –

-2

Ce déclencheur devrait faire ce que vous avez demandé.

CREATE TRIGGER mytrigger BEFORE INSERT ON mytable 
      IF new.group_id IS NULL 
      SET new.group_id = new.id 
      END IF 
     END; 

C'est copié à partir d'un exemple très similaire dans la page MYSQL documentation.

+0

Ne fonctionne pas sur MySQL: Vous avez une erreur dans votre syntaxe SQL; consultez le manuel qui correspond à votre version du serveur MySQL pour la bonne syntaxe à utiliser près de 'WHERE new.group_id IS NULL END' à la ligne 1 – szeryf

+0

Vous devriez être capable d'obtenir la syntaxe exacte des exemples à http: //dev.mysql .com/doc/refman/5.1/fr/create-trigger.html - Je n'ai pas testé. Je vais essayer un edit – Lucky

-2

Un déclencheur semble être surdimensionné dans cette situation. Il suffit d'appliquer une valeur par défaut.

CREATE TABLE `test` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `value` varchar(100) NOT NULL, 
    `group_id` TINYINT(3) UNSIGNED NOT NULL DEFAULT '2' 
) 
+0

Je suis désolé mais vous avez manqué le point. Il ne s'agit pas d'insérer la valeur littérale '2' comme' group_id'. Je veux que le 'id' de cet enregistrement soit le' group_id' sauf si je spécifie explicitement 'group_id'. – szeryf

0

Je réponds, comme dans la réponse acceptée Bill Karwin états:

Dans la phase AVANT INSERT, l'identifiant généré automatiquement n'a pas été encore généré. Donc, si group_id est nul, la valeur par défaut de NEW.id qui est toujours 0.


J'ai une réponse pour elle - pour OP (et les visiteurs à venir), voici quelques points: vous ne pouvez pas mettre à jour la table d'où le déclenchement s'invoqué, car il vous obtiendrez erreur 1442:

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

1.to Mise à jour de la nouvelle ligne Utilisez BEFORE INSERT ON déclencheur, de cette façon vous pouvez mettre à jour tous les champs de la nouvelle ligne, qui peut être accessible par l'opérateur NEW-à-dire

set NEW.group_id = NEW.id 

2.Get valeur auto_increment avant insertion:

SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='MyTable' 

En résumé haut - le déclencheur SQL pour 'd être quelque chose comme suit:

DELIMITER // 
DROP TRIGGER IF EXISTS MyTrigger// 
CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable 
FOR EACH ROW BEGIN 
    IF new.group_id IS NULL 
     set @auto_id := (SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES 
         WHERE TABLE_NAME='MyTable' AND TABLE_SCHEMA=DATABASE()); 
     set NEW.group_id = @auto_id; 
    ENF IF; 
END; 
// 
DELIMITER ; 
+0

La sélection de la valeur auto_increment à partir de la table introduit une condition de concurrence. –

Questions connexes