Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment traduire la fonction PostgreSQL merge_db (alias upsert) en MySQL

Testé sur MySQL 5.5.14.

CREATE TABLE db (a INT PRIMARY KEY, b TEXT);

DELIMITER //
CREATE PROCEDURE merge_db(k INT, data TEXT) 
BEGIN
    DECLARE done BOOLEAN;
    REPEAT
        BEGIN
            -- If there is a unique key constraint error then 
            -- someone made a concurrent insert. Reset the sentinel
            -- and try again.
            DECLARE ER_DUP_UNIQUE CONDITION FOR 23000;
            DECLARE CONTINUE HANDLER FOR ER_DUP_UNIQUE BEGIN
                SET done = FALSE;
            END;

            SET done = TRUE;
            SELECT COUNT(*) INTO @count FROM db WHERE a = k;
            -- Race condition here. If a concurrent INSERT is made after
            -- the SELECT but before the INSERT below we'll get a duplicate
            -- key error. But the handler above will take care of that.
            IF @count > 0 THEN 
                UPDATE db SET b = data WHERE a = k;
            ELSE 
                INSERT INTO db (a, b) VALUES (k, data);
            END IF;
        END;
    UNTIL done END REPEAT;
END//

DELIMITER ;

CALL merge_db(1, 'david');
CALL merge_db(1, 'dennis');

Quelques réflexions :

  • Vous ne pouvez pas d'abord faire une mise à jour puis vérifier @ROW_COUNT() car il renvoie le nombre de lignes réellement modifiées. Cela peut être 0 si la ligne contient déjà la valeur que vous essayez de mettre à jour.
  • Aussi, @ROW_COUNT() n'est pas sûr pour la réplication.
  • Vous pouvez utiliser REPLACE...INTO .
  • Si vous utilisez InnoDB ou une table avec prise en charge des transactions, vous pourrez peut-être utiliser SELECT...FOR UPDATE (non testé).

Je ne vois aucun avantage à cette solution par rapport à la simple utilisation de INSERT...ON DUPLICATE KEY UPDATE .