0

TableX带有列和值

A   B   C   D   E   F   G   H   Level
---------------------------------------------------------------------
10  ABC 10  ABC XYZ 2   3   4   1
10  ABC 10  ABC XYZ 2   3   4   1
11  DEF 10  ABC XYZ 4   5   6   2
11  DEF 10  ABC XYZ 6   7   8   2
12  GHI 11  DEF XYZ 7   8   9   3
12  GHI 11  DEF XYZ 8   9   10  3
15  JKL 15  JKL ABC 9   10  11  1
15  JKL 15  JKL ABC 10  11  12  1
16  MNO 15  JKL ABC 13  14  15  2
16  MNO 15  JKL ABC 16  16  18  2

这里Level不是表格中的一列,我只是为了清楚起见而添加,但 CTE 会通过将 A、B 与 C 和 D 进行比较来自动推断

对于 1 级,计算将是

Calc1 = (F + G - H)  
Calc2 = Calc1 + G + H  

2级及以后的计算公式为

Calc1 = (Calc2 Of Previous Level) 的总和 / 100
Calc2 = Calc1 + G + H - 无论级别如何,此计算都没有变化

The calculation is cyclic- 2 级的计算结果将需要输入到 3 级计算等等..

WITH Tiers (
     Level,
     A,
     B,
     C,
     D,
     E,
     Calc1,
     Calc2)
AS
SELECT 1 AS Level,
       A,
       B,
       C,
       D,
       E,
       F + G - H AS Calc1,
       (F + G - H) + G + H AS Calc2
 FROM TableX
WHERE A = C
  AND B = D
UNION ALL
SELECT tier.Level + 1 AS Level,
       A,
       B,
       C,
       D,
       E,
       /* How can I do this SUM (tier.Calc1) / 100 */
       /* How can I do this SUM (tier.Calc1) / 100 + G + H */
 FROM TableX tab
 INNER JOIN Tiers tier
    ON tab.C = tier.A
   AND tab.D = tier.B
   AND tab.E = tier.E
WHERE (A <> C
   OR B <> D)
)
SELECT *
  FROM Tiers

我试过了

SELECT tier.Level + 1 AS Level,
       A,
       B,
       C,
       D,
       E,
       sumCalc.calc1 / 100 Calc1
       sumCalc.calc1 / 100 + G + H Calc2
 FROM TableX tab
 INNER JOIN Tiers tier
    ON tab.C = tier.A
   AND tab.E = tier.B
 INNER JOIN (
      SELECT A, B, E, SUM(Calc1) Calc1
        FROM Tiers
      GROUP BY A, B, E) sumCalc /* SQL Server throws error that CTE table cannot be used here */
WHERE (A <> C
   OR B <> D)

我也希望使用表值的 OUTER APPLY 或其他东西..

4

1 回答 1

0

编辑:在摆弄 CTE 之后,包括多个 CTE 一起滚动,它看起来并不乐观。

以下代码使用 CTE 分配级别并处理级别 1 计算并将结果保存在临时表中。然后一个循环按顺序处理每个附加级别。对于 SUM 的分组,我仍然有点迷糊(总的来说),但这应该很容易调整。

 declare @TableX as Table ( A Int, B VarChar(3), C Int, D VarChar(3), E VarChar(3), F Int, G Int, H Int )

 insert into @TableX ( A, B, C, D, E, F, G, H ) values
   ( 10, 'ABC', 10, 'ABC', 'XYZ', 2,  3,  4 ),
   ( 10, 'ABC', 10, 'ABC', 'XYZ', 2,  3,  4 ),
   ( 11, 'DEF', 10, 'ABC', 'XYZ', 4,  5,  6 ),
   ( 11, 'DEF', 10, 'ABC', 'XYZ', 6,  7,  8 ),
   ( 12, 'GHI', 11, 'DEF', 'XYZ', 7,  8,  9 ),
   ( 12, 'GHI', 11, 'DEF', 'XYZ', 8,  9,  10 ),
   ( 15, 'JKL', 15, 'JKL', 'ABC', 9,  10, 11 ),
   ( 15, 'JKL', 15, 'JKL', 'ABC', 10, 11, 12 ),
   ( 16, 'MNO', 15, 'JKL', 'ABC', 13, 14, 15 ),
   ( 16, 'MNO', 15, 'JKL', 'ABC', 16, 16, 18 )

