2012-03-08 118 views
26

我希望下面的示例代碼是不言自明:如何結合GROUP BY和ROW_NUMBER?

declare @t1 table (ID int,Price money, Name varchar(10)) 
declare @t2 table (ID int,Orders int, Name varchar(10)) 
declare @relation table (t1ID int,t2ID int) 
insert into @t1 values(1, 200, 'AAA'); 
insert into @t1 values(2, 150, 'BBB'); 
insert into @t1 values(3, 100, 'CCC'); 
insert into @t2 values(1,25,'aaa'); 
insert into @t2 values(2,35,'bbb'); 
insert into @relation values(1,1); 
insert into @relation values(2,1); 
insert into @relation values(3,2); 

select T2.ID AS T2ID 
,T2.Name as T2Name 
,T2.Orders 
,T1.ID AS T1ID 
,T1.Name As T1Name 
,T1Sum.Price 
FROM @t2 T2 
INNER JOIN (
    SELECT Rel.t2ID 
     ,MAX(Rel.t1ID)AS t1ID 
-- the MAX returns an arbitrary ID, what i need is: 
--  ,ROW_NUMBER()OVER(Partition By Rel.t2ID Order By Price DESC)As PriceList 
     ,SUM(Price)AS Price 
     FROM @t1 T1 
     INNER JOIN @relation Rel ON Rel.t1ID=T1.ID 
     GROUP BY Rel.t2ID 
)AS T1Sum ON T1Sum.t2ID = T2.ID 
INNER JOIN @t1 T1 ON T1Sum.t1ID=T1.ID 

結果:

T2ID T2Name Orders T1ID T1Name Price  
1  aaa  25  2  BBB 350,00  
2  bbb  35  3  CCC 100,00 

我需要的是上述評論的,一種方式來獲得的ROW_NUMBERGroup By擺在首位。所以我需要sum所有的T1價格在T2.ID分組在關係表和t1ID與最高的價格。

換句話說:如何更改MAX(Rel.t1ID)AS t1ID有點返回最高價格的ID?

所以期望的結果是(注意:第一T1ID從2改爲1,因爲它有更高的價格):

T2ID T2Name Orders T1ID T1Name Price  
1  aaa  25  1  AAA 350,00  
2  bbb  35  3  CCC 100,00 

注意:萬一你想知道我爲什麼不乘Orders與價格:他們不相關(所以我應該離開這個專欄,因爲它有點模糊,請忽略它,我剛剛添加它,使所有不那麼抽象)。其實Orders必須保持不變,這就是子查詢方法加入兩者的原因以及我需要首先進行分組的原因。

