web-dev-qa-db-fra.com

Truc pour auto_incrèce sur des clés composites à Innodb

Contrairement au moteur MySQL Myisam, le moteur InnoDb ne peut pas gérer lorsqu'une colonne d'une clé primaire composite est déclarée AUTO_INCREMENT. Par exemple, considérons le tableau suivant:

CREATE TABLE `ExampleTable` (
     `KeyPartA` mediumint(8) unsigned NOT NULL,
     `KeyPartB` smallint(5) unsigned NOT NULL,
     `Data` text NOT NULL,
     PRIMARY KEY (`KeyPartA`,`KeyPartB`)
) ENGINE=InnoDB;

Maintenant simuler AUTO_INCREMENT, J'ai appris, il est possible de créer le déclencheur suivant

DELIMITER $$

CREATE TRIGGER ExampleAutoIncrement BEFORE INSERT ON ExampleTable
FOR EACH ROW BEGIN
        SET NEW.KeyPartB = (
             SELECT IFNULL(MAX(KeyPartB), 0) + 1
             FROM ExampleTable
             WHERE KeyPartA  = NEW.KeyPartA
        );
END $$

DELIMITER ;

Maintenant, les insertions fonctionnent correctement, générant des valeurs auto-incrémentées. Malheureusement, je ne peux pas penser à un moyen judicieux d'obtenir la valeur clé nouvellement créée.

Ni LAST_INSERT_ID() _ NOR CANAL DE COLLABLE DE C, car il n'y a pas de colonne AUTO_INCREMENT. Il n'est également pas possible de définir la valeur avec LAST_INSERT_ID(IFNULL(MAX(KeyPartB), 0) + 1) à l'intérieur de la gâchette ExampleAutoIncrement, car MySQL réinitialise la valeur après la finition de la gâchette.

La seule façon dont j'ai pensé était de délivrer une SELECT MAX(KeyPartB) FROM ExampleTable WHERE KeyPartA = ? après un insert, qui défait tout le but de la gâchette. C'est à dire. Je pourrais aussi bien faire cela avant l'insertion et l'incrémentation manuellement.

Existe-t-il un moyen d'obtenir la valeur clé incrémentée de la gâchette ou d'un autre moyen de simuler le AUTO_INCREMENT Je veux?

4
bodo

Ma solution est dans Migration de Myisam à Innodb . Ça va quelque chose comme:

  BEGIN;
  SELECT @id := IFNULL(MAX(id),0) + 1 FROM foo WHERE other = 123 FOR UPDATE;
  INSERT INTO foo
     (other, id, ...)
     VALUES
     (123, @id, ...);
  COMMIT;

Avoir une transaction est obligatoire pour empêcher un autre thread de saisir le même identifiant.

4
Rick James