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_counts
的 article_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_counts
的 published_at
、source
、category
的联合索引。但这应该不是问题,因为据我所知,我没有更新这 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
.
我有一个 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:
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_counts
的 article_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_counts
的 published_at
、source
、category
的联合索引。但这应该不是问题,因为据我所知,我没有更新这 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 theNULL
attribute or an explicitDEFAULT
orON UPDATE
attribute, is automatically declared with theDEFAULT CURRENT_TIMESTAMP
andON UPDATE CURRENT_TIMESTAMP
attributes.
您可以尝试启用此系统变量,但这可能会影响其他应用程序。我认为它仅在您实际创建 table 时生效,因此它不应影响任何现有的 tables.
如果您不想像这样进行 system-level 更改,您可以将显式 DEFAULT
属性添加到此 table 的 published_at
列,然后它不会自动添加 ON UPDATE
.