MySQL:更新查询的奇怪行为(错误 1062 重复条目)

MySQL: Strange behavior of UPDATE query (ERROR 1062 Duplicate entry)

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

由于这 3 个参数的某些组合可能没有文章,简单的 GROUP BY 是行不通的。因此,我首先生成一个 table 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 |
| ...          | ...        |      ... |           ... |
+--------------+------------+----------+---------------+

为了测试,我现在创建了一个临时 table tmp 作为原始新闻文章 table:

的 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 |
| ...          | ...        |      ... | ... |
+--------------+------------+----------+-----+

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

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;

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

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 是 table 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;

我在这里错过了什么?

更新 1:我实际上检查了数据库中 news_article_counts 的 table 定义。确实有以下内容:

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;

似乎没有什么适合我。

您似乎禁用了 explicit_defaults_for_timestamp 系统变量。其影响之一是:

The first TIMESTAMP column in a table, if not explicitly declared with the NULL attribute or an explicit DEFAULT or ON UPDATE attribute, is automatically declared with the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP attributes.

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

如果您不想像这样进行 system-level 更改,您可以将显式 DEFAULT 属性添加到此 table 的 published_at 列,然后它不会自动添加 ON UPDATE.