在使用公共表表达式的递归处理内执行聚合处理

更新页 :
页面创建日期 :

样本数据

使用具有以下分层数据的表和具有聚合数据的表:

金额层次结构表

ID (int, PK) Name (nvarchar(50)) Money (bigint) ParentID (int)
1 A 10000 NULL
2 B 5000 1
3 C 3000 2
11 K 20000 NULL
12 L 1000 11

点表

点 ID (int, PK) 金额 ID (int) 点 (bigint)
1 1 100
2 1 50
3 2 40
4 3 10
5 3 60
6 3 80
7 11 20
8 12 50
9 12 40

如何使用公共表表达式

我们不会在这里详细讨论它,但简单地说,公共表表达式允许您提前定义选择表达式,并使用在以后的表引用中定义 select 表达式,而无需创建多个相同的描述。 图像可能更接近视图。

用法如下:

-- 共通テーブル式で事前に select 内容を定義する
with [cte] as
(
  select *
  from [金額階層テーブル]
  where [Money] >= 5000
)
select * from [cte]
union all
select * from [cte]
;

结果

分层数据的表示

我认为这种模式可能有效地使用公共表表达式。 前面介绍的数据的 select 表达式可以替换为视图和表变量等,因此没有多大好处。

通过在公共表表达式中调用更多公共表表达式(如以下 SQL),可以实现分层表示形式:

使用时需要注意的事项包括“将源选择与分层数据连接的选择与联合所有合并”和“合并字符串时统一大小”。

-- 共通テーブル式で階層データをつなげる
with [cte] as
(
  select
    [ID]
   ,[Name]
   ,[ParentID]
   ,[Money] as [金額合計]
   ,1 as [レベル]
   ,cast([Name] as nvarchar(4000)) as [階層]
  from [金額階層テーブル]
  where [ParentID] is null

  union all

  select
    [子].[ID]
   ,[子].[Name]
   ,[子].[ParentID]
   ,[親].[金額合計] + [子].[Money] as [金額合計]
   ,[親].[レベル] + 1 as [レベル]
   ,[親].[階層] + N'⇒' + [子].[Name] as [階層]
  from [金額階層テーブル] [子]
  inner join [cte] [親]
    on [子].[ParentID] = [親].[ID]
)
select *
from [cte]
order by [ID]
;

结果

公共表表达式的分层处理中的聚合(错误)

有时,您希望在公共表表达式的层次结构过程中计算聚合值。 在这里,我们试图计算与金额 ID 关联的积分总数。

-- 共通テーブル式の階層処理内で集計を使用する (エラー)
with [cte] as
(
  select
    [ID]
   ,[Name]
   ,[ParentID]
   ,[Money] as [金額合計]
   ,(
      select sum([ポイント])
      from [ポイントテーブル]
      where [金額ID] = [ID]
    ) as [ポイント合計]
   ,1 as [レベル]
   ,cast([Name] as nvarchar(4000)) as [階層]
  from [金額階層テーブル]
  where [ParentID] is null

  union all

  select
    [子].[ID]
   ,[子].[Name]
   ,[子].[ParentID]
   ,[親].[金額合計] + [子].[Money] as [金額合計]
   ,[親].[ポイント合計] + (
                            select sum([ポイント])
                            from [ポイントテーブル]
                            where [金額ID] = [子].[ID]
                          ) as [ポイント合計]
   ,[親].[レベル] + 1 as [レベル]
   ,[親].[階層] + N'⇒' + [子].[Name] as [階層]
  from [金額階層テーブル] [子]
  inner join [cte] [親]
    on [子].[ParentID] = [親].[ID]
)
select *
from [cte]
order by [ID]
;

但是,当您运行它时,您会收到类似于以下内容的错误:

GROUP BY、HAVING、または集計関数は、再帰共通テーブル式 'cte' の再帰部分では許可されません。

递归公共表表达式似乎不能处理与分组相关的操作。

公共表表达式层次结构中的聚合(正常行为)

虽然无法在递归公共表表达式中编写聚合处理,但可以通过将聚合过程的部分定义为更通用的表表达式来执行此操作。

若要描述多个公共表表达式,请使用逗号分隔公共表表达式。

-- 共通テーブル式の階層処理内で集計を使用する (正常)
with [ポイント合計CTE] as
(
  select
    [金額ID]
   ,sum([ポイント]) as [ポイント合計]
  from [ポイントテーブル]
  group by [金額ID]
)
,[cte] as
(
  select
    [ID]
   ,[Name]
   ,[ParentID]
   ,[Money] as [金額合計]
   ,(
      select [ポイント合計]
      from [ポイント合計CTE]
      where [金額ID] = [ID]
    ) as [ポイント合計]
   ,1 as [レベル]
   ,cast([Name] as nvarchar(4000)) as [階層]
  from [金額階層テーブル]
  where [ParentID] is null

  union all

  select
    [子].[ID]
   ,[子].[Name]
   ,[子].[ParentID]
   ,[親].[金額合計] + [子].[Money] as [金額合計]
   ,[親].[ポイント合計] + (
                            select [ポイント合計]
                            from [ポイント合計CTE]
                            where [金額ID] = [子].[ID]
                          ) as [ポイント合計]
   ,[親].[レベル] + 1 as [レベル]
   ,[親].[階層] + N'⇒' + [子].[Name] as [階層]
  from [金額階層テーブル] [子]
  inner join [cte] [親]
    on [子].[ParentID] = [親].[ID]
)
select *
from [cte]
order by [ID]
;

结果