In order to fix a bug, I have to iterate over all the rows in a table, updating a cached count of children to what its real value should be. The structure of the things in the table form a tree.
In rails, the following does what I want:
Thing.all.each do |th|
Thing.connection.update(
"
UPDATE #{Thing.quoted_table_name}
SET children_count = #{th.children.count}
WHERE id = #{th.id}
"
)
end
Is there any way of doing this in a single MySQL query?
Alternatively, is there any way of doing this in multiple queries, but in pure MySQL?
I want something like
UPDATE table_name
SET children_count = (
SELECT COUNT(*)
FROM table_name AS tbl
WHERE tbl.parent_id = table_name.id
)
except the above doesn’t work (I understand why it doesn’t).
You probably got this error, right?
The easiest way around this is probably to select the child counts into a temporary table, then join to that table for the updates.
This should work, assuming the depth of the parent/child relationship is always 1. Based on your original update this seems like a safe assumption.
I added an explicit write lock on the table to assure that no rows are modified after I create the temp table. You should only do this if you can afford to have it locked for the duration of this update, which will depend on the amount of data.