У меня есть база данных MySQL, где хранятся новостные статьи с датой публикации (только дневная информация), источником и категорией. Исходя из этого, я хочу сгенерировать таблицу, содержащую счетчик статей по этим 3 параметрам.
Поскольку для некоторых комбинаций этих трех параметров не может быть никакой статьи, простая GROUP BY не будет делать. Поэтому я сначала news_article_counts
таблицу 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;
Но теперь мне нужно обновить article_count
таблицы news_article_counts
со значениями в таблице tmp
где 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
совлокальный индекс по published_at
, source
, category
столовых news_article_counts
. Но это не должно быть проблемой, поскольку я не могу - насколько я могу судить, обновить любое из этих 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
в базе данных. И действительно, есть следующее:
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
установлен 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
. Одним из последствий этого является:
Первый столбец
TIMESTAMP
в таблице, если явно не объявлен с атрибутомNULL
или явным атрибутомDEFAULT
илиON UPDATE
, автоматически объявляется с атрибутамиDEFAULT CURRENT_TIMESTAMP
иON UPDATE CURRENT_TIMESTAMP
.
Вы можете попробовать включить эту системную переменную, но это может повлиять на другие приложения. Я думаю, что это вступает в силу только тогда, когда вы создаете таблицу, поэтому она не должна влиять на существующие таблицы.
Если вы этого не сделаете, чтобы сделать изменения на уровне системы, как это, вы могли бы добавить явное DEFAULT
атрибут в published_at
столбце этой таблицы, то он не будет автоматически добавлять ON UPDATE
.