Mysql
 sql >> Datenbank >  >> RDS >> Mysql

So übersetzen Sie die PostgreSQL-Funktion merge_db (auch bekannt als Upsert) in MySQL

Getestet auf 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');

Einige Gedanken:

  • Sie können nicht zuerst ein Update durchführen und dann @ROW_COUNT() weil es die Anzahl der tatsächlich geänderten Zeilen zurückgibt. Dies könnte 0 sein, wenn die Zeile bereits den Wert hat, den Sie aktualisieren möchten.
  • Außerdem @ROW_COUNT() ist nicht replikationssicher.
  • Sie könnten REPLACE...INTO verwenden .
  • Wenn Sie InnoDB oder eine Tabelle mit Transaktionsunterstützung verwenden, können Sie möglicherweise SELECT...FOR UPDATE verwenden (ungetestet).

Ich sehe keinen Vorteil für diese Lösung gegenüber der einfachen Verwendung von INSERT...ON DUPLICATE KEY UPDATE .