Php MySQL UPSERT不使用重复密钥

Php MySQL UPSERT不使用重复密钥,php,mysql,database,upsert,Php,Mysql,Database,Upsert,我希望在MySQL表上使用以下字段进行UPSERT(UPDATE,如果存在,则插入): CREATE TABLE item ( uid int(11) NOT NULL AUTO_INCREMENT, timestamp int(11) NOT NULL DEFAULT '0', category1 int(11) NOT NULL DEFAULT '0', category2 int(11) NOT NULL DEFAULT '0', counter int(11) NOT

我希望在MySQL表上使用以下字段进行
UPSERT
UPDATE
,如果存在,则插入):

CREATE TABLE item (
  uid int(11) NOT NULL AUTO_INCREMENT,
  timestamp int(11) NOT NULL DEFAULT '0',
  category1 int(11) NOT NULL DEFAULT '0',
  category2 int(11) NOT NULL DEFAULT '0',
  counter int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`uid`)
)
此表已在生产性使用中,
(时间戳,类别1,类别2)
的组合仅适用于我的
插入
,而不适用于整个表内容。这就是为什么我不能在重复键上使用“”功能的原因

有关独特问题的说明: 如果category1=9,则这是我的插入,
(时间戳,category1,category2)
是唯一的。但该表正在生产性使用中,如果category1=1,2,则
(时间戳,category1,category2)
不是唯一的。 据我所知,我不能添加一个
唯一的
键,因为它会给类别1+2带来问题

我需要的是这样的东西:

 IF (timestamp,category1,category2) exists 
     counter=existingCount + newCount
 ELSE 
     insert new record
我使用PHP和MySQL,所以两种语言的任何组合都可以

我已经试过了,但花了太多时间的是:

  • 单个PHP
    选择
    语句,然后
    更新
    插入
  • 插入
    所有内容,然后
    更新
    删除
    重复行
多亏了我现在创建的这个存储过程的答案,语法还可以,但过程不起作用:

DROP PROCEDURE IF EXISTS myUpsert;
DELIMITER |
CREATE PROCEDURE myUpsert (IN v_timestamp INT, IN v_category1 INT, IN v_category2 INT, IN v_counter INT)        
BEGIN
  DECLARE existingCounter INT;
  SELECT COUNT(counter) AS existingCounter from item 
  WHERE timestamp =v_timestamp  AND category1=v_category1 AND category2=v_category2;

  IF existingCounter=0 THEN
    INSERT INTO item (timestamp,category1,category2,counter) 
    VALUES (v_timestamp,v_category1,v_category2,v_counter);
  ELSE
    UPDATE item SET count=v_counter+existingCounter
    WHERE timestamp=v_timestamp AND category1=v_category1 AND category2=v_category2;
  END IF;
END
|
DELIMITER ;

我建议为这三列添加唯一索引:


ALTER TABLE item ADD UNIQUE(时间戳、类别1、类别2)

能否显示您尝试的代码?不仅仅是重复键上的itINSERT说明?表中是否有唯一的列组合?如果是,请为它们添加一个
唯一
键,并在重复键更新时使用
是否要在表中插入/更新记录?如果单个select+(插入或更新)太慢,您是否尝试过执行upsert存储过程?我相信OP指出列集合在表中不是唯一的。或者您也可以(进入)…将计数(计数器)从…选择到现有计数器…这在并发访问下不起作用。请参阅上的优秀摘要。
DROP PROCEDURE IF EXISTS myUpsert;
DELIMITER |
CREATE PROCEDURE myUpsert (IN v_timestamp INT, IN v_category1 INT, IN v_category2 INT, IN v_counter INT)        
BEGIN
DECLARE existingCounter INT;
  SET existingCounter = (SELECT COUNT(counter) from item 
  WHERE timestamp =v_timestamp  AND category1=v_category1 AND category2=v_category2);

IF existingCounter=0 THEN
 INSERT INTO item (timestamp,category1,category2,counter) 
 VALUES (v_timestamp,v_category1,v_category2,v_counter);
ELSE
 UPDATE item SET count=v_counter+existingCounter
 WHERE timestamp=v_timestamp AND category1=v_category1 AND category2=v_category2;
 END IF;
END
|
DELIMITER ;