CTE или нет для подсчета идентификатора дерева, указанного в дополнительной таблице - PullRequest
2 голосов
/ 28 января 2020

У меня есть простая древовидная таблица, в которой я ссылаюсь на типы, подтипы (без ограничения уровня), бренды и модели для простого инвентарного приложения.

Структура данных такая, как показано ниже: (nodeIsModel - это логическое поле, используемое для расчетов)

ID    parentID    label               nodeIsModel
 1     -1          Root                   0  
 2     1           IT                     0
 3     2           Desktops               0
 4     3           Hewlett-Packard        0 
 5     4           HP Z240                1
 6     4           H97M-PLUS              1
 7     2           Laptops                0
 8     7           DELL                   0
 9     8           G3 3579                1

и т. д.

Эта таблица (отображается в DBTreeView под Delphi) дает мне что-то вроде:

ID     Label
1      Root
2        |_IT
3        |__Desktops
4        |___Hewlett-Packard
5        |____HP Z240
6        |____H97M-PLUS
7        |__Laptops
8        |___DELL
9        |____G3 3579

Эта таблица является справочной таблицей, в которой пользователь будет выбирать и назначать оборудованию, набору типов, подтипов, марок и моделей.

Оборудование сохраняется в другой таблице (data_items) и связывается к предыдущей таблице по идентификатору выбранной модели (самый низкий уровень древовидной структуры).

Например, мой настольный компьютер будет сохранен как:

itemID    itemLabel         typeID
  1       RSI-HP-DESK-01      5

, потому что это HP Рабочая станция Z240, и на нее ссылаются как на ID 5 в таблице дерева.

Начиная с этого typeID, у меня есть запрос CTE, который поднимается по дереву, чтобы найти всех родителей по дочернему ID, это не проблема.

Мой Вопрос в следующем:

Я хотел бы, чтобы при отображении DBTreeView был столбец с отображением:

  • количество элементов для всех моделей

но также

  • сумма моделей для каждой марки (с учетом моделей)
  • сумма моделей для каждого подтипа
  • сумма моделей для каждого типа ...

и так далее ...

Например, если бы мы имели 2 рабочих станции HP Z240 и 1 ноутбук DELL G3 в базе данных TreeView будут выглядеть следующим образом:

ID     Label                    NB
1      Root
2        |_IT                   3
3        |__Desktops            2
4        |___Hewlett-Packard    2
5        |____HP Z240           1
6        |____H97M-PLUS         1
7        |__Laptops             1
8        |___DELL               1
9        |____G3 3579           1

На основании логического поля "nodeIsModel" в таблице дерева я пробовал запросы, некоторые с CTE, другие без , но я запутался в JOIN и подзапросах, а также получил сообщение об ошибке:

агрегированные запросы не разрешены в CTE

Любой совет будет очень признателен начиная с дочернего идентификатора:

Этот запрос работает. Я ищу новый запрос, который бы соединял древовидную таблицу с таблицей предметов, давая счет моделей, назначенных предметам на каждом уровне дерева

WITH CTE AS (
SELECT
    ID,
    parentID,
    label,
    CAST (nodeLevel AS INTEGER) AS LEVEL
FROM
    dico_TBM
WHERE
    ID = :lookupID
UNION ALL
    SELECT
        r.ID,
        t.parentID,
        t.label,
        LEVEL - 1
    FROM
        dico_TBM t
    INNER JOIN CTE r ON t.ID = r.parentID
) SELECT DISTINCT
    r.ID,
    r.parentID,
    r.label,
    LEVEL
FROM
    CTE r
WHERE
    LEVEL > 0
ORDER BY
    LEVEL

(nodeLevel - целое число, дающее уровень узла в дереве, который я пропустил, чтобы упомянуть в своем вопросе, думая, что он не представляет интереса, и: lookupID - это идентификатор начального дочернего узла, который я передаю в качестве параметра в свой запрос)

Ответы [ 2 ]

0 голосов
/ 28 января 2020

Вот один подход, который может помочь вам решить проблему. Ниже приведены мои аналогичные настройки enter image description here

И следующий запрос дает нам количество ресурсов на каждом уровне в дереве ресурсов.

;with CTE1 AS (
  SELECT r.id, r.label, r.parentID, count(*) AS ItemCount 
    FROM resourcetree r 
    JOIN items i ON (r.id = i.resourceID) 
   GROUP BY r.id, r.label, r.parentID
), 
CTE2 AS (
  SELECT r.id, r.label, r.parentID, SUM(cte1.itemCount) AS ItemCount, 0 AS sumFlag 
    FROM resourceTree r 
    JOIN CTE1 ON (r.id = cte1.parentID) 
   GROUP BY r.id, r.label, r.parentID
  UNION ALL
  SELECT r.id, r.label, r.parentID, cte2.ItemCount AS ItemCount, 1 AS sumFlag 
    FROM resourceTree r 
    JOIN cte2 ON (r.id = cte2.parentID)
)
SELECT r.id, 
       r.label, 
       COALESCE(c2_1.ItemCount, c2_0.ItemCount, cte1.ItemCount, 0) AS ItemCount 
  FROM resourceTree r 
  LEFT JOIN cte1 ON r.id = cte1.id 
  LEFT JOIN cte2 c2_0 ON (r.id = c2_0.id AND c2_0.sumFlag = 0)
  LEFT JOIN (SELECT id, label, SUM(ItemCount) AS ItemCount 
               FROM CTE2 
              WHERE sumFlag = 1 
              GROUP BY id, label) c2_1 ON r.id = c2_1.id

Ниже приведено результат я получил. Надеюсь, поможет. Спасибо.

enter image description here

PS: мне не нужно было использовать флаг 'NodeIsModel'

0 голосов
/ 28 января 2020

Используйте nodeIsModel = 1 в качестве якорного члена recursive cte и начинайте отсюда и go до уровня

with
rcte as
(
    select  *
    from    dico_TBM
    where   nodeIsModel = 1

    union all

    select  d.*
    from    rcte r
            inner join dico_TBM d   on  r.parnetID  = d.ID
)
select  ID, label, count(*) as NB
from    rcte
group by ID, label
order by ID
...