我有一个小的时间跟踪网络应用程序(在 Rails 3.2.8 和 MySQL 中实现)。该应用程序有几个用户在给定日期将时间添加到特定任务中。系统设置为每个日期每个任务用户只能有 1 个时间条目(即行)。即,如果您在同一任务和日期上添加两次时间,它将向现有行添加时间,而不是创建新行。user_id/task_id/date
唯一性由索引强制执行UNIQUE
。
现在我正在寻找合并 2 个任务。用最简单的术语来说,将任务 ID 2 合并到任务 ID 1 将采用此
time | user_id | task_id | date
------+----------+----------+-----------
10 | 1 | 1 | 2012-10-29
15 | 2 | 1 | 2012-10-29
10 | 1 | 2 | 2012-10-29
5 | 3 | 2 | 2012-10-29
并将其更改为
time | user_id | task_id | date
------+----------+----------+-----------
20 | 1 | 1 | 2012-10-29 <-- time values merged (summed)
15 | 2 | 1 | 2012-10-29 <-- no change
5 | 3 | 1 | 2012-10-29 <-- task_id changed (no merging necessary)
即通过对时间值求和来合并,其中给定的 user_id/date/task 组合会发生冲突。
ON DUPLICATE KEY UPDATE ...
我想如果我为每个 task_id=2 条目进行插入,我可以使用唯一约束来执行。但这似乎很不雅。
我还试图找到一种方法,首先使用汇总时间更新任务 1 中的所有行,但我无法完全弄清楚这一点。
有任何想法吗?
更新:离开奥拉夫的回答,我想出了这个,这似乎正在工作
INSERT INTO `timetable`
(`time`, `user_id`, `task_id`, `date`)
(
SELECT
SUM(`time`) AS `time`,
`user_id`,
1 AS `task_id`,
`date`
FROM `timetable` AS `t1`
WHERE `task_id` IN (1,2)
GROUP BY `user_id`, `date`
)
ON DUPLICATE KEY UPDATE `time`=VALUES(`time`);
DELETE FROM `timetable` WHERE `task_id`=2;
如果有人有更好的解决方案(或者我的解决方案中有任何我应该知道的问题),我会留下这个问题
更新2:不知道为什么我之前没有意识到这一点,但是我的解决方案可能会做很多多余的INSERT,因为它还会找到所有只存在于目标任务中并且不需要合并的条目。在上面的示例数据中,将找到第二行,重新插入,触发重复键,并将时间设置为与现在相同。因此,如果目标任务有 10 行,源任务有 0 行,它仍然会执行 10 次(完全没有意义的)INSERT。
这可以通过将内部 SELECT 的所有内容包装在另一个 SELECT 中来避免,并用于COUNT(*)
仅查找需要合并的那些行。当然,这将需要另一个更多的查询来更新那些不需要合并的行的 task_id (据我所知,这需要一个连接来弄清楚)。