我有一个小时间跟踪网络应用程序(在Rails 3.2.8和MySQL中实现)。该应用程序有几个用户在给定日期将时间添加到特定任务。系统设置为每个日期每个任务只能有一次输入(即行)。即如果在同一任务和日期上添加两次时间,它会为现有行添加时间,而不是创建一个新行。 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组合将发生冲突。
如果我为每个task_id = 2条目执行插入操作,我想我可以使用唯一约束来执行ON DUPLICATE KEY UPDATE ...
。但这看起来非常不优雅。
我还试图找到一种方法来首先使用总计时间更新任务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,因为它还会找到目标中只存在的所有条目任务,不需要合并。在上面的示例数据中,将找到第二行,重新插入,触发on-duplicate-key,并将时间设置为与现有相同。因此,如果目标任务有10行,而源任务有0行,那么它仍会执行10次(完全无意义的)INSERT。
这可以通过将内部SELECT包装在另一个SELECT中来避免,并使用COUNT(*)
仅查找需要合并的那些行。当然,这将需要另外的更多查询来更新不需要合并的那些行的task_id(据我所知,这需要一个连接来解决)。
答案 0 :(得分:0)
user_id
和date
上的总结将是:
select sum(time), user_id, 1, date
from timetable
group by user_id, date;
更新时间表(荣誉为@Flambino):
insert into timetable (time, user_id, task_id, date)
select sum(time), user_id, 1, date
from timetable
group by user_id, date
on duplicate key update time = values(time);
最后删除task_id
而不是1:
delete from timetable where task_id > 1;
当更新仅限于任务1和2时,请应用@ Flambino更新中的where子句。