SQL:按分区聚合

时间:2020-04-11 18:05:33

标签: sql sql-server tsql group-by window-functions

查询:对于每种商品类别和每年,仅考虑意大利航线

  • 选择每个月的平均每日收入

  • 自年初以来的每月总收入

SQL:

SELECT
  gc.GoodCategory,
  tm.Month,
  tm.Year,
  SUM(ro.Income) / COUNT(DISTINCT tm.Date),
  SUM(ro.Income) OVER (PARTITION BY gc.GoodCategory, tm.Year 
    ORDER BY tm.Month ROWS UNBOUNDED PRECEDING)

FROM FactRoutes ro,
     DimLocation dp,
     DimLocation ds,
     DimGoodCategory gc,
     DimTime tm

WHERE ro.DepartureID = dp.LocationID
    AND ro.DestinationID = ds.LocationID
    AND ro.GoodCategoryID = gc.GoodCategoryID
    AND ro.GoodTimeID = tm.GoodTimeID
    AND dp.State = 'Italy'
    AND ds.State = 'Italy'

GROUP BY gc.GoodCategory,
     tm.Month,
     tm.Year;

但遇到以下错误

Column 'FactRoutes.Income' is invalid in the select list
because it is not contained in either an aggregate function
or the GROUP BY clause.

有什么更好的处理方法?

1 个答案:

答案 0 :(得分:0)

我认为您想要

SELECT
  gc.GoodCategory,
  tm.Month,
  tm.Year,
  SUM(ro.Income) / COUNT(DISTINCT tm.Date),
  SUM(SUM(ro.Income)) OVER (PARTITION BY gc.GoodCategory, tm.Year ORDER BY tm.Month)
FROM FactRoutes ro
INNER JOIN DimLocation dp ON ro.DepartureID = dp.LocationID
INNER JOIN DimLocation ds ON ro.DestinationID = ds.LocationID
INNER JOIN DimGoodCategory gc ON ro.GoodCategoryID = gc.GoodCategoryID
INNER JOIN DimTime tm ON ro.GoodTimeID = tm.GoodTimeID
WHERE dp.State = 'Italy' AND ds.State = 'Italy'
GROUP BY gc.GoodCategory, tm.Month, tm.Year;

主要要点是,为了使查询不是有效的聚合查询,您需要在window函数内使用聚合函数,例如SUM(SUM(ro.Income)) OVER (...)而不是SUM(ro.Income) OVER(...),因此您会获得以前的 groups 记录的总和。

其他值得注意的地方:

  • 始终使用显式联接(使用ON关键字)而不是老式的隐式联接(在FROM子句中使用逗号),其语法已经数十年

  • 失宠了 不需要
  • ROWS UNBOUNDED PRECEDING;您的窗口函数有一个ORDER BY子句,所以无论如何它都是这样做的