在MySQL中执行UPDATE时,在重复键上加上“count”列

时间:2012-08-02 15:23:53

标签: php mysql

我有一个计数表,我希望能够在重命名其中一个复合键字段时对计数求和。这很难解释,所以让我给你看一些SQL:

示例表:

CREATE TABLE `test` (
  `id` int(11) NOT NULL,
  `type` int(11) NOT NULL,
  `count` int(11) NOT NULL,
  PRIMARY KEY (`id`,`type`)
);

插入一些数据:

INSERT INTO test VALUES(1, 10, 1);
INSERT INTO test VALUES(2, 20, 3);
INSERT INTO test VALUES(2, 10, 3);
INSERT INTO test VALUES(2, 30, 3);

查询数据:

mysql> SELECT SUM(count) as count FROM test WHERE id = 2;
+-------+
| count |
+-------+
|     9 |
+-------+

mysql> SELECT SUM(count) as count FROM test WHERE type = 10;
+-------+
| count |
+-------+
|     4 |
+-------+

效果很好,快速而灵活。

现在,我想重映射类型10到20型

UPDATE test SET type = 20 WHERE type = 10;
Duplicate entry '2-20' for key 'PRIMARY'

此处使用ON DUPLICATE KEY UPDATE无效。 我认为应该可以使用创意插页,但我不确定。任何人都可以想到一种方法吗?

3 个答案:

答案 0 :(得分:1)

更新查询时,您要创建包含id = 2type = 20的多行,由于您的primary key限制,这是不允许的。

您应该使用单个列作为主键,并在插入新行时使其自动增加。这样就保证了它的独特性。

答案 1 :(得分:1)

一种方法是放松"放松" PRIMARY KEY,意思是,将它从PRIMARY(唯一)KEY更改为非唯一KEY。这将允许重复值,并允许您的UPDATE语句成功,这样您将有两个(或更多)具有匹配(id,type)的行。 (请注意,这会使更新单行成为问题,因此您可能希望添加一个唯一的新列.AUTO_INCREMENT列可以很好地用于此。)


如果你不想这样做,那么另一种方法就是"结合"将类型10和类型20行的计数(对于每个id)计入类型20行,将类型10行的计数设置为零,并(可选)在单独的语句中删除冗余类型10行。

以下声明"结合"类型10和类型20按"映射"第一个选择中的10值为20。


 -- combine count for types 10 and 20 as new count for type 20
 -- and set count to zero for type 10

 INSERT INTO test (id, `type`, `count`)
 SELECT t.id
      , IF(t.`type`=10,20,t.`type`) AS new_type
      , SUM(t.`count`) AS `count`
   FROM test t
  WHERE t.`type` IN (10,20)
  GROUP BY id, new_type
  UNION ALL
 SELECT u.id
      , u.`type`
      , 0 AS `count`
   FROM test u
  WHERE u.`type` = 10
     ON DUPLICATE KEY UPDATE `count` = VALUES(`count`);

 -- remove unnecessary type 10 rows.
 DELETE FROM test WHERE `type` = 10 AND `count` = 0;

注意:第一个SELECT中的IF()表达式等同于:

CASE WHEN t.type = 10 THEN 20 ELSE t.type END

第二个选择是为我们提供所有需要更新的10行。我们使用UNION ALL运算符连接这两个结果集。

然后我们采用组合(连接)结果集,并将它们运行到插入中。我们遇到的任何地方都是重复的#34; key,我们通过ON DUPLICATE KEY子句执行更新操作。

您可能希望在事务中执行此操作(如果您使用的是InnoDB)并在执行DELETE之前验证第一个语句是否成功完成。如果第一个语句抛出异常(可能有一个不稳定的触发器),那么你会想要ROLLBACK事务。如果由于某种原因DELETE失败,您也想要ROLLBACK(可能存在违反的外键约束。)

或者,您不一定需要执行DELETE,您可以保留10行,计数为零。


重要:

请勿同时实施这些解决方案!只有其中一个。

第一种方法是架构更改,它不需要任何数据更改。这一改变将使您的UPDATE成功。

第二种方法要求模式保持不变,并且取决于(id,type)上UNIQUE KEY的存在(和强制执行)。

答案 2 :(得分:0)

您已在两列上设置主键,更新后第三行主键与第二行相同,因此不允许使用。

最后你会有1..20; 2..20,2..20等。