sql >> Base de Datos >  >> RDS >> Mysql

Cómo traducir la función PostgreSQL merge_db (aka upsert) a MySQL

Probado en 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');

Algunos pensamientos:

  • No puede hacer una actualización primero y luego verificar @ROW_COUNT() porque devuelve el número de filas que realmente cambiaron. Esto podría ser 0 si la fila ya tiene el valor que está tratando de actualizar.
  • Además, @ROW_COUNT() no es seguro para la replicación.
  • Podrías usar REPLACE...INTO .
  • Si usa InnoDB o una tabla con soporte de transacciones, podría usar SELECT...FOR UPDATE (no probado).

No veo ninguna ventaja en esta solución sobre el simple uso de INSERT...ON DUPLICATE KEY UPDATE .