Reputation: 57
I have three tables:
task: (t_id is a primary key, all_done is boolean)
+------+-------------+
| t_id | all_done |
+------+-------------+
| 1 | 0 |
| 2 | 0 |
+------+-------------+
subtask: (s_id is a primary key, done is boolean)
+------+------------+
| s_id | done |
+------+------------+
| 1 | 0 |
| 2 | 0 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 0 |
| 7 | 0 |
+------+------------+
task_subtask: (s_id and t_id are foreign keys. not every subtask belongs to a task)
+------+------+
| t_id | s_id |
+------+------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 4 |
| 2 | 5 |
+------+------+
The table task_subtask shows which subtask belongs to which task.
My intention is to make an sql-call to set all_done = 1 if all subtasks of that task are done. So in this example all_done should be set to 1 for t_id = 2
The following code seems to work, but i can't manage to fill this into an UPDATE call and i'm not really sure if i'm thinking into the right direction:
SELECT x.t_id, count(x.t_id), SUM(x.done) FROM (
SELECT subtask.s_id, subtask.done, task_subtask.t_id FROM subtask JOIN task_subtask WHERE subtask.s_id = task_subtask.s_id
) AS x GROUP BY x.t_id;
With that statement i'd get this output:
+------+---------------+-------------+
| t_id | count(x.t_id) | SUM(x.done) |
+------+---------------+-------------+
| 1 | 3 | 1 |
| 2 | 2 | 2 |
+------+---------------+-------------+
My best try might have been this:
UPDATE task, (SELECT x.t_id, count(x.t_id), SUM(x.done) FROM (
SELECT subtask.s_id, subtask.done, task_subtask.t_id FROM subtask JOIN task_subtask WHERE subtask.s_id = task_subtask.s_id
) AS x GROUP BY x.t_id)
SET task.all_done = 1 WHERE task.t_id = t_id AND count(x.t_id) = SUM(x.done);
The error message with this call is
ERROR 1248 (42000): Every derived table must have its own alias
but i'm not sure if the update call would even work this way.
Thanks in advance for any help!
Upvotes: 1
Views: 53
Reputation:
If you just merge task_subtask as the same table, adding T_ID field,
task_table:
+------+-------------+
| t_id | all_done |
+------+-------------+
| 1 | 0 |
| 2 | 0 |
+------+-------------+
subtask_table: (s_id,t_id is a primary key)
+------+------+------------+
| s_id | t_id | done |
+------+-------------------+
| 1 | 1 | 0 |
| 2 | 1 | 0 |
| 3 | 1 | 1 |
| 4 | 2 | 1 |
| 5 | 2 | 1 |
etc...
+------+------|------------+
Now you can try
UPDATE TASK SET all_done=1 WHERE
count
(Select done from subtask join task
on subtask.t_id=task.t_id WHERE done=0)=0
That means, for each Task, if don't have more subtask where done=0, then update Task set all_done=1
Another good way: Create a trigger AFTER update subTask, with the same logic above.
CREATE TRIGGER set_all_done
AFTER UPDATE
ON subtask FOR EACH ROW
BEGIN
IF count(Select done from subtask WHERE subtask.t_id = new.t_id)=0
then UPDATE TASK SET all_done=1 WHERE Task.t_id = new.t_id
END;
I look now and have a third solution, using just one table:
SELECT distinct t_id from subtask where done=0
This single line returns t_id not yet done, and you can use it as verification, or
UPDATE TASK SET all_done=1 WHERE t_id NOT in (SELECT distinct t_id from subtask where done=0)
Upvotes: 0
Reputation: 49260
You were complicating the query. I think this should work.
UPDATE task
JOIN (SELECT ts.t_id
FROM subtask s
JOIN task_subtask ts ON s.s_id = ts.s_id
GROUP BY ts.t_id
HAVING COUNT(s.s_id) = SUM(s.done)
) x
ON task.t_id = x.t_id
SET all_done = 1
Upvotes: 1