У меня есть дерево, закодированное в базе данных MySQL как ребра:
CREATE TABLE items (
num INT,
tot INT,
PRIMARY KEY (num)
);
CREATE TABLE tree (
orig INT,
term INT
FOREIGN KEY (orig,term) REFERENCES items (num,num)
)
Для каждого листа в дереве кто-то устанавливает items.tot
. Для внутренних узлов items.tot
должно быть суммой дочерних узлов. Многократное выполнение следующего запроса приведет к желаемому результату.
UPDATE items SET tot = (
SELECT SUM(b.tot) FROM
tree JOIN items AS b
ON tree.term = b.num
WHERE tree.orig=items.num)
WHERE EXISTS
(SELECT * FROM tree WHERE orig=items.num)
(обратите внимание, что это на самом деле не работает, но это не относится к делу)
Предположим, что база данных существует и инвариант уже выполнен.
Вопрос в том:
Каков наиболее практичный способ обновления БД при сохранении этого требования? Обновления могут перемещать узлы или изменять значение
tot
на листовых узлах. Можно предположить, что листовые узлы останутся листовыми узлами, внутренние узлы останутся внутренними узлами, и все останется как правильное дерево.
Некоторые мысли, которые у меня были:
- Полная инвалидация, после любого обновления пересчитывать все (Эм... Нет)
- Set a trigger on the items table to update the parent of any row that is updated
- This would be recursive (updates trigger updates, trigger updates, ...)
- Не работает, MySQL не может обновить таблицу, которая запустила триггер
- Set a trigger to schedule an update of the parent of any row that is updated
- This would be iterative (get an item from the schedule, processing it schedules more items)
- Что запускает это? Доверять клиентскому коду, чтобы сделать это правильно?
- Преимущество состоит в том, что при правильном заказе обновлений требуется меньшее количество средств. Но этот порядок сам по себе является осложнением.
Идеальное решение было бы обобщено на другие «инварианты агрегации».
FWIW Я знаю, что это «немного за борт», но я делаю это для удовольствия (Веселье: глагол, Поиск невозможного, делая это. :-)