2012-09-06 3 views
2

Дерево неограниченной глубины. пример:postgresql подсчитывает количество детей

+----+-------+--------------------+ 
| id | name | parent_id | value | 
+----+-------+--------------------+ 
| 1 | test1 |   | 0 | 
| 2 | test2 |  1  | 0 | 
| 3 | test3 |  2  | 5 | 
| 4 | test4 |  1  | 0 | 
| 5 | test5 |  4  | 5 | 
| 6 | test6 |  4  | 0 | 
| 7 | test7 |  6  | 10 | 
+----+-------+--------------------+ 

Я хочу получить общую стоимость своих детей. :

+----+-------+--------------------+ 
| id | name | parent_id | value | 
+----+-------+--------------------+ 
| 1 | test1 |   | 20 | = test2.value + test4.value 
| 2 | test2 |  1  | 5 | = test3.value 
| 3 | test3 |  2  | 5 | 
| 4 | test4 |  1  | 15 | = test5.value + test6.value 
| 5 | test5 |  4  | 5 | 
| 6 | test6 |  4  | 10 | = test7.value 
| 7 | test7 |  6  | 10 | 
+----+-------+--------------------+ 

любое предложение? Благодаря!

+0

Не зная остаток ваших потребностей, я ничего не могу окончательно о том, что правильный шаблон будет, но ваша реализация довольно наивный способ хранения деревьев в базе данных говорят. Были изобретены некоторые шаблоны дизайна, которые значительно облегчают работу со всеми умными вещами, включая вопрос, который вы задаете. Например, проверьте структуру материализованного шаблона пути. См. Http://www.rampant-books.com/book_0601_sql_coding_styles.htm или другие ссылки. –

+0

@ hims056: Что непонятно? Следуйте ссылкам 'parent_id' и рекурсивно суммируйте значения' count'. –

+0

@ hims056 первая таблица - это то, что у меня есть, а вторая - то, что я хочу получить, чтобы создать представление. – Danfi

ответ

11

Вот рекурсивный запрос, который мы надеемся решить вашу проблему:

WITH RECURSIVE tree (id, parent_id, cnt) AS (
    -- start from bottom-level entries 
    SELECT id, parent_id, 0::bigint AS cnt 
    FROM tbl t 
    WHERE NOT EXISTS (
     SELECT id 
     FROM tbl 
     WHERE parent_id = t.id 
    ) 

    UNION ALL 

    -- join the next level, add the number of children to that of already counted ones 
    SELECT t.id, t.parent_id, tree.cnt + (
      SELECT count(id) 
      FROM tbl 
      WHERE parent_id = t.id 
     ) 
    FROM tbl t JOIN tree ON t.id = tree.parent_id 
) 
SELECT tree.id, max(tree.cnt) AS number_of_children 
FROM tree 
-- use the JOIN if you need additional columns from tbl 
-- JOIN tbl ON tree.id = tbl.id 
-- use the WHERE clause if you want to see root nodes only 
-- WHERE parent_id IS NULL 
GROUP BY tree.id 
ORDER BY tree.id 
; 

Я сделал SQLFiddle тоже.

+0

Благодарим вас за ответ. Я допустил ошибку, я действительно хотел получить общую стоимость, но не счет. Сожалею. – Danfi

+0

Я использую функцию, чтобы решить ее наконец. – Danfi

+0

Боюсь, что ваша реализация неверна. Пожалуйста, рассмотрите дерево с корнем, у которого трое детей, у обоих сначала есть двое детей, а у последнего нет детей. По вашему запросу корень имеет 5 детей (потомков), в то время как на самом деле он имеет 7. – lared

Смежные вопросы