sql >> Database teknologi >  >> RDS >> Mysql

Sådan oversætter du PostgreSQL merge_db (aka upsert) funktion til MySQL

Testet på 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');

Nogle tanker:

  • Du kan ikke lave en opdatering først og derefter tjekke @ROW_COUNT() fordi det returnerer antallet af rækker, der faktisk er ændret. Dette kunne være 0, hvis rækken allerede har den værdi, du forsøger at opdatere.
  • Også @ROW_COUNT() er ikke replikeringssikker.
  • Du kan bruge REPLACE...INTO .
  • Hvis du bruger InnoDB eller en tabel med transaktionsunderstøttelse, kan du muligvis bruge SELECT...FOR UPDATE (utestet).

Jeg ser ingen fordele ved denne løsning frem for blot at bruge INSERT...ON DUPLICATE KEY UPDATE .




  1. Hvordan redigerer man hurtigt værdier i tabel i SQL Server Management Studio?

  2. Tegnkodningsproblem med PHP Simple HTML DOM Parser

  3. Er det bedre at returnere én stor forespørgsel eller nogle få mindre?

  4. 1045, Adgang nægtet for brugeren 'brugernavn'@'NOT-local' (ved hjælp af adgangskode:JA)