SQL 聚合 OVER 和 PARTITION
Posted
技术标签:
【中文标题】SQL 聚合 OVER 和 PARTITION【英文标题】:SQL Aggregates OVER and PARTITION 【发布时间】:2014-08-29 16:23:13 【问题描述】:全部,
这是我在 *** 上的第一篇文章,所以放轻松...
我使用的是 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 语句一起使用,但如果可能的话,我正在寻找一种更简洁、更有效的方式来编写查询。
谢谢!
【问题讨论】:
我认为 OrgAverage 需要“OVER (Partition by Month(StartDate))”,UserAverage 需要“OVER (Partition By Month(StartDate),UserId)”。然后摆脱 Group By。如果这不起作用,您可能必须使用子查询或派生表来获取 OrgAverage。 这是个好主意。我实际上认为这会起作用,但不幸的是,结果集一遍又一遍地显示相同的 OrgAverage 和 UserAverage,以及同一个月(一月)一遍又一遍。 【参考方案1】:您在这里将两个查询连接在一起:
每个用户每月的平均值 每月所有组织的平均值如果您一次只为一个用户返回数据,那么内联选择可能会给您带来乐趣:
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(通用表表达式)
【讨论】:
【参考方案2】:Average 函数中缺少分区子句
OVER ( Partition by MONTH(StartDate))
【讨论】:
【参考方案3】: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;
【讨论】:
【参考方案4】:我能够使用自联接完成它,可能有更好的方法。
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
【讨论】:
【参考方案5】:您可以在下面尝试使用更少的代码。
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]
【讨论】:
这个炸弹告诉我'order'附近的语法不正确。分区中的“排序依据”是否在 2008 年有效?我知道窗口功能在 2012 年和 2014 年得到了一些升级。 您可以尝试删除订单...没有问题以上是关于SQL 聚合 OVER 和 PARTITION的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server:使用具有相同 OVER 子句的多个聚合/分析函数?