Oracle Running Total

时间:2012-07-09 18:20:18

标签: sql oracle aggregate-functions

使用PLSQL寻找2种不同类型小计的建议。

我需要提取一个数据集,其中包括1)一个独特的人数,以及2)总学分数,作为随时间变化的总计。

原始数据:
这是交易数据 - 每次学生注册或课程时,都会插入包含日期,学生ID和学分(以及课程编号和一堆其他相关数据)的记录。每个学生每门课程一个记录。

STUDENT_ID   CREDITS   DATE
1            3         01-JAN-12
1            2         02-JAN-12
57           1         03-JAN-12
1            1         03-JAN-12

处理数据:
这是老板需要看到的 - 它将用于以后的趋势(例如,看看今年的01年1月如何衡量去年1月1日等)。

UniqueHeadcount   SumCredits   Date
1                 3            01-JAN-12
1                 5            02-JAN-12
2                 7            03-JAN-12

对此的粗暴方法是编写一堆单独的SELECTS(每天一个),并将它们组合在一起。例如:

SELECT
  COUNT(DISTINCT STUDENT_ID) as "UniqueHeadcount",
  SUM(CREDIT_HR) as "SumCredits",
  '01-JAN-12' as "DATE"
FROM
  REGISTRATIONS
WHERE
  TO_CHAR(DATE,'yyyymmdd') <= '20120101' 
GROUP BY
  '01-JAN-12'

UNION

SELECT
  COUNT(DISTINCT STUDENT_ID) as "UniqueHeadcount",
  SUM(CREDIT_HR) as "SumCredits",
  '02-JAN-12' as "DATE"
FROM
  REGISTRATIONS
WHERE
  TO_CHAR(DATE,'yyyymmdd') <= '20120102' 
GROUP BY
  '02-JAN-12'

UNION

...

这是有效的 - 结果是准确的 - 但正如你所看到的 - 这远远不够优雅 - 如果你必须做365天,那么......它是一个野兽。必须有更好的方法来做到这一点。

到目前为止,在我的搜索中,我已经了解了我可以使用的'OVER'条款 - 就像这样:

SELECT
  COUNT(DISTINCT STUDENT_ID) OVER(ORDER BY TRUNC(RSTS_DATE) ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) "UniqueHeadcount",
  SUM(CREDIT_HR) OVER(ORDER BY TRUNC(RSTS_DATE) ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as "SumCredits",
  TRUNC(RSTS_DATE) as "DATE"
FROM
  REGISTRATIONS

这个查询方式更简短(yay) - 但有两个重要的问题我无法找到解决方法。首先,它与COUNT DISTINCT不起作用(通过设计,显然?)。所以我暂时评论了一下,但后来遇到了第二个问题:它忽略了TRUNC()函数。 RSTS_DATE,虽然看起来只是一个日/月/年值,当你在它上面运行SELECT时,实际上也保留了时间,所以我得到的结果集不是简单地在日期上求和,而是在时间上 - 因此,我的处理数据每天返回数百条记录(每个单独的课程注册一个记录),而不是每天一条记录。例如:

UniqueHeadcount   SumCredits   Date
1                 3            01-JAN-12
1                 5            02-JAN-12
2                 6            03-JAN-12 (hidden time: 07:32:27)
2                 7            03-JAN-12 (hidden time: 08:01:33)

不是我追求的目标。

所以我正在寻找专业知识 - 如果我到目前为止所解释的是有意义的 - 是否有另一种使用OVER子句的方法,或者可能还有PLSQL的另一个特性我应该用于此?如果你不知道,我在PLSQL中并不强大,但是如果有人能给我一些方向 - 即使只是谷歌的话,我也会感谢你的帮助。

由于

1 个答案:

答案 0 :(得分:1)

试试这个:

WITH CRdata AS
(
    SELECT COUNT(DISTINCT STUDENT_ID) AS UniqueHeadcount,
    SUM(CREDIT_HR)                     AS SumCredits,
    TRUNC(RSTS_DATE) RSTS_DATE
     FROM REGISTRATIONS
    GROUP BY TRUNC(RSTS_DATE)
)
 SELECT SUM(UniqueHeadcount) OVER(ORDER BY RSTS_DATE ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS UniqueHeadcount,
  SUM(SumCredits) OVER(ORDER BY RSTS_DATE ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS  SumCredits, 
  RSTS_DATE 
  FROM CRdata