Sea*_*ere 1 mysql sql postgresql upsert
直接从手册,这是PostgreSQL中merge_db的规范示例:
CREATE TABLE db (a INT PRIMARY KEY, b TEXT);
CREATE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS
$$
BEGIN
LOOP
-- first try to update the key
UPDATE db SET b = data WHERE a = key;
IF found THEN
RETURN;
END IF;
-- not there, so try to insert the key
-- if someone else inserts the same key concurrently,
-- we could get a unique-key failure
BEGIN
INSERT INTO db(a,b) VALUES (key, data);
RETURN;
EXCEPTION WHEN unique_violation THEN
-- Do nothing, and loop to try the UPDATE again.
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
SELECT merge_db(1, 'david');
SELECT merge_db(1, 'dennis');
Run Code Online (Sandbox Code Playgroud)
这可以表示为MySQL中的用户定义函数,如果是,如何?MySQL的标准会有什么优势INSERT...ON DUPLICATE KEY UPDATE吗?
注意:我专门寻找用户定义的函数,而不是INSERT...ON DUPLICATE KEY UPDATE.
小智 5
在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');
Run Code Online (Sandbox Code Playgroud)
一些想法:
@ROW_COUNT()因为它返回实际更改的行数.如果行已经具有您尝试更新的值,则该值可以为0.@ROW_COUNT()不是复制安全.REPLACE...INTO.SELECT...FOR UPDATE(未经测试).我觉得这个解决方案没有优势而只是使用INSERT...ON DUPLICATE KEY UPDATE.