0

TableX列和值SQL Server的CTE,怎樣才能再次使用CTE表GROUP BY

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 = SUM(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或其他東西..

+0

嘗試使用層而不是層 – HLGEM

+0

謝謝,這是一個錯字,更新 – Humble

+0

如果我理解你的問題,你不需要'SUM()'。您只需在CTE的後半部分添加它們即可累積這些值。 'Level'不是'SUM()',它是一系列增加的總和。 – HABO

回答

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 

首先嚐試下面保留完整:

也許解決辦法是做所有的Calc1/Calc2計算的建設CTE後:

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 

注意我添加了一個小數點,以便結果計算返回實際值。

+0

謝謝@ user92546花時間。但是計算有一個問題,它們是循環的。如果看到,計算1是SUM(上一級的計算2),然後計算2再次指的是我們剛剛計算的計算1。在你的答案中,你正在做兩個單獨的SUM,在這種情況下,下一級的計算值將無法訪問上一級的更新的Calc1和Calc2,因爲我們正在計算並且沒有將該值放回表中,因此下一級將參照他們。希望我能夠解釋這種情況。 – Humble

+0

我更新了原來的問題,並提到了關於循環性質。 – Humble

+0

而我錯過了GROUP BY中的SUM查詢,在你的SELECT CASE中我們也需要得到所有匹配的A,B和E記錄,並且做了GROUP BY A,B,E爲SUM – Humble