-- Create a temporary table with levels assigned and the level 1 calculations performed.
; with Tiers ( Level, A, B, C, D, E, F, G, H, Calc1, Calc2 )
  as (
    -- Level 1.
    select 1, A, B, C, D, E, F, G, H, Cast( F + G - H as Float ), Cast( ( F + G - H ) + G + H as Float )
      from @TableX
      where A = C and B = D
    union all
    -- Level > 1.
    select T.Level + 1, TX.A, TX.B, TX.C, TX.D, TX.E, TX.F, TX.G, TX.H, NULL, NULL
      from @TableX as TX inner join
        Tiers as T on T.A = TX.C and T.B = TX.D and T.E = TX.E
      where TX.A <> TX.C or TX.B <> TX.D
    )
  select *
    into #Tiers
    from Tiers

-- Perform the additional calculations one level at a time.
declare @MinLevel as Int
select @MinLevel = Min( Level )
  from #Tiers
  where Calc1 is NULL

while @MinLevel is not NULL
  begin
  -- Note: The   SELECTs   for the sums may need extended   WHERE   clauses to implement the desired grouping.
  update #Tiers
    set Calc1 = ( select Sum( Calc2 ) from #Tiers where Level = @MinLevel - 1 ) / 100,
      Calc2 = ( select Sum( Calc2 ) from #Tiers where Level = @MinLevel - 1 ) / 100 + G + H
    where Level = @MinLevel
  select @MinLevel = Min( Level )
    from #Tiers
    where Calc1 is NULL
  end

-- Display the results.
select *
  from #Tiers
  order by Level

-- Houseclean.    
drop table #Tiers

为了完整起见,第一次尝试保留在下面:

也许解决方案是在构建 CTE 之后进行所有Calc1/计算:Calc2

 declare @TableX as Table ( A Int, B VarChar(3), C Int, D VarChar(3), E VarChar(3), F Int, G Int, H Int )

 insert into @TableX ( A, B, C, D, E, F, G, H ) values
   ( 10, 'ABC', 10, 'ABC', 'XYZ', 2,  3,  4 ),
   ( 10, 'ABC', 10, 'ABC', 'XYZ', 2,  3,  4 ),
   ( 11, 'DEF', 10, 'ABC', 'XYZ', 4,  5,  6 ),
   ( 11, 'DEF', 10, 'ABC', 'XYZ', 6,  7,  8 ),
   ( 12, 'GHI', 11, 'DEF', 'XYZ', 7,  8,  9 ),
   ( 12, 'GHI', 11, 'DEF', 'XYZ', 8,  9,  10 ),
   ( 15, 'JKL', 15, 'JKL', 'ABC', 9,  10, 11 ),
   ( 15, 'JKL', 15, 'JKL', 'ABC', 10, 11, 12 ),
   ( 16, 'MNO', 15, 'JKL', 'ABC', 13, 14, 15 ),
   ( 16, 'MNO', 15, 'JKL', 'ABC', 16, 16, 18 )

; with Tiers ( Level, A, B, C, D, E, F, G, H )
  as (
    -- Level 1.
    select 1, A, B, C, D, E, F, G, H
      from @TableX
      where A = C and B = D
    union all
    -- Level > 1.
    select T.Level + 1, TX.A, TX.B, TX.C, TX.D, TX.E, TX.F, TX.G, TX.H
      from @TableX as TX inner join
        Tiers as T on T.A = TX.C and T.B = TX.D and T.E = TX.E
      where TX.A <> TX.C or TX.B <> TX.D
    )
  select *,
    case Level
      when 1 then T.F + T.G - T.H
      else ( select Sum( F + G - H ) / 100. from Tiers where Level = T.Level - 1 ) end as Calc1,
    case Level
      when 1 then ( T.F + T.G - T.H ) + T.G + T.H
      else ( select Sum( F + G - H ) / 100. + T.G + T.H from Tiers where Level = T.Level - 1 ) end as Calc2
    from Tiers as T
    order by Level

请注意,我添加了一个小数点,以便生成的计算返回实际值。

于 2012-05-10T15:49:54.020 回答