結論:顯然,我的問題的核心可以通過OVER clause回答是可以應用到任何之類的函數SUM(見Damien's answer)什麼新的我。謝謝大家的工作方法。

+1

不應該在最終結果而不是'BBB'而不是'BBB'? – 2012-03-08 12:41:01

回答

50

哇,其他的答案看起來複雜 - 所以我希望我沒有錯過一些東西明顯。

您可以對集合使用OVER/PARTITION BY,然後他們將執行分組/彙總,而不使用GROUP BY子句。所以我只是修改您的查詢爲:

select T2.ID AS T2ID 
,T2.Name as T2Name 
,T2.Orders 
,T1.ID AS T1ID 
,T1.Name As T1Name 
,T1Sum.Price 
FROM @t2 T2 
INNER JOIN (
    SELECT Rel.t2ID 
     ,Rel.t1ID 
--  ,MAX(Rel.t1ID)AS t1ID 
-- the MAX returns an arbitrary ID, what i need is: 
     ,ROW_NUMBER()OVER(Partition By Rel.t2ID Order By Price DESC)As PriceList 
     ,SUM(Price)OVER(PARTITION BY Rel.t2ID) AS Price 
     FROM @t1 T1 
     INNER JOIN @relation Rel ON Rel.t1ID=T1.ID 
--  GROUP BY Rel.t2ID 
)AS T1Sum ON T1Sum.t2ID = T2.ID 
INNER JOIN @t1 T1 ON T1Sum.t1ID=T1.ID 
where t1Sum.PriceList = 1 

哪給出了請求的結果集。

+1

哇,這是我所希望的,另一個回答我所害怕的。謝謝(全部),我必須仔細看看如何將它安裝到我的實際查詢中(我的示例是_very_減少)。 – 2012-03-08 13:14:50

+1

+1 definitly simpler – 2012-03-08 13:21:55

+0

謝謝!我一直在試圖弄清楚如何使這項工作適用於幾種不同的窗口功能。我一直把這個總和放在分區的子句中,而不是在開始處! – BilliD 2016-07-20 21:10:16

2

毫無疑問,這可以簡化,但結果符合您的期望。

的這個主旨是

  • 計算的最高價格在一個單獨的CTE每個t2ID
  • 計算在一個單獨的CTE每個t2ID
  • 總價合併兩組CTE的結果的

SQL Statement

;WITH MaxPrice AS ( 
    SELECT t2ID 
      , t1ID 
    FROM (  
       SELECT t2.ID AS t2ID 
         , t1.ID AS t1ID 
         , rn = ROW_NUMBER() OVER (PARTITION BY t2.ID ORDER BY t1.Price DESC) 
       FROM @t1 t1 
         INNER JOIN @relation r ON r.t1ID = t1.ID   
         INNER JOIN @t2 t2 ON t2.ID = r.t2ID 
      ) maxt1 
    WHERE maxt1.rn = 1        
) 
, SumPrice AS (
    SELECT t2ID = t2.ID 
      , Price = SUM(Price) 
    FROM @t1 t1 
      INNER JOIN @relation r ON r.t1ID = t1.ID 
      INNER JOIN @t2 t2 ON t2.ID = r.t2ID 
    GROUP BY 
      t2.ID   
)   
SELECT t2.ID 
     , t2.Name 
     , t2.Orders 
     , mp.t1ID 
     , t1.ID 
     , t1.Name 
     , sp.Price 
FROM @t2 t2 
     INNER JOIN MaxPrice mp ON mp.t2ID = t2.ID 
     INNER JOIN SumPrice sp ON sp.t2ID = t2.ID 
     INNER JOIN @t1 t1 ON t1.ID = mp.t1ID 
2

重複數據刪除(選擇最大值T1)和聚合需要做爲不同的步驟。我已經使用了CTE,因爲我覺得這使得它更清晰:

;WITH sumCTE 
AS 
(
    SELECT Rel.t2ID, SUM(Price) price 
    FROM @t1   AS T1 
    JOIN @relation AS Rel 
    ON  Rel.t1ID=T1.ID 
    GROUP 
    BY  Rel.t2ID 
) 
,maxCTE 
AS 
(
    SELECT Rel.t2ID, Rel.t1ID, 
      ROW_NUMBER()OVER(Partition By Rel.t2ID Order By Price DESC)As PriceList 
    FROM @t1   AS T1 
    JOIN @relation AS Rel 
    ON  Rel.t1ID=T1.ID 
) 
SELECT T2.ID AS T2ID 
,T2.Name as T2Name 
,T2.Orders 
,T1.ID AS T1ID 
,T1.Name As T1Name 
,sumT1.Price 
FROM @t2 AS T2 
JOIN sumCTE AS sumT1 
ON  sumT1.t2ID = t2.ID 
JOIN maxCTE AS maxT1 
ON  maxT1.t2ID = t2.ID 
JOIN @t1 AS T1 
ON  T1.ID = maxT1.t1ID 
WHERE maxT1.PriceList = 1 
2
;with C as 
(
    select Rel.t2ID, 
     Rel.t1ID, 
     t1.Price, 
     row_number() over(partition by Rel.t2ID order by t1.Price desc) as rn 
    from @t1 as T1 
    inner join @relation as Rel 
     on T1.ID = Rel.t1ID 
) 
select T2.ID as T2ID, 
     T2.Name as T2Name, 
     T2.Orders, 
     T1.ID as T1ID, 
     T1.Name as T1Name, 
     T1Sum.Price 
from @t2 as T2 
    inner join (
       select C1.t2ID, 
        sum(C1.Price) as Price, 
        C2.t1ID 
       from C as C1 
       inner join C as C2 
        on C1.t2ID = C2.t2ID and 
        C2.rn = 1 
       group by C1.t2ID, C2.t1ID 
      ) as T1Sum 
    on T2.ID = T1Sum.t2ID 
    inner join @t1 as T1 
    on T1.ID = T1Sum.t1ID