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は、テーブルの列ではありません。わかりやすくするために追加しましたが、A、B を C および D と比較することにより、CTE によって自動的に推測されます。

レベル 1 の場合、計算は次のようになります。

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

レベル2以降の計算式は

Calc1 = (以前のレベルの Calc2) の合計 / 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 に答える