SQL Server - 如何将带有组小计的列添加到查询结果中

Posted

技术标签:

【中文标题】SQL Server - 如何将带有组小计的列添加到查询结果中【英文标题】:SQL Server - How to add column with group subtotals to the query results 【发布时间】:2018-09-05 14:06:54 【问题描述】:

我有一个数据库表,其中包含放置在树层次结构中的项目。项目有其 ID 和 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

如果将整个表(所有层次结构)的 TOTAL 汇总放在单独的行中,那就太好了。

【问题讨论】:

您使用的是什么类型的服务器? (Oracle/SQL Server/等)什么版本? (SQL Server 2008 / SQL Server 2014 / 等) Microsoft SQL Server 2017 【参考方案1】:

你现有的结果数据让我觉得你可能已经在使用某种形式的递归 CTE 来构建像 LevelName 这样的东西。如果是这样,这可能可以适应同时计算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 类型而不是父/子类型直接 对层次结构进行建模。这取决于该数据必须满足的其他用例。


这里的问题是,大多数分层查询最终都倾向于自上而下地探索层次结构,但您想要的数据只能轻松地自下而上获得。我确实试图弄清楚是否有一个聪明的 GROUP BYORDER BY 表达式(后者用于窗口函数)也可以使用 IsDescendantOf 但失败了。

【讨论】:

是的,我已经在使用 cte 来选择层次结构,没有订购工作,它看起来像这样: 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 你能把它调整到展位吗按层级对项目进行排序并计算组汇总? @B.Sverediuk - 所以在我的hierarchy CTE 中使用我对hier 列的定义,并将其添加到cte 中的列集中。添加第二个 CTE 以将其转换为正确的类型(上面的Typed),然后在最终选择中执行cross apply。正如我在添加评论时提到的那样,问题是您想要自下而上的数据,但正在自上而下探索层次结构 - 同时进行第一个层次结构构建时,没有简单的方法来获得总和.

以上是关于SQL Server - 如何将带有组小计的列添加到查询结果中的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 如何对分组进行小计

如何按小计创建 SQL 组?

如何将滚动 7 天和 30 天的列添加到我每天在 SQL Server 中的不同登录次数中

将具有默认值的列添加到 SQL Server 中的现有表

VBA Excel小计动态范围不起作用

sql添加小计和总计