【问题标题】:MySQL: Strange behavior of UPDATE query (ERROR 1062 Duplicate entry)MySQL:UPDATE 查询的奇怪行为(ERROR 1062 Duplicate entry)
【发布时间】:2018-09-17 04:35:34
【问题描述】:

我有一个 MySQL 数据库,用于存储带有发布日期(只是日期信息)、来源和类别的新闻文章。基于这些,我想生成一个包含文章计数 w.r.t 的表。这三个参数。

由于这 3 个参数的某些组合可能没有文章,因此简单的 GROUP BY 是行不通的。因此,我首先生成一个表 news_article_counts,其中包含 3 个参数的所有可能组合,默认 article_count 为 0 —— 像这样:

SELECT * FROM news_article_counts;
+--------------+------------+----------+---------------+
| published_at | source     | category | article_count |
+------------- +------------+----------+---------------+
| 2016-08-05   | 1826089206 |        0 |             0 |
| 2016-08-05   | 1826089206 |        1 |             0 |
| 2016-08-05   | 1826089206 |        2 |             0 |
| 2016-08-05   | 1826089206 |        3 |             0 |
| 2016-08-05   | 1826089206 |        4 |             0 |
| ...          | ...        |      ... |           ... |
+--------------+------------+----------+---------------+

为了测试,我现在创建了一个临时表 tmp 作为原始新闻文章表的 GROUP BY 结果:

SELECT * FROM tmp LIMIT 6;
+--------------+------------+----------+-----+
| published_at | source     | category | cnt |
+--------------+------------+----------+-----+
| 2016-08-05   | 1826089206 |        3 |   1 |
| 2003-09-19   | 1826089206 |        4 |   1 |
| 2005-08-08   | 1826089206 |        3 |   1 |
| 2008-07-22   | 1826089206 |        4 |   1 |
| 2008-11-26   | 1826089206 |        8 |   1 |
| ...          | ...        |      ... | ... |
+--------------+------------+----------+-----+

鉴于这两个表,以下查询按预期工作:

SELECT * FROM news_article_counts c, tmp t
WHERE c.published_at = t.published_at AND c.source = t.source AND c.category = t.category;

但现在我需要用表tmp 中的3 个参数匹配的值更新表news_article_countsarticle_count。为此,我使用以下查询(我尝试了不同的方法,但结果相同):

UPDATE 
  news_article_counts c
INNER JOIN
  tmp t
ON
  c.published_at = t.published_at AND
  c.source = t.source AND
  c.category = t.category
SET
  c.article_count = t.cnt;

执行此查询会产生此错误:

ERROR 1062 (23000): Duplicate entry '2018-04-07 14:46:17-1826089206-1' for key 'uniqueIndex'

uniqueIndex 是表news_article_countspublished_atsourcecategory 上的联合索引。但这不应该是一个问题,因为我没有——据我所知——更新这 3 个值中的任何一个,只更新 article_count

最让我困惑的是,它在错误中提到了我执行查询的时间戳(这里:2018-04-07 14:46:17)。我完全不知道这在哪里起作用。事实上,news_article_counts 中的某些行现在将2018-04-07 14:46:17 作为published_at 的值。虽然这解释了错误,但我不明白为什么 published_at 会被当前时间戳覆盖。此栏目没有ON UPDATE CURRENT_TIMESTAMP;见:

CREATE TABLE IF NOT EXISTS `test`.`news_article_counts` (
  `published_at` TIMESTAMP NOT NULL,
  `source` INT UNSIGNED NOT NULL,
  `category` INT UNSIGNED NOT NULL,
  `article_count` INT UNSIGNED NOT NULL DEFAULT 0,
  UNIQUE INDEX `uniqueIndex` (`published_at` ASC, `source` ASC, `category`  ASC))
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8mb4;

我在这里错过了什么?

UPDATE 1:我实际上检查了数据库中news_article_counts的表定义。而且确实有以下几点:

mysql> SHOW COLUMNS FROM news_article_counts;
+---------------+------------------+------+-----+-------------------+-----------------------------+
| Field         | Type             | Null | Key | Default           | Extra                       |
+---------------+------------------+------+-----+-------------------+-----------------------------+
| published_at  | timestamp        | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| source        | int(10) unsigned | NO   |     | NULL              |                             |
| category      | int(10) unsigned | NO   |     | NULL              |                             |
| article_count | int(10) unsigned | NO   |     | 0                 |                             |
+---------------+------------------+------+-----+-------------------+-----------------------------+

但是为什么要设置on update CURRENT_TIMESTAMP。我仔细检查了我的 CREATE TABLE 语句。我删除了联合索引,我添加了一个人工主键(auto_increment)。没什么帮助。我什至尝试从published_at 中明确删除这些属性:

ALTER TABLE `news_article_counts` CHANGE `published_at` `published_at` TIMESTAMP NOT NULL;

似乎没有什么对我有用。

【问题讨论】:

标签: mysql sql-update mysql-error-1062


【解决方案1】:

您似乎禁用了explicit_defaults_for_timestamp 系统变量。这样做的效果之一是:

表中的第一个TIMESTAMP 列,如果没有使用NULL 属性或显式DEFAULTON UPDATE 属性显式声明,将自动使用DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP 属性声明。

您可以尝试启用此系统变量,但这可能会影响其他应用程序。我认为它仅在您实际创建表时才生效,因此它不应影响任何现有表。

如果您不进行这样的系统级更改,您可以在此表的published_at 列中添加显式DEFAULT 属性,然后它不会自动添加ON UPDATE

【讨论】:

  • 准确!我刚刚对其进行了测试并解决了所有问题。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2013-09-09
  • 2021-01-22
  • 1970-01-01
  • 2019-10-11
  • 2017-06-22
  • 2018-12-01
  • 1970-01-01
  • 2011-10-29
相关资源
最近更新 更多