簡體   English   中英

SQL聚合OVER和PARTITION

[英]SQL Aggregates OVER and PARTITION

所有,

這是我關於Stackoverflow的第一篇文章,所以輕松吧...

我正在使用SQL Server 2008。

我剛開始編寫SQL查詢,但遇到一個我認為很簡單的問題,但是我已經奮斗了2天。 我有一組看起來像這樣的數據:

UserId          Duration(Seconds)        Month
1               45                       January
1               90                       January
1               50                       February
1               42                       February
2               80                       January
2               110                      February
3               45                       January
3               62                       January
3               56                       January
3               60                       February

現在,我要編寫一個查詢,為我提供特定用戶的平均值,並將其與該月所有用戶的平均值進行比較。 因此,查詢用戶#1后的結果數據集將如下所示:

UserId         Duration(seconds)        OrganizationDuration(Seconds)        Month
1              67.5                     63                                   January
1              46                       65.5                                 February

我一直在圍繞不同的子查詢和按場景分組,似乎沒有任何工作。 最近,我一直在嘗試OVER和PARTITION BY,但也沒有成功。 我最新的查詢如下所示:

select Userid, 
       AVG(duration) OVER () as OrgAverage,
       AVG(duration) as UserAverage,
       DATENAME(mm,MONTH(StartDate)) as Month
            from table.name 
            where YEAR(StartDate)=2014
            AND userid=119 
                  GROUP BY MONTH(StartDate), UserId     

該查詢在選擇列表中用“持續時間”轟炸,因為它沒有包含在聚合函數或GROUP BY子句中,因此無效。

請記住,我正在處理大量數據。 我認為我可以使其與CASE語句一起使用,但是我正在尋找一種更簡潔,更有效的方式來編寫查詢(如果可能)。

謝謝!

平均函數中缺少分區子句

OVER ( Partition by MONTH(StartDate)) 

您在這里將兩個查詢結合在一起:

  • 每個用戶每月的平均值
  • 所有組織平均每月

如果您一次僅要返回一個用戶的數據,那么內聯選擇可能會給您帶來歡樂:

SELECT AVG(a.duration) AS UserAvergage,
   (SELECT AVG(b.Duration) FROM tbl b WHERE MONTH(b.StartDate) = MONTH(a.StartDate)) AS OrgAverage 
    ...
    FROM tbl a
    WHERE userid = 119 
    GROUP BY MONTH(StartDate), UserId

注意-在MONTH上使用比較可能會比較慢-使用CTE(通用表表達式)可能會更好

我能夠通過自我連接完成它,這可能是一種更好的方法。

Select UserId, AVG(t1.Duration) as Duration, t2.duration as OrgDur, t1.Month 
from #temp t1
inner join (Select Distinct MONTH, AVG(Duration) over (partition by Month) as duration
from #temp) t2 on t2.Month = t1.Month
group by t1.Month, t1.UserId, t2.Duration 
order by t1.UserId, Month desc

這里使用的CTE可能是更好的解決方案,而且絕對更易於閱讀

With MonthlyAverage
as 
(
Select MONTH, AVG(Duration) as OrgDur 
from #temp
group by Month
)

Select UserId, AVG(t1.Duration) as Duration, m.duration as OrgDur , t1.Month 
from #temp t1
inner join MonthlyAverage m on m.Month = t1.Month
group by UserId, t1.Month, m.duration
Please try this. It works fine to me.

WITH C1
AS
(
SELECT 
AVG(Duration) AS TotalAvg, 
[Month]
FROM [dbo].[Test]
GROUP BY [Month]
),
C2
AS
(
SELECT Distinct UserID,
AVG(Duration) OVER(PARTITION BY UserID, [Month] ORDER BY UserID) AS DetailedAvg, 
[Month]
FROM [dbo].[Test]
)
SELECT C2.*, C1.TotalAvg
FROM C2 c2 
INNER JOIN C1 c1 ON c1.[Month] = c2.[Month]
ORDER BY c2.UserID, c2.[Month] desc;

您可以在下面用更少的代碼嘗試。

SELECT Distinct UserID,
AVG(Duration)  OVER(PARTITION BY [Month]) AS TotalAvg,
AVG(Duration) OVER(PARTITION BY UserID, [Month] ORDER BY UserID) AS DetailedAvg, 
[Month]
FROM [dbo].[Test]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM