Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como traduzir a função merge_db do PostgreSQL (também conhecida como upsert) para o MySQL


Testado no 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');

Alguns pensamentos:
  • Você não pode fazer uma atualização primeiro e depois verificar @ROW_COUNT() porque ele retorna o número de linhas realmente alteradas. Pode ser 0 se a linha já tiver o valor que você está tentando atualizar.
  • Além disso, @ROW_COUNT() não é seguro para replicação.
  • Você pode usar REPLACE...INTO .
  • Se estiver usando InnoDB ou uma tabela com suporte a transações, você poderá usar SELECT...FOR UPDATE (não testado).

Não vejo vantagem nesta solução em apenas usar INSERT...ON DUPLICATE KEY UPDATE .