直接从手册中获取,这里是canonical example of merge_db in PostgreSQL
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');在MySQL中可以将其表示为用户定义的函数吗?如果可以,如何表示?与MySQL的标准INSERT...ON DUPLICATE KEY UPDATE相比有什么优势吗?
注意:我特别想找一个用户定义的函数,而不是INSERT...ON DUPLICATE KEY UPDATE。
发布于 2012-07-07 12:15:29
已在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');一些想法:
@ROW_COUNT(),因为它会返回实际更改的行数。如果行已经具有您尝试更新的值,则此值可能为0。@ROW_COUNT()不是复制安全的。REPLACE...INTO. InnoDB或具有事务支持的表,您可以使用SELECT...FOR UPDATE (未测试)。
与仅仅使用INSERT...ON DUPLICATE KEY UPDATE相比,我看不出这种解决方案有什么优势。
https://stackoverflow.com/questions/11371479
复制相似问题