SQL Server - Как добавить столбец с промежуточными итогами группы к результатам запроса - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть таблица базы данных с элементами, которые размещены в древовидной иерархии. Предметы имеют свои идентификаторы и ParentID. Каждому элементу назначена сумма, поэтому при извлечении данных из моей иерархии и ее сумм это выглядит так:

| ID | Name            | ParentID | Level | Amount |
| 1  | ITEM 1          |     NULL |     0 |    100 |
| 3  |  - Item 1-1     |        1 |     1 |    100 |
| 7  |  - - Item 1-1-1 |        3 |     2 |    100 |
| 8  |  - - Item 1-1-2 |        3 |     2 |    100 |
| 4  |  - Item 1-2     |        1 |     1 |    100 |
| 9  |  - - Item 1-2-1 |        4 |     2 |    100 |
| 10 |  - - Item 1-2-2 |        4 |     2 |    100 |
| 2  | ITEM 2          |     NULL |     0 |    200 |
| 5  |  - Item 2-1     |        2 |     1 |    200 |
| 11 |  - - Item 2-1-1 |        5 |     2 |    200 |
| 12 |  - - Item 2-1-2 |        5 |     2 |    200 |
| 6  |  - Item 2-2     |        2 |     1 |    200 |
| 13 |  - - Item 2-2-1 |        6 |     2 |    200 |
| 14 |  - - Item 2-2-2 |        6 |     2 |    200 |

Предположим, это новая таблица. Мне нужно выбрать из него данные, а также рассчитать промежуточные итоги группы по сумме для каждого уровня иерархии, например:

| ID | Name            | ParentID | Level | Amount | Group rollup |
| 1  | ITEM 1          |     NULL |     0 |    100 |          700 |
| 3  |  - Item 1-1     |        1 |     1 |    100 |          300 |
| 7  |  - - Item 1-1-1 |        3 |     2 |    100 |          100 |
| 8  |  - - Item 1-1-2 |        3 |     2 |    100 |          100 |
| 4  |  - Item 1-2     |        1 |     1 |    100 |          300 |
| 9  |  - - Item 1-2-1 |        4 |     2 |    100 |          100 |
| 10 |  - - Item 1-2-2 |        4 |     2 |    100 |          100 |
| 2  | ITEM 2          |     NULL |     0 |    200 |         1400 |
| 5  |  - Item 2-1     |        2 |     1 |    200 |          600 |
| 11 |  - - Item 2-1-1 |        5 |     2 |    200 |          200 |
| 12 |  - - Item 2-1-2 |        5 |     2 |    200 |          200 |
| 6  |  - Item 2-2     |        2 |     1 |    200 |          600 |
| 13 |  - - Item 2-2-1 |        6 |     2 |    200 |          200 |
| 14 |  - - Item 2-2-2 |        6 |     2 |    200 |          200 |

Пожалуйста, помогите мне достичь этой цели.

Прямо сейчас я использую этот запрос для выбора данных. Тем не менее, он не упорядочивает элементы правильно и не делает свертку. Можете ли вы настроить его так, чтобы они упорядочивались, как показано выше, и рассчитывали групповой свод?

WITH cte AS
  (SELECT ID,
          Name,
          ParentID,
          0 AS LEVEL,
          Amount
   FROM MyTable
   WHERE ParentID IS NULL
   UNION ALL
   SELECT t.ID,
          t.Name,
          t.ParentID,
          LEVEL+1,
          t.Amount
   FROM cte
   JOIN MyTable t ON cte.ID = t.ParentID)
SELECT d1.*
FROM cte d1

Было бы неплохо иметь ОБЩИЙ сводный пакет для всей таблицы (всех иерархий) в отдельной строке.

1 Ответ

0 голосов
/ 05 сентября 2018

Ваши существующие данные результатов заставляют меня думать, что вы, возможно, уже используете какую-то рекурсивную CTE для создания таких вещей, как Level и Name. Если это так, то, вероятно, его можно адаптировать для одновременного вычисления hier.

Но если нет, мы используем рекурсивный CTE для построения наших hier столбцов, а затем используем IsDescendantOf при вычислении сумм:

declare @t table(ID int, Name  varchar(30), ParentID int, Level int, Amount int)
insert into @t(ID ,Name , ParentID , Level , Amount) values
(1  ,'ITEM 1         ',NULL, 0 ,100 ),
(3  ,' - Item 1-1    ',   1, 1 ,100 ),
(7  ,' - - Item 1-1-1',   3, 2 ,100 ),
(8  ,' - - Item 1-1-2',   3, 2 ,100 ),
(4  ,' - Item 1-2    ',   1, 1 ,100 ),
(9  ,' - - Item 1-2-1',   4, 2 ,100 ),
(10 ,' - - Item 1-2-2',   4, 2 ,100 ),
(2  ,'ITEM 2         ',NULL, 0 ,200 ),
(5  ,' - Item 2-1    ',   2, 1 ,200 ),
(11 ,' - - Item 2-1-1',   5, 2 ,200 ),
(12 ,' - - Item 2-1-2',   5, 2 ,200 ),
(6  ,' - Item 2-2    ',   2, 1 ,200 ),
(13 ,' - - Item 2-2-1',   6, 2 ,200 ),
(14 ,' - - Item 2-2-2',   6, 2 ,200 )

;With hierarchy as (
    select ID, Name, '/' + CONVERT(varchar(max),ID) + '/' as hier,Amount
    from @t
    where ParentID is null
    union all
    select t.ID,t.Name, hier + CONVERT(varchar(max),t.ID) + '/',t.Amount
    from
        hierarchy h
            inner join
        @t t
            on
                t.ParentID = h.ID
), Typed as (
    select ID,Name,Amount,CONVERT(hierarchyid,hier) as hier
    from hierarchy
)
select
    *
from
    Typed t1
        cross apply
    (select SUM(Amount) as GroupTotal from Typed t2
     where t2.hier.IsDescendantOf(t1.hier) = 1) u
order by hier

Результаты:

ID          Name                           Amount      hier          GroupTotal
----------- ------------------------------ ----------- ------------- -----------
1           ITEM 1                         100         0x58          700
3            - Item 1-1                    100         0x5BC0        300
7            - - Item 1-1-1                100         0x5BE7        100
8            - - Item 1-1-2                100         0x5BE880      100
4            - Item 1-2                    100         0x5C20        300
9            - - Item 1-2-1                100         0x5C34C0      100
10           - - Item 1-2-2                100         0x5C3540      100
2           ITEM 2                         200         0x68          1400
5            - Item 2-1                    200         0x6C60        600
11           - - Item 2-1-1                200         0x6C75C0      200
12           - - Item 2-1-2                200         0x6C7640      200
6            - Item 2-2                    200         0x6CA0        600
13           - - Item 2-2-1                200         0x6CB6C0      200
14           - - Item 2-2-2                200         0x6CB740      200

На этом этапе вы также можете решить, что ваша модель данных должна быть изменена таким образом, чтобы иерархия напрямую моделировалась с использованием типа hierarchyid, а не Parent / Child. Это зависит от того, в каких других случаях эти данные должны удовлетворять.


Проблема здесь в том, что большинство иерархических запросов, как правило, в конечном итоге исследуют иерархию сверху вниз, но нужные данные легко получить снизу вверх. Я попытался выяснить, существует ли умное выражение GROUP BY или ORDER BY (последнее для использования в оконной функции), которое также может использовать IsDescendantOf, но не удалось.